From edf5674b9d6a4812b1a36b32e0e1bfd5b0cb968e Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 15 十月 2025 09:19:42 +0800
Subject: [PATCH] 263 【主界面】头像系统(内政-幻境阁系统)-服务端(形象、头像、头像框、气泡、称号)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ChatBox.py                            |   33 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerChatBox.py                           |  224 +--
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py                              |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini                                               |   16 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                                    |  424 +------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                                |  572 ++++++---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py                         |   47 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py                                    |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                                     |    1 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameServerRefresh.py                       |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py                             |   12 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Face.py                               |   35 
 /dev/null                                                                                                             |  121 --
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py                            |    9 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                            |   50 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                                  |  299 ++---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                                |   11 
 PySysDB/PySysDBPY.h                                                                                                   |  124 -
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFace.py                              |  488 +++-----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/GMToolLogicProcess/Commands/GMT_Face.py |  104 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/HJG.py                                |  149 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                           |   20 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                       |   19 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHJG.py                               |  684 +++++++++++
 24 files changed, 1,867 insertions(+), 1,584 deletions(-)

diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 434c83a..3dfd5f3 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -343,75 +343,84 @@
 	BYTE		SkillExCnt;	//随机附加技能数,0为所有
 };
 
-//称号表 #tagDienstgrad
+//称号表
 
-struct	tagDienstgrad
+struct	Title
 {
-	DWORD		_ID;	//头衔id
-	WORD		Type;	//头衔类型
-    DWORD		ExpireTime;	//有效时间
-	list		LightType;	//点亮属性类型
-	list		LightAttribute;	//点亮属性值
-	list		Skills;		//被动技能
-	DWORD		InitFightPower;	//初始战力
+	DWORD		_TitleID;	//称号ID
+    DWORD		ExpireMinutes;	//时效分钟,0永久
+	BYTE		UnlockWay;	//解锁方式
+    DWORD		UnlockValue;	//解锁方式值
+	BYTE		UnlockNeedCnt;	//解锁所需个数
+	BYTE		UpNeedCnt;	//升级所需个数
+	BYTE		StarMax;	//最高星级
+	list		AttrIDList;	//属性ID列表
+	list		InitAttrValueList;	//初始属性值列表
+    list		AttrPerStarAddList;	//每星加成值列表
 };
 
-//称号升星表
+//形象表
 
-struct tagTitleStarUp
+struct	Model
 {
-	DWORD		_TitleID;	//称号NPCID
-	BYTE		_TitleStar;	//称号星级
-	list		StarUpNeedItemList;	//升下一星所需道具 [[物品ID,个数], ...]
-	list		StarAttrType;	//累计总属性类型
-	list		StarAttrValue;	//累计总属性值
+	DWORD		_ModelID;	//形象ID
+    DWORD		ExpireMinutes;	//时效分钟,0永久
+	BYTE		UnlockWay;	//解锁方式
+    DWORD		UnlockValue;	//解锁方式值
+	BYTE		UnlockNeedCnt;	//解锁所需个数
+	BYTE		UpNeedCnt;	//升级所需个数
+	BYTE		StarMax;	//最高星级
+	list		AttrIDList;	//属性ID列表
+	list		InitAttrValueList;	//初始属性值列表
+    list		AttrPerStarAddList;	//每星加成值列表
 };
 
 //头像表
 
-struct	tagPlayerFace
+struct	PlayerFace
 {
 	DWORD		_FaceID;	//头像ID
-	BYTE		UnlockDefault;	//是否默认激活
     DWORD		ExpireMinutes;	//时效分钟,0永久
-    DWORD		CustomPlayerID;	//定制玩家ID
-	list		LightAttrType;	//点亮属性类型
-	list		LightAttrValue;	//点亮属性值
-    DWORD		LightFightPower;	//点亮附加战力
-};
-
-//头像升星表
-
-struct tagPlayerFaceStar
-{
-	DWORD		_FaceID;	//头像ID
-	BYTE		_FaceStar;	//头像星级
-	list		StarUpNeedItemList;	//升该星所需物品 [[物品ID,个数], ...]
-	list		StarAttrType;	//累计总属性类型
-	list		StarAttrValue;	//累计总属性值
+	BYTE		UnlockWay;	//解锁方式
+    DWORD		UnlockValue;	//解锁方式值
+	BYTE		UnlockNeedCnt;	//解锁所需个数
+	BYTE		UpNeedCnt;	//升级所需个数
+	BYTE		StarMax;	//最高星级
+	list		AttrIDList;	//属性ID列表
+	list		InitAttrValueList;	//初始属性值列表
+    list		AttrPerStarAddList;	//每星加成值列表
 };
 
 //头像框表
 
-struct	tagPlayerFacePic
+struct	PlayerFacePic
 {
 	DWORD		_FacePicID;	//头像框ID
-	BYTE		UnlockDefault;	//是否默认激活
     DWORD		ExpireMinutes;	//时效分钟,0永久
-	list		LightAttrType;	//点亮属性类型
-	list		LightAttrValue;	//点亮属性值
-    DWORD		LightFightPower;	//点亮附加战力
+	BYTE		UnlockWay;	//解锁方式
+    DWORD		UnlockValue;	//解锁方式值
+	BYTE		UnlockNeedCnt;	//解锁所需个数
+	BYTE		UpNeedCnt;	//升级所需个数
+	BYTE		StarMax;	//最高星级
+	list		AttrIDList;	//属性ID列表
+	list		InitAttrValueList;	//初始属性值列表
+    list		AttrPerStarAddList;	//每星加成值列表
 };
 
-//头像框升星表
+//气泡表
 
-struct tagPlayerFacePicStar
+struct ChatBox
 {
-	DWORD		_FacePicID;	//头像框ID
-	BYTE		_FacePicStar;	//头像框星级
-	list		StarUpNeedItemList;	//升该星所需物品 [[物品ID,个数], ...]
-	list		StarAttrType;	//累计总属性类型
-	list		StarAttrValue;	//累计总属性值
+	BYTE		_BoxID;	//气泡框ID
+    DWORD		ExpireMinutes;	//时效分钟,0永久
+	BYTE		UnlockWay;	//解锁方式
+    DWORD		UnlockValue;	//解锁方式值
+	BYTE		UnlockNeedCnt;	//解锁所需个数
+	BYTE		UpNeedCnt;	//升级所需个数
+	BYTE		StarMax;	//最高星级
+	list		AttrIDList;	//属性ID列表
+	list		InitAttrValueList;	//初始属性值列表
+    list		AttrPerStarAddList;	//每星加成值列表
 };
 
 //技能搭配表
@@ -2244,31 +2253,6 @@
 {
 	DWORD		_FuncID;	//功能ID
 	dict		Award;	//属性类型
-};
-
-//聊天气泡表
-
-struct tagChatBubbleBox
-{
-	BYTE		_BoxID;	//气泡框ID
-	WORD		NeedLV;	//所需等级
-	BYTE		NeedVIPLVGift;	//所需购买VIP等级礼包
-	BYTE		UnlockDefault;	//是否默认激活
-    DWORD		ExpireMinutes;	//时效分钟,0永久
-	list		LightAttrType;	//点亮属性类型
-	list		LightAttrValue;	//点亮属性值
-    DWORD		LightFightPower;	//点亮附加战力
-};
-
-//聊天气泡升星表
-
-struct tagChatBubbleBoxStar
-{
-	BYTE		_BoxID;	//气泡框ID
-	BYTE		_BoxStar;	//气泡框星级
-	list		StarUpNeedItemList;	//升该星所需物品 [[物品ID,个数], ...]
-	list		StarAttrType;	//累计总属性类型
-	list		StarAttrValue;	//累计总属性值
 };
 
 //表情包表
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index a307f41..a0e502a 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -334,57 +334,17 @@
 PacketSubCMD_4=0x06
 PacketCallFunc_4=OnPetStarUp
 
-;称号
-[PlayerDienstgrad]
-ScriptName = Player\PlayerDienstgrad.py
+;幻境阁
+[PlayerHJG]
+ScriptName = Player\PlayerHJG.py
 Writer = hxp
 Releaser = hxp
 RegType = 0
 RegisterPackCount = 1
 
-PacketCMD_1=0xA5
-PacketSubCMD_1=0x36
-PacketCallFunc_1=OnTitleStarUp
-
-;头像
-[PlayerFace]
-ScriptName = Player\PlayerFace.py
-Writer = hxp
-Releaser = hxp
-RegType = 0
-RegisterPackCount = 4
-
 PacketCMD_1=0xB2
-PacketSubCMD_1=0x26
-PacketCallFunc_1=OnFaceChange
-
-PacketCMD_2=0xB2
-PacketSubCMD_2=0x27
-PacketCallFunc_2=OnFaceStarUP
-
-PacketCMD_3=0xB2
-PacketSubCMD_3=0x28
-PacketCallFunc_3=OnFacePicChange
-
-PacketCMD_4=0xB2
-PacketSubCMD_4=0x29
-PacketCallFunc_4=OnFacePicStarUP
-
-;聊天框
-[PlayerChatBox]
-ScriptName = Player\PlayerChatBox.py
-Writer = hxp
-Releaser = hxp
-RegType = 0
-RegisterPackCount = 2
-
-PacketCMD_1=0xA2
-PacketSubCMD_1=0x30
-PacketCallFunc_1=OnSetChatBubbleBox
-
-PacketCMD_2=0xA2
-PacketSubCMD_2=0x36
-PacketCallFunc_2=OnChatBubbleBoxStarUP
+PacketSubCMD_1=0x25
+PacketCallFunc_1=OnHJGOP
 
 ;事件
 [EventShell]
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
index f630018..3683a76 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
@@ -570,22 +570,6 @@
 PacketSubCMD_1=0xFE
 PacketCallFunc_1=RecNetPack
 
-;玩家称号
-[PlayerDienstgrad]
-ScriptName = Player\PlayerDienstgrad
-Writer = xmnathan
-Releaser = xmnathan
-RegType = 0
-RegisterPackCount = 2
-
-PacketCMD_1=0x3
-PacketSubCMD_1=0x35
-PacketCallFunc_1=OnCPlayerDienstgradRefresh
-
-PacketCMD_2=0x3
-PacketSubCMD_2=0x37
-PacketCallFunc_2=OnCPlayerChangeDienstgrad
-
 ;任务
 [QuestLogic]
 ScriptName = Event\QuestLogic.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index a51cd79..4ddee20 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -215,7 +215,8 @@
 Def_CalcAttr_HeroBook, # 武将图鉴 2
 Def_CalcAttr_Realm, # 官职 3
 Def_CalcAttr_Gubao, # 古宝 4
-) = range(5)
+Def_CalcAttr_HJG, # 幻境阁 5
+) = range(6)
 
 CalcAttrName = {
                 Def_CalcAttr_LV:"主公等级",
@@ -223,6 +224,7 @@
                 Def_CalcAttr_HeroBook:"武将图鉴",
                 Def_CalcAttr_Realm:"官职",
                 Def_CalcAttr_Gubao:"古宝",
+                Def_CalcAttr_HJG:"幻境阁",
                 }
 
 ##-----------------------------------------------------------------------------------------------
@@ -3584,6 +3586,16 @@
 Def_PDict_WishingWellItem = "WishingWellItem_%s_%s"  # 物品ID,是否极品、是否绑定信息 参数(类型,物品数据)
 Def_PDict_WishingWellItemCnt = "WishingWellItemCnt_%s_%s"  # 物品数量记录 参数(类型,物品数据)
 
+# 称号
+Def_PDict_TitleState = "TitleState_%s"  # 称号状态,参数(key编号)
+Def_PDict_TitleEndTime = "TitleEndTime_%s"  # 称号到期时间戳,0为永久,参数(称号ID)
+Def_PDict_TitleStar = "TitleStar_%s"  # 称号星级,参数(称号ID)
+
+# 形象
+Def_PDict_ModelState = "ModelState_%s"  # 形象状态,参数(key编号)
+Def_PDict_ModelEndTime = "ModelEndTime_%s"  # 形象到期时间戳,0为永久,参数(形象ID)
+Def_PDict_ModelStar = "ModelStar_%s"  # 形象星级,参数(形象ID)
+
 #头像
 Def_PDict_FaceState = "FaceState_%s"  # 头像状态,参数(key编号)
 Def_PDict_FaceEndTime = "FaceEndTime_%s"  # 头像到期时间戳,0为永久,参数(头像ID)
@@ -3593,7 +3605,7 @@
 Def_PDict_FacePicStar = "FacePicStar_%s"  # 头像框星级,参数(头像框ID)
 
 #聊天气泡
-Def_PDict_ChatBubbleBoxState = "ChatBubbleBoxState_%s"  # 聊天气泡状态, 参数(key编号)
+Def_PDict_ChatBoxState = "ChatBoxState_%s"  # 聊天气泡状态, 参数(key编号)
 Def_PDict_ChatBoxEndTime = "ChatBoxEndTime_%s"  # 到期时间戳,0为永久,参数(气泡ID)
 Def_PDict_ChatBoxStar = "ChatBoxStar_%s"  # 星级,参数(气泡ID)
 Def_PDict_EmojiPackState = "EmojiPackState_%s"  # 表情包状态,参数(key编号)
@@ -3771,9 +3783,6 @@
 #骑宠觉醒
 Def_PDict_HorsePetSkinData = "HorsePetSkinData%d_%s"  #觉醒等级*100+外观索引  参数(类型,关联ID) 1-坐骑 2-灵宠
 Def_PDict_HorsePetSkinExp = "HorsePetSkinExp%d_%s"  #经验  参数(类型,关联ID) 1-坐骑 2-灵宠
-
-# 称号
-Def_PDict_TitleStar = "TitleStar_%s"  # 称号星级,参数(称号ID)
 
 # 符印
 Def_PDict_Rune_HoleOpenState = "Rune_HoleOpenState"  # 符印解锁状态
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 4c239d2..4b5679d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -1031,58 +1031,6 @@
 
 
 #------------------------------------------------------
-# A2 36 聊天气泡框升星 #tagCMChatBubbleBoxStarUP
-
-class  tagCMChatBubbleBoxStarUP(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("BoxID", c_ubyte),    #气泡ID
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xA2
-        self.SubCmd = 0x36
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xA2
-        self.SubCmd = 0x36
-        self.BoxID = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMChatBubbleBoxStarUP)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// A2 36 聊天气泡框升星 //tagCMChatBubbleBoxStarUP:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                BoxID:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.BoxID
-                                )
-        return DumpString
-
-
-m_NAtagCMChatBubbleBoxStarUP=tagCMChatBubbleBoxStarUP()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChatBubbleBoxStarUP.Cmd,m_NAtagCMChatBubbleBoxStarUP.SubCmd))] = m_NAtagCMChatBubbleBoxStarUP
-
-
-#------------------------------------------------------
 # A2 24 触碰NPC #tagCMTouchNPC
 
 class  tagCMTouchNPC(Structure):
@@ -1962,58 +1910,6 @@
 
 m_NAtagCMSelectRealmDifficulty=tagCMSelectRealmDifficulty()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSelectRealmDifficulty.Cmd,m_NAtagCMSelectRealmDifficulty.SubCmd))] = m_NAtagCMSelectRealmDifficulty
-
-
-#------------------------------------------------------
-# A2 30 设置聊天气泡框 #tagCMSetChatBubbleBox
-
-class  tagCMSetChatBubbleBox(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("BubbleBoxType", c_ubyte),    #气泡框类型
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xA2
-        self.SubCmd = 0x30
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xA2
-        self.SubCmd = 0x30
-        self.BubbleBoxType = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMSetChatBubbleBox)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// A2 30 设置聊天气泡框 //tagCMSetChatBubbleBox:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                BubbleBoxType:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.BubbleBoxType
-                                )
-        return DumpString
-
-
-m_NAtagCMSetChatBubbleBox=tagCMSetChatBubbleBox()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSetChatBubbleBox.Cmd,m_NAtagCMSetChatBubbleBox.SubCmd))] = m_NAtagCMSetChatBubbleBox
 
 
 #------------------------------------------------------
@@ -8237,58 +8133,6 @@
 
 
 #------------------------------------------------------
-# A5 36 称号升星 #tagCMTitleStarUp
-
-class  tagCMTitleStarUp(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("TitleID", c_int),    #称号ID
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xA5
-        self.SubCmd = 0x36
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xA5
-        self.SubCmd = 0x36
-        self.TitleID = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMTitleStarUp)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// A5 36 称号升星 //tagCMTitleStarUp:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                TitleID:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.TitleID
-                                )
-        return DumpString
-
-
-m_NAtagCMTitleStarUp=tagCMTitleStarUp()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMTitleStarUp.Cmd,m_NAtagCMTitleStarUp.SubCmd))] = m_NAtagCMTitleStarUp
-
-
-#------------------------------------------------------
 # A5 73 解锁命格孔 #tagCMUnLockBirthChartHole
 
 class  tagCMUnLockBirthChartHole(Structure):
@@ -13062,214 +12906,6 @@
 
 
 #------------------------------------------------------
-# B2 26 头像幻化 #tagCMFaceChange
-
-class  tagCMFaceChange(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("FaceID", c_int),    # 幻化的ID
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xB2
-        self.SubCmd = 0x26
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xB2
-        self.SubCmd = 0x26
-        self.FaceID = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMFaceChange)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// B2 26 头像幻化 //tagCMFaceChange:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                FaceID:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.FaceID
-                                )
-        return DumpString
-
-
-m_NAtagCMFaceChange=tagCMFaceChange()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFaceChange.Cmd,m_NAtagCMFaceChange.SubCmd))] = m_NAtagCMFaceChange
-
-
-#------------------------------------------------------
-# B2 28 头像框幻化 #tagCMFacePicChange
-
-class  tagCMFacePicChange(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("FacePicID", c_int),    # 幻化的ID
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xB2
-        self.SubCmd = 0x28
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xB2
-        self.SubCmd = 0x28
-        self.FacePicID = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMFacePicChange)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// B2 28 头像框幻化 //tagCMFacePicChange:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                FacePicID:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.FacePicID
-                                )
-        return DumpString
-
-
-m_NAtagCMFacePicChange=tagCMFacePicChange()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFacePicChange.Cmd,m_NAtagCMFacePicChange.SubCmd))] = m_NAtagCMFacePicChange
-
-
-#------------------------------------------------------
-# B2 29 头像框升星 #tagCMFacePicStarUP
-
-class  tagCMFacePicStarUP(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("FacePicID", c_int),    
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xB2
-        self.SubCmd = 0x29
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xB2
-        self.SubCmd = 0x29
-        self.FacePicID = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMFacePicStarUP)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// B2 29 头像框升星 //tagCMFacePicStarUP:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                FacePicID:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.FacePicID
-                                )
-        return DumpString
-
-
-m_NAtagCMFacePicStarUP=tagCMFacePicStarUP()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFacePicStarUP.Cmd,m_NAtagCMFacePicStarUP.SubCmd))] = m_NAtagCMFacePicStarUP
-
-
-#------------------------------------------------------
-# B2 27 头像升星 #tagCMFaceStarUP
-
-class  tagCMFaceStarUP(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("Cmd", c_ubyte),
-                  ("SubCmd", c_ubyte),
-                  ("FaceID", c_int),    
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        self.Cmd = 0xB2
-        self.SubCmd = 0x27
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.Cmd = 0xB2
-        self.SubCmd = 0x27
-        self.FaceID = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagCMFaceStarUP)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// B2 27 头像升星 //tagCMFaceStarUP:
-                                Cmd:%s,
-                                SubCmd:%s,
-                                FaceID:%d
-                                '''\
-                                %(
-                                self.Cmd,
-                                self.SubCmd,
-                                self.FaceID
-                                )
-        return DumpString
-
-
-m_NAtagCMFaceStarUP=tagCMFaceStarUP()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFaceStarUP.Cmd,m_NAtagCMFaceStarUP.SubCmd))] = m_NAtagCMFaceStarUP
-
-
-#------------------------------------------------------
 # B2 12 领取功能系统特权奖励 #tagCMGetFuncSysPrivilegeAward
 
 class  tagCMGetFuncSysPrivilegeAward(Structure):
@@ -14118,6 +13754,66 @@
 
 
 #------------------------------------------------------
+# B2 25 幻境阁操作 #tagCSHJGOP
+
+class  tagCSHJGOP(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Type", c_ubyte),    # 类型 1-形象;2-头像;3-头像框;4-气泡;5-称号	
+                  ("OPType", c_ubyte),    # 操作 1-激活;2-佩戴;3-卸下;4-升星
+                  ("OPID", c_int),    # 操作对应的ID,如形象ID等
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xB2
+        self.SubCmd = 0x25
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xB2
+        self.SubCmd = 0x25
+        self.Type = 0
+        self.OPType = 0
+        self.OPID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCSHJGOP)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B2 25 幻境阁操作 //tagCSHJGOP:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Type:%d,
+                                OPType:%d,
+                                OPID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Type,
+                                self.OPType,
+                                self.OPID
+                                )
+        return DumpString
+
+
+m_NAtagCSHJGOP=tagCSHJGOP()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSHJGOP.Cmd,m_NAtagCSHJGOP.SubCmd))] = m_NAtagCSHJGOP
+
+
+#------------------------------------------------------
 # B2 07 重置加点 #tagCMResetAttrPoint
 
 class  tagCMResetAttrPoint(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index a17f6a5..bae733d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -9466,114 +9466,6 @@
 
 
 #------------------------------------------------------
-# A3 CE 称号星级信息 #tagMCTitleStarInfo
-
-class  tagMCTitleStar(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("TitleID", c_int),    # 称号ID
-                  ("Star", c_ubyte),    # 星级
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.TitleID = 0
-        self.Star = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagMCTitleStar)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// A3 CE 称号星级信息 //tagMCTitleStarInfo:
-                                TitleID:%d,
-                                Star:%d
-                                '''\
-                                %(
-                                self.TitleID,
-                                self.Star
-                                )
-        return DumpString
-
-
-class  tagMCTitleStarInfo(Structure):
-    Head = tagHead()
-    Count = 0    #(BYTE Count)
-    TitleStarList = list()    #(vector<tagMCTitleStar> TitleStarList)
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xA3
-        self.Head.SubCmd = 0xCE
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        for i in range(self.Count):
-            temTitleStarList = tagMCTitleStar()
-            _pos = temTitleStarList.ReadData(_lpData, _pos)
-            self.TitleStarList.append(temTitleStarList)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xA3
-        self.Head.SubCmd = 0xCE
-        self.Count = 0
-        self.TitleStarList = list()
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        for i in range(self.Count):
-            length += self.TitleStarList[i].GetLength()
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.Count)
-        for i in range(self.Count):
-            data = CommFunc.WriteString(data, self.TitleStarList[i].GetLength(), self.TitleStarList[i].GetBuffer())
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                Count:%d,
-                                TitleStarList:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.Count,
-                                "..."
-                                )
-        return DumpString
-
-
-m_NAtagMCTitleStarInfo=tagMCTitleStarInfo()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCTitleStarInfo.Head.Cmd,m_NAtagMCTitleStarInfo.Head.SubCmd))] = m_NAtagMCTitleStarInfo
-
-
-#------------------------------------------------------
 # A3 56 通天令信息 #tagMCTongTianLingInfo
 
 class  tagMCTongTianLingInfo(Structure):
@@ -14752,122 +14644,6 @@
 
 m_NAtagMCBossHurtList=tagMCBossHurtList()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCBossHurtList.Head.Cmd,m_NAtagMCBossHurtList.Head.SubCmd))] = m_NAtagMCBossHurtList
-
-
-#------------------------------------------------------
-# A7 17 聊天气泡框状态 #tagMCChatBubbleBoxState
-
-class  tagMCChatBubbleBox(Structure):
-    _pack_ = 1
-    _fields_ = [
-                  ("BoxID", c_ubyte),    #气泡ID
-                  ("State", c_ubyte),    #是否已激活
-                  ("EndTime", c_int),    #到期时间戳,0为永久
-                  ("Star", c_ubyte),    #星级
-                  ]
-
-    def __init__(self):
-        self.Clear()
-        return
-
-    def ReadData(self, stringData, _pos=0, _len=0):
-        self.Clear()
-        memmove(addressof(self), stringData[_pos:], self.GetLength())
-        return _pos + self.GetLength()
-
-    def Clear(self):
-        self.BoxID = 0
-        self.State = 0
-        self.EndTime = 0
-        self.Star = 0
-        return
-
-    def GetLength(self):
-        return sizeof(tagMCChatBubbleBox)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// A7 17 聊天气泡框状态 //tagMCChatBubbleBoxState:
-                                BoxID:%d,
-                                State:%d,
-                                EndTime:%d,
-                                Star:%d
-                                '''\
-                                %(
-                                self.BoxID,
-                                self.State,
-                                self.EndTime,
-                                self.Star
-                                )
-        return DumpString
-
-
-class  tagMCChatBubbleBoxState(Structure):
-    Head = tagHead()
-    Count = 0    #(BYTE Count)
-    BoxList = list()    #(vector<tagMCChatBubbleBox> BoxList)
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xA7
-        self.Head.SubCmd = 0x17
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        for i in range(self.Count):
-            temBoxList = tagMCChatBubbleBox()
-            _pos = temBoxList.ReadData(_lpData, _pos)
-            self.BoxList.append(temBoxList)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xA7
-        self.Head.SubCmd = 0x17
-        self.Count = 0
-        self.BoxList = list()
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        for i in range(self.Count):
-            length += self.BoxList[i].GetLength()
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.Count)
-        for i in range(self.Count):
-            data = CommFunc.WriteString(data, self.BoxList[i].GetLength(), self.BoxList[i].GetBuffer())
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                Count:%d,
-                                BoxList:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.Count,
-                                "..."
-                                )
-        return DumpString
-
-
-m_NAtagMCChatBubbleBoxState=tagMCChatBubbleBoxState()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCChatBubbleBoxState.Head.Cmd,m_NAtagMCChatBubbleBoxState.Head.SubCmd))] = m_NAtagMCChatBubbleBoxState
 
 
 #------------------------------------------------------
@@ -35765,6 +35541,122 @@
 
 
 #------------------------------------------------------
+# B1 27 聊天气泡框信息 #tagSCChatBoxInfo
+
+class  tagSCChatBox(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("BoxID", c_int),    #气泡框ID
+                  ("State", c_ubyte),    #是否已激活
+                  ("EndTime", c_int),    #到期时间戳,0为永久
+                  ("Star", c_ubyte),    #星级
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.BoxID = 0
+        self.State = 0
+        self.EndTime = 0
+        self.Star = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagSCChatBox)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B1 27 聊天气泡框信息 //tagSCChatBoxInfo:
+                                BoxID:%d,
+                                State:%d,
+                                EndTime:%d,
+                                Star:%d
+                                '''\
+                                %(
+                                self.BoxID,
+                                self.State,
+                                self.EndTime,
+                                self.Star
+                                )
+        return DumpString
+
+
+class  tagSCChatBoxInfo(Structure):
+    Head = tagHead()
+    Count = 0    #(BYTE Count)
+    BoxList = list()    #(vector<tagSCChatBox> BoxList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB1
+        self.Head.SubCmd = 0x27
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temBoxList = tagSCChatBox()
+            _pos = temBoxList.ReadData(_lpData, _pos)
+            self.BoxList.append(temBoxList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB1
+        self.Head.SubCmd = 0x27
+        self.Count = 0
+        self.BoxList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        for i in range(self.Count):
+            length += self.BoxList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.BoxList[i].GetLength(), self.BoxList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                Count:%d,
+                                BoxList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagSCChatBoxInfo=tagSCChatBoxInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCChatBoxInfo.Head.Cmd,m_NAtagSCChatBoxInfo.Head.SubCmd))] = m_NAtagSCChatBoxInfo
+
+
+#------------------------------------------------------
 # B1 02 玩家时装皮肤激活状态 #tagMCClothesCoatSkinState
 
 class  tagMCClothesCoatLVInfo(Structure):
@@ -36598,6 +36490,122 @@
 
 
 #------------------------------------------------------
+# B1 19 形象信息 #tagSCModelInfo
+
+class  tagSCModel(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ModelID", c_int),    #形象ID
+                  ("State", c_ubyte),    #是否已激活
+                  ("EndTime", c_int),    #到期时间戳,0为永久
+                  ("Star", c_ubyte),    #星级
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.ModelID = 0
+        self.State = 0
+        self.EndTime = 0
+        self.Star = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagSCModel)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B1 19 形象信息 //tagSCModelInfo:
+                                ModelID:%d,
+                                State:%d,
+                                EndTime:%d,
+                                Star:%d
+                                '''\
+                                %(
+                                self.ModelID,
+                                self.State,
+                                self.EndTime,
+                                self.Star
+                                )
+        return DumpString
+
+
+class  tagSCModelInfo(Structure):
+    Head = tagHead()
+    Count = 0    #(BYTE Count)
+    ModelList = list()    #(vector<tagSCModel> ModelList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB1
+        self.Head.SubCmd = 0x19
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temModelList = tagSCModel()
+            _pos = temModelList.ReadData(_lpData, _pos)
+            self.ModelList.append(temModelList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB1
+        self.Head.SubCmd = 0x19
+        self.Count = 0
+        self.ModelList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        for i in range(self.Count):
+            length += self.ModelList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.ModelList[i].GetLength(), self.ModelList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                Count:%d,
+                                ModelList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagSCModelInfo=tagSCModelInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCModelInfo.Head.Cmd,m_NAtagSCModelInfo.Head.SubCmd))] = m_NAtagSCModelInfo
+
+
+#------------------------------------------------------
 # B1 06 通知玩家向目标点移动 #tagMCNotifyPlayerMove
 
 class  tagMCNotifyPlayerMove(Structure):
@@ -37297,6 +37305,122 @@
 
 
 #------------------------------------------------------
+# B1 26 称号信息 #tagSCTitleInfo
+
+class  tagSCTitle(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("TitleID", c_int),    #称号ID
+                  ("State", c_ubyte),    #是否已激活
+                  ("EndTime", c_int),    #到期时间戳,0为永久
+                  ("Star", c_ubyte),    #星级
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.TitleID = 0
+        self.State = 0
+        self.EndTime = 0
+        self.Star = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagSCTitle)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B1 26 称号信息 //tagSCTitleInfo:
+                                TitleID:%d,
+                                State:%d,
+                                EndTime:%d,
+                                Star:%d
+                                '''\
+                                %(
+                                self.TitleID,
+                                self.State,
+                                self.EndTime,
+                                self.Star
+                                )
+        return DumpString
+
+
+class  tagSCTitleInfo(Structure):
+    Head = tagHead()
+    Count = 0    #(BYTE Count)
+    TitleList = list()    #(vector<tagSCTitle> TitleList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB1
+        self.Head.SubCmd = 0x26
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temTitleList = tagSCTitle()
+            _pos = temTitleList.ReadData(_lpData, _pos)
+            self.TitleList.append(temTitleList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB1
+        self.Head.SubCmd = 0x26
+        self.Count = 0
+        self.TitleList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        for i in range(self.Count):
+            length += self.TitleList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.TitleList[i].GetLength(), self.TitleList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                Count:%d,
+                                TitleList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagSCTitleInfo=tagSCTitleInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCTitleInfo.Head.Cmd,m_NAtagSCTitleInfo.Head.SubCmd))] = m_NAtagSCTitleInfo
+
+
+#------------------------------------------------------
 # B1 12 培养功能境界信息 #tagMCTrainRealmLVInfo
 
 class  tagMCTrainRealmLV(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/AddTitle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/AddTitle.py
deleted file mode 100644
index 3b4d4f5..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/AddTitle.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#---------------------------------------------------------------------
-#
-#---------------------------------------------------------------------
-##@package AddTitle
-# @todo: 给玩家称号
-#
-# @author: Alee
-# @date 2014-11-14 19:30
-# @version 1.1
-#
-# @note: 参数1为称号ID,存在参数2代表删除
-# @change: "2014-12-20 17:00" ljd 增加指定玩家称号增删
-# 
-#---------------------------------------------------------------------
-"""Version = 2014-12-20 17:00"""
-#---------------------------------------------------------------------
-import IPY_GameWorld
-import GameWorld
-import ItemCommon
-import ItemControler
-import ChConfig
-import PlayerDienstgrad
-#---------------------------------------------------------------------
-#逻辑实现
-## GM命令执行入口
-#  @param curPlayer 当前玩家
-#  @param msgList 参数列表
-#  @return None
-#  @remarks 函数详细说明.
-def OnExec(curPlayer, msgList):
-    if len(msgList) < 2:
-        GameWorld.DebugAnswer(curPlayer, "AddTitle 称号ID 操作[0-删除 1-增加] 有效时间 玩家ID[无玩家ID表示给自己操作]")
-        return
-    
-    if len(msgList) >= 4:
-        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(msgList[3])
-    
-    if msgList[1]:
-        nTime = msgList[2] if len(msgList) > 2 else 0
-        result = PlayerDienstgrad.PlayerAddDienstgrad(curPlayer, msgList[0], expireTime=nTime)
-        GameWorld.DebugAnswer(curPlayer, "增加称号[%s]:%s-%s"%(msgList[0], result, nTime))
-    else:
-        result = PlayerDienstgrad.PlayerDelDienstgrad(curPlayer, msgList[0])
-        GameWorld.DebugAnswer(curPlayer, "删除称号[%s]:True"%msgList[0])
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ChatBox.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ChatBox.py
index fb48fe7..0accdec 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ChatBox.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ChatBox.py
@@ -34,8 +34,8 @@
         GameWorld.DebugAnswer(curPlayer, "添加气泡框: ChatBox b1 气泡框ID [有效秒]")
         GameWorld.DebugAnswer(curPlayer, "删除气泡框: ChatBox b0 [气泡框ID]")
         GameWorld.DebugAnswer(curPlayer, "气泡框星级: ChatBox bs 气泡框ID 星级")
-        GameWorld.DebugAnswer(curPlayer, "添加表情包: ChatBox e1 表情包ID [有效秒]")
-        GameWorld.DebugAnswer(curPlayer, "删除表情包: ChatBox e0 [表情包ID]")
+        #GameWorld.DebugAnswer(curPlayer, "添加表情包: ChatBox e1 表情包ID [有效秒]")
+        #GameWorld.DebugAnswer(curPlayer, "删除表情包: ChatBox e0 [表情包ID]")
         GameWorld.DebugAnswer(curPlayer, "有效秒:不填读表,0-永久,>0指定有效秒")
         return
     
@@ -48,26 +48,21 @@
     if value1 == "b0":
         boxID = msgList[1] if len(msgList) > 1 else 0
         if not boxID:
-            for index in range(ipyDataMgr.GetChatBubbleBoxCount()):
-                ipyData = ipyDataMgr.GetChatBubbleBoxByIndex(index)
+            for index in range(ipyDataMgr.GetChatBoxCount()):
+                ipyData = ipyDataMgr.GetChatBoxByIndex(index)
                 boxID = ipyData.GetBoxID()
-                if ipyData.GetUnlockDefault():
+                if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID):
                     continue
-                if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID):
-                    continue
-                GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID, 0)
+                GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID, 0)
                 PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxEndTime % boxID, 0)
                 PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxStar % boxID, 0)
                 syncBoxIDList.append(boxID)
         else:
-            ipyData = IpyGameDataPY.GetIpyGameData("ChatBubbleBox", boxID)
+            ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
             if not ipyData:
                 GameWorld.DebugAnswer(curPlayer, "该气泡框不存在:%s" % boxID)
                 return
-            if ipyData.GetUnlockDefault():
-                GameWorld.DebugAnswer(curPlayer, "该气泡框默认激活:%s" % boxID)
-                return
-            GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID, 0)
+            GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID, 0)
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxEndTime % boxID, 0)
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxStar % boxID, 0)
             syncBoxIDList.append(boxID)
@@ -77,7 +72,7 @@
     elif value1 == "b1":
         boxID = msgList[1] if len(msgList) > 1 else 0
         expireTimes = msgList[2] if len(msgList) > 2 else None
-        if PlayerChatBox.AddChatBox(curPlayer, boxID, expireTimes):
+        if PlayerChatBox.AddChatBox(curPlayer, boxID, expireTimes, True):
             endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxEndTime % boxID)
             endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
             GameWorld.DebugAnswer(curPlayer, "添加气泡框成功:%s,到期:%s" % (boxID, endTimeStr))
@@ -88,11 +83,11 @@
     elif value1 == "bs":
         boxID = msgList[1] if len(msgList) > 1 else 0
         boxStar = msgList[2] if len(msgList) > 2 else 0
-        if boxStar:
-            starIpyData = IpyGameDataPY.GetIpyGameData("ChatBubbleBoxStar", boxID, boxStar)
-            if not starIpyData:
-                GameWorld.DebugAnswer(curPlayer, "气泡框星级不存在:%s,star:%s" % (boxID, boxStar))
-                return
+        ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
+        if not ipyData:
+            GameWorld.DebugAnswer(curPlayer, "该气泡框不存在:%s" % boxID)
+            return
+        boxStar = min(boxStar, ipyData.GetStarMax())
         GameWorld.DebugAnswer(curPlayer, "设置气泡框星级:%s,星:%s" % (boxID, boxStar))
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxStar % boxID, boxStar)
         syncBoxIDList.append(boxID)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ClearTitle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ClearTitle.py
deleted file mode 100644
index 2917fc3..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ClearTitle.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-
-##@package ClearTitle
-# 清除称号
-#
-# @author hch
-# @date 2010-4-21
-# @version 1.0
-#
-# 修改时间 修改人 修改内容
-# VER = "2010-05-12 18:30" zhengyang 添加注释
-#
-# 模块详细说明
-
-#导入
-import IPY_GameWorld
-import Lang
-import PlayerDienstgrad
-import PlayerControl
-import GameWorld
-#---------------------------------------------------------------------
-#全局变量
-#---------------------------------------------------------------------
-
-#---------------------------------------------------------------------
-#逻辑实现
-
-## GM命令执行入口
-#  @param curPlayer 当前玩家
-#  @param playerList 参数列表 []
-#  @return True
-#  @remarks 函数详细说明.
-def OnExec(curPlayer,playerList):
-    backPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptTitle)
-    for i in range(backPack.GetCount()):
-        curItem = backPack.GetAt(i)
-        curItem.Clear()
-        
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    gradCnt = curDienstgradMgr.GetCount()
-    for i in xrange(gradCnt):
-        curGradID = curPlayer.GetDienstgradManager().AtGradID(i)
-        if not curGradID:
-            continue
-        curDienstgradMgr.DeleteDienstgrad(curGradID)
-        curDienstgradMgr.Sync_PlayerDelDienstgrad(curGradID)
-        GameWorld.DebugAnswer(curPlayer, "删除称号: %s" % curGradID)
-        
-    #重新刷新角色属性
-    PlayerDienstgrad.CalcAllDienstgradAttr(curPlayer)
-    playerControl = PlayerControl.PlayerControl(curPlayer)
-    playerControl.RefreshPlayerAttrState()
-    GameWorld.DebugAnswer(curPlayer, Lang.GBText("清除称号成功: %s" % gradCnt))
-    return True
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Face.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Face.py
index e31234d..ebf9feb 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Face.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Face.py
@@ -52,10 +52,6 @@
             for index in range(ipyDataMgr.GetPlayerFaceCount()):
                 ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
                 faceID = ipyData.GetFaceID()
-                if ipyData.GetUnlockDefault():
-                    continue
-                if ipyData.GetCustomPlayerID():
-                    continue
                 if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID):
                     continue
                 GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID, 0)
@@ -67,12 +63,6 @@
             if not ipyData:
                 GameWorld.DebugAnswer(curPlayer, "该头像不存在:%s" % faceID)
                 return
-            if ipyData.GetUnlockDefault():
-                GameWorld.DebugAnswer(curPlayer, "该头像默认激活:%s" % faceID)
-                return
-            if ipyData.GetCustomPlayerID():
-                GameWorld.DebugAnswer(curPlayer, "定制头像不处理:%s" % faceID)
-                return
             GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID, 0)
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FaceEndTime % faceID, 0)
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FaceStar % faceID, 0)
@@ -83,21 +73,22 @@
     elif value1 == "f1":
         faceID = msgList[1] if len(msgList) > 1 else 0
         expireTimes = msgList[2] if len(msgList) > 2 else None
-        if PlayerFace.AddFace(curPlayer, faceID, expireTimes):
+        if PlayerFace.AddFace(curPlayer, faceID, expireTimes, True):
             endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceEndTime % faceID)
             endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
             GameWorld.DebugAnswer(curPlayer, "添加头像成功:%s,到期:%s" % (faceID, endTimeStr))
         else:
             GameWorld.DebugAnswer(curPlayer, "添加头像失败:%s" % (faceID))
-                    
+            
     # 头像星级
     elif value1 == "fs":
         faceID = msgList[1] if len(msgList) > 1 else 0
         faceStar = msgList[2] if len(msgList) > 2 else 0
-        starIpyData = IpyGameDataPY.GetIpyGameData("PlayerFaceStar", faceID, faceStar)
-        if not starIpyData:
-            GameWorld.DebugAnswer(curPlayer, "头像星级不存在:%s,star:%s" % (faceID, faceStar))
+        ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
+        if not ipyData:
+            GameWorld.DebugAnswer(curPlayer, "该头像不存在:%s" % faceID)
             return
+        faceStar = min(faceStar, ipyData.GetStarMax())
         GameWorld.DebugAnswer(curPlayer, "设置头像星级:%s,星:%s" % (faceID, faceStar))
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FaceStar % faceID, faceStar)
         syncFaceIDList.append(faceID)
@@ -109,8 +100,6 @@
             for index in range(ipyDataMgr.GetPlayerFacePicCount()):
                 ipyData = ipyDataMgr.GetPlayerFacePicByIndex(index)
                 facePicID = ipyData.GetFacePicID()
-                if ipyData.GetUnlockDefault():
-                    continue
                 if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID):
                     continue
                 GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID, 0)
@@ -122,9 +111,6 @@
             if not ipyData:
                 GameWorld.DebugAnswer(curPlayer, "该头像框不存在:%s" % facePicID)
                 return
-            if ipyData.GetUnlockDefault():
-                GameWorld.DebugAnswer(curPlayer, "该头像框默认激活:%s" % facePicID)
-                return
             GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID, 0)
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FacePicEndTime % facePicID, 0)
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FacePicStar % facePicID, 0)
@@ -135,7 +121,7 @@
     elif value1 == "p1":
         facePicID = msgList[1] if len(msgList) > 1 else 0
         expireTimes = msgList[2] if len(msgList) > 2 else None
-        if PlayerFace.AddFacePic(curPlayer, facePicID, expireTimes):
+        if PlayerFace.AddFacePic(curPlayer, facePicID, expireTimes, True):
             endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicEndTime % facePicID)
             endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
             GameWorld.DebugAnswer(curPlayer, "添加头像框成功:%s,到期:%s" % (facePicID, endTimeStr))
@@ -146,10 +132,11 @@
     elif value1 == "ps":
         facePicID = msgList[1] if len(msgList) > 1 else 0
         facePicStar = msgList[2] if len(msgList) > 2 else 0
-        starIpyData = IpyGameDataPY.GetIpyGameData("PlayerFacePicStar", facePicID, facePicStar)
-        if not starIpyData:
-            GameWorld.DebugAnswer(curPlayer, "头像框星级不存在:%s,star:%s" % (facePicID, facePicStar))
+        ipyData = IpyGameDataPY.GetIpyGameData("PlayerFacePic", facePicID)
+        if not ipyData:
+            GameWorld.DebugAnswer(curPlayer, "该头像框不存在:%s" % facePicID)
             return
+        facePicStar = min(facePicStar, ipyData.GetStarMax())
         GameWorld.DebugAnswer(curPlayer, "设置头像框星级:%s,星:%s" % (facePicID, facePicStar))
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FacePicStar % facePicID, facePicStar)
         syncFacePicIDList.append(facePicID)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/HJG.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/HJG.py
new file mode 100644
index 0000000..22c4c1a
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/HJG.py
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.HJG
+#
+# @todo:幻境阁
+# @author hxp
+# @date 2025-10-15
+# @version 1.0
+#
+# 详细描述: 幻境阁
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-10-15 09:30"""
+#-------------------------------------------------------------------------------
+
+import ChConfig
+import GameWorld
+import IpyGameDataPY
+import PlayerControl
+import PlayerHJG
+import ChatBox
+import Face
+
+def OnExec(curPlayer, msgList):
+    
+    if not msgList:
+        GameWorld.DebugAnswer(curPlayer, "---------- %s" % GameWorld.GetCurrentDataTimeStr())
+        GameWorld.DebugAnswer(curPlayer, "添加称号: HJG t1 称号ID [有效秒]")
+        GameWorld.DebugAnswer(curPlayer, "删除称号: HJG t0 [称号ID]")
+        GameWorld.DebugAnswer(curPlayer, "称号星级: HJG ts 称号ID 星级")
+        GameWorld.DebugAnswer(curPlayer, "添加形象: HJG m1 形象ID [有效秒]")
+        GameWorld.DebugAnswer(curPlayer, "删除形象: HJG m0 [形象ID]")
+        GameWorld.DebugAnswer(curPlayer, "形象星级: HJG ms 形象ID 星级")
+        GameWorld.DebugAnswer(curPlayer, "有效秒:不填读表,0-永久,>0指定有效秒")
+        Face.OnExec(curPlayer, msgList)
+        ChatBox.OnExec(curPlayer, msgList)
+        return
+    
+    syncTitleIDList = []
+    syncModelIDList = []
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    value1 = msgList[0]
+    
+    # 删除称号
+    if value1 == "t1":
+        titleID = msgList[1] if len(msgList) > 1 else 0
+        if not titleID:
+            for index in range(ipyDataMgr.GetTitleCount()):
+                ipyData = ipyDataMgr.GetTitleByIndex(index)
+                titleID = ipyData.GetTitleID()
+                if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID):
+                    continue
+                GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID, 0)
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleEndTime % titleID, 0)
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % titleID, 0)
+                syncTitleIDList.append(titleID)
+        else:
+            ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+            if not ipyData:
+                GameWorld.DebugAnswer(curPlayer, "该称号不存在:%s" % titleID)
+                return
+            GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID, 0)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleEndTime % titleID, 0)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % titleID, 0)
+            syncTitleIDList.append(titleID)
+        GameWorld.DebugAnswer(curPlayer, "删除称号:%s" % syncTitleIDList)
+        
+    # 添加称号
+    elif value1 == "t1":
+        titleID = msgList[1] if len(msgList) > 1 else 0
+        expireTimes = msgList[2] if len(msgList) > 2 else None
+        if PlayerHJG.AddTitle(curPlayer, titleID, expireTimes, True):
+            endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleEndTime % titleID)
+            endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
+            GameWorld.DebugAnswer(curPlayer, "添加称号成功:%s,到期:%s" % (titleID, endTimeStr))
+        else:
+            GameWorld.DebugAnswer(curPlayer, "添加称号失败:%s" % (titleID))
+            
+    # 称号星级
+    elif value1 == "ts":
+        titleID = msgList[1] if len(msgList) > 1 else 0
+        setStar = msgList[2] if len(msgList) > 2 else 0
+        ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+        if not ipyData:
+            GameWorld.DebugAnswer(curPlayer, "该称号不存在:%s" % titleID)
+            return
+        setStar = min(setStar, ipyData.GetStarMax())
+        GameWorld.DebugAnswer(curPlayer, "设置称号星级:%s,星:%s" % (titleID, setStar))
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % titleID, setStar)
+        syncTitleIDList.append(titleID)
+        
+    # 删除形象
+    elif value1 == "m0":
+        modelID = msgList[1] if len(msgList) > 1 else 0
+        if not modelID:
+            for index in range(ipyDataMgr.GetModelCount()):
+                ipyData = ipyDataMgr.GetModelByIndex(index)
+                modelID = ipyData.GetModelID()
+                if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID):
+                    continue
+                GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID, 0)
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelEndTime % modelID, 0)
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelStar % modelID, 0)
+                syncModelIDList.append(modelID)
+        else:
+            ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+            if not ipyData:
+                GameWorld.DebugAnswer(curPlayer, "该形象不存在:%s" % modelID)
+                return
+            GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID, 0)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelEndTime % modelID, 0)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelStar % modelID, 0)
+            syncModelIDList.append(modelID)
+        GameWorld.DebugAnswer(curPlayer, "删除形象:%s" % syncModelIDList)
+        
+    # 添加形象
+    elif value1 == "m1":
+        modelID = msgList[1] if len(msgList) > 1 else 0
+        expireTimes = msgList[2] if len(msgList) > 2 else None
+        if PlayerHJG.AddModel(curPlayer, modelID, expireTimes, True):
+            endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelEndTime % modelID)
+            endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
+            GameWorld.DebugAnswer(curPlayer, "添加形象成功:%s,到期:%s" % (modelID, endTimeStr))
+        else:
+            GameWorld.DebugAnswer(curPlayer, "添加形象失败:%s" % (modelID))
+                    
+    # 形象星级
+    elif value1 == "ms":
+        modelID = msgList[1] if len(msgList) > 1 else 0
+        setStar = msgList[2] if len(msgList) > 2 else 0
+        ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+        if not ipyData:
+            GameWorld.DebugAnswer(curPlayer, "该形象不存在:%s" % modelID)
+            return
+        setStar = min(setStar, ipyData.GetStarMax())
+        GameWorld.DebugAnswer(curPlayer, "设置形象星级:%s,星:%s" % (modelID, setStar))
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelStar % modelID, setStar)
+        syncModelIDList.append(modelID)
+        
+    if syncTitleIDList:
+        PlayerHJG.RefreshHJGAttr(curPlayer)
+        PlayerHJG.SyncTitleInfo(curPlayer, syncTitleIDList)
+        
+    if syncModelIDList:
+        PlayerHJG.RefreshHJGAttr(curPlayer)
+        PlayerHJG.SyncModelInfo(curPlayer, syncModelIDList)
+    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 2eb4c1f..fe91e04 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -333,57 +333,69 @@
                         ("BYTE", "SkillExCnt", 0),
                         ),
 
-                "Dienstgrad":(
-                        ("DWORD", "ID", 1),
-                        ("WORD", "Type", 0),
-                        ("DWORD", "ExpireTime", 0),
-                        ("list", "LightType", 0),
-                        ("list", "LightAttribute", 0),
-                        ("list", "Skills", 0),
-                        ("DWORD", "InitFightPower", 0),
+                "Title":(
+                        ("DWORD", "TitleID", 1),
+                        ("DWORD", "ExpireMinutes", 0),
+                        ("BYTE", "UnlockWay", 0),
+                        ("DWORD", "UnlockValue", 0),
+                        ("BYTE", "UnlockNeedCnt", 0),
+                        ("BYTE", "UpNeedCnt", 0),
+                        ("BYTE", "StarMax", 0),
+                        ("list", "AttrIDList", 0),
+                        ("list", "InitAttrValueList", 0),
+                        ("list", "AttrPerStarAddList", 0),
                         ),
 
-                "TitleStarUp":(
-                        ("DWORD", "TitleID", 1),
-                        ("BYTE", "TitleStar", 1),
-                        ("list", "StarUpNeedItemList", 0),
-                        ("list", "StarAttrType", 0),
-                        ("list", "StarAttrValue", 0),
+                "Model":(
+                        ("DWORD", "ModelID", 1),
+                        ("DWORD", "ExpireMinutes", 0),
+                        ("BYTE", "UnlockWay", 0),
+                        ("DWORD", "UnlockValue", 0),
+                        ("BYTE", "UnlockNeedCnt", 0),
+                        ("BYTE", "UpNeedCnt", 0),
+                        ("BYTE", "StarMax", 0),
+                        ("list", "AttrIDList", 0),
+                        ("list", "InitAttrValueList", 0),
+                        ("list", "AttrPerStarAddList", 0),
                         ),
 
                 "PlayerFace":(
                         ("DWORD", "FaceID", 1),
-                        ("BYTE", "UnlockDefault", 0),
                         ("DWORD", "ExpireMinutes", 0),
-                        ("DWORD", "CustomPlayerID", 0),
-                        ("list", "LightAttrType", 0),
-                        ("list", "LightAttrValue", 0),
-                        ("DWORD", "LightFightPower", 0),
-                        ),
-
-                "PlayerFaceStar":(
-                        ("DWORD", "FaceID", 1),
-                        ("BYTE", "FaceStar", 1),
-                        ("list", "StarUpNeedItemList", 0),
-                        ("list", "StarAttrType", 0),
-                        ("list", "StarAttrValue", 0),
+                        ("BYTE", "UnlockWay", 0),
+                        ("DWORD", "UnlockValue", 0),
+                        ("BYTE", "UnlockNeedCnt", 0),
+                        ("BYTE", "UpNeedCnt", 0),
+                        ("BYTE", "StarMax", 0),
+                        ("list", "AttrIDList", 0),
+                        ("list", "InitAttrValueList", 0),
+                        ("list", "AttrPerStarAddList", 0),
                         ),
 
                 "PlayerFacePic":(
                         ("DWORD", "FacePicID", 1),
-                        ("BYTE", "UnlockDefault", 0),
                         ("DWORD", "ExpireMinutes", 0),
-                        ("list", "LightAttrType", 0),
-                        ("list", "LightAttrValue", 0),
-                        ("DWORD", "LightFightPower", 0),
+                        ("BYTE", "UnlockWay", 0),
+                        ("DWORD", "UnlockValue", 0),
+                        ("BYTE", "UnlockNeedCnt", 0),
+                        ("BYTE", "UpNeedCnt", 0),
+                        ("BYTE", "StarMax", 0),
+                        ("list", "AttrIDList", 0),
+                        ("list", "InitAttrValueList", 0),
+                        ("list", "AttrPerStarAddList", 0),
                         ),
 
-                "PlayerFacePicStar":(
-                        ("DWORD", "FacePicID", 1),
-                        ("BYTE", "FacePicStar", 1),
-                        ("list", "StarUpNeedItemList", 0),
-                        ("list", "StarAttrType", 0),
-                        ("list", "StarAttrValue", 0),
+                "ChatBox":(
+                        ("BYTE", "BoxID", 1),
+                        ("DWORD", "ExpireMinutes", 0),
+                        ("BYTE", "UnlockWay", 0),
+                        ("DWORD", "UnlockValue", 0),
+                        ("BYTE", "UnlockNeedCnt", 0),
+                        ("BYTE", "UpNeedCnt", 0),
+                        ("BYTE", "StarMax", 0),
+                        ("list", "AttrIDList", 0),
+                        ("list", "InitAttrValueList", 0),
+                        ("list", "AttrPerStarAddList", 0),
                         ),
 
                 "SkillMatch":(
@@ -1790,25 +1802,6 @@
                         ("dict", "Award", 0),
                         ),
 
-                "ChatBubbleBox":(
-                        ("BYTE", "BoxID", 1),
-                        ("WORD", "NeedLV", 0),
-                        ("BYTE", "NeedVIPLVGift", 0),
-                        ("BYTE", "UnlockDefault", 0),
-                        ("DWORD", "ExpireMinutes", 0),
-                        ("list", "LightAttrType", 0),
-                        ("list", "LightAttrValue", 0),
-                        ("DWORD", "LightFightPower", 0),
-                        ),
-
-                "ChatBubbleBoxStar":(
-                        ("BYTE", "BoxID", 1),
-                        ("BYTE", "BoxStar", 1),
-                        ("list", "StarUpNeedItemList", 0),
-                        ("list", "StarAttrType", 0),
-                        ("list", "StarAttrValue", 0),
-                        ),
-
                 "EmojiPack":(
                         ("DWORD", "EmojiPackID", 1),
                         ("BYTE", "UnlockDefault", 0),
@@ -2923,32 +2916,40 @@
     def GetSkillExCnt(self): return self.attrTuple[10] # 随机附加技能数,0为所有 BYTE
 
 # 称号表
-class IPY_Dienstgrad():
+class IPY_Title():
     
     def __init__(self):
         self.attrTuple = None
         return
         
-    def GetID(self): return self.attrTuple[0] # 头衔id DWORD
-    def GetType(self): return self.attrTuple[1] # 头衔类型 WORD
-    def GetExpireTime(self): return self.attrTuple[2] # 有效时间 DWORD
-    def GetLightType(self): return self.attrTuple[3] # 点亮属性类型 list
-    def GetLightAttribute(self): return self.attrTuple[4] # 点亮属性值 list
-    def GetSkills(self): return self.attrTuple[5] # 被动技能 list
-    def GetInitFightPower(self): return self.attrTuple[6] # 初始战力 DWORD
+    def GetTitleID(self): return self.attrTuple[0] # 称号ID DWORD
+    def GetExpireMinutes(self): return self.attrTuple[1] # 时效分钟,0永久 DWORD
+    def GetUnlockWay(self): return self.attrTuple[2] # 解锁方式 BYTE
+    def GetUnlockValue(self): return self.attrTuple[3] # 解锁方式值 DWORD
+    def GetUnlockNeedCnt(self): return self.attrTuple[4] # 解锁所需个数 BYTE
+    def GetUpNeedCnt(self): return self.attrTuple[5] # 升级所需个数 BYTE
+    def GetStarMax(self): return self.attrTuple[6] # 最高星级 BYTE
+    def GetAttrIDList(self): return self.attrTuple[7] # 属性ID列表 list
+    def GetInitAttrValueList(self): return self.attrTuple[8] # 初始属性值列表 list
+    def GetAttrPerStarAddList(self): return self.attrTuple[9] # 每星加成值列表 list
 
-# 称号升星表
-class IPY_TitleStarUp():
+# 形象表
+class IPY_Model():
     
     def __init__(self):
         self.attrTuple = None
         return
         
-    def GetTitleID(self): return self.attrTuple[0] # 称号NPCID DWORD
-    def GetTitleStar(self): return self.attrTuple[1] # 称号星级 BYTE
-    def GetStarUpNeedItemList(self): return self.attrTuple[2] # 升下一星所需道具 [[物品ID,个数], ...] list
-    def GetStarAttrType(self): return self.attrTuple[3] # 累计总属性类型 list
-    def GetStarAttrValue(self): return self.attrTuple[4] # 累计总属性值 list
+    def GetModelID(self): return self.attrTuple[0] # 形象ID DWORD
+    def GetExpireMinutes(self): return self.attrTuple[1] # 时效分钟,0永久 DWORD
+    def GetUnlockWay(self): return self.attrTuple[2] # 解锁方式 BYTE
+    def GetUnlockValue(self): return self.attrTuple[3] # 解锁方式值 DWORD
+    def GetUnlockNeedCnt(self): return self.attrTuple[4] # 解锁所需个数 BYTE
+    def GetUpNeedCnt(self): return self.attrTuple[5] # 升级所需个数 BYTE
+    def GetStarMax(self): return self.attrTuple[6] # 最高星级 BYTE
+    def GetAttrIDList(self): return self.attrTuple[7] # 属性ID列表 list
+    def GetInitAttrValueList(self): return self.attrTuple[8] # 初始属性值列表 list
+    def GetAttrPerStarAddList(self): return self.attrTuple[9] # 每星加成值列表 list
 
 # 头像表
 class IPY_PlayerFace():
@@ -2958,25 +2959,15 @@
         return
         
     def GetFaceID(self): return self.attrTuple[0] # 头像ID DWORD
-    def GetUnlockDefault(self): return self.attrTuple[1] # 是否默认激活 BYTE
-    def GetExpireMinutes(self): return self.attrTuple[2] # 时效分钟,0永久 DWORD
-    def GetCustomPlayerID(self): return self.attrTuple[3] # 定制玩家ID DWORD
-    def GetLightAttrType(self): return self.attrTuple[4] # 点亮属性类型 list
-    def GetLightAttrValue(self): return self.attrTuple[5] # 点亮属性值 list
-    def GetLightFightPower(self): return self.attrTuple[6] # 点亮附加战力 DWORD
-
-# 头像升星表
-class IPY_PlayerFaceStar():
-    
-    def __init__(self):
-        self.attrTuple = None
-        return
-        
-    def GetFaceID(self): return self.attrTuple[0] # 头像ID DWORD
-    def GetFaceStar(self): return self.attrTuple[1] # 头像星级 BYTE
-    def GetStarUpNeedItemList(self): return self.attrTuple[2] # 升该星所需物品 [[物品ID,个数], ...] list
-    def GetStarAttrType(self): return self.attrTuple[3] # 累计总属性类型 list
-    def GetStarAttrValue(self): return self.attrTuple[4] # 累计总属性值 list
+    def GetExpireMinutes(self): return self.attrTuple[1] # 时效分钟,0永久 DWORD
+    def GetUnlockWay(self): return self.attrTuple[2] # 解锁方式 BYTE
+    def GetUnlockValue(self): return self.attrTuple[3] # 解锁方式值 DWORD
+    def GetUnlockNeedCnt(self): return self.attrTuple[4] # 解锁所需个数 BYTE
+    def GetUpNeedCnt(self): return self.attrTuple[5] # 升级所需个数 BYTE
+    def GetStarMax(self): return self.attrTuple[6] # 最高星级 BYTE
+    def GetAttrIDList(self): return self.attrTuple[7] # 属性ID列表 list
+    def GetInitAttrValueList(self): return self.attrTuple[8] # 初始属性值列表 list
+    def GetAttrPerStarAddList(self): return self.attrTuple[9] # 每星加成值列表 list
 
 # 头像框表
 class IPY_PlayerFacePic():
@@ -2986,24 +2977,33 @@
         return
         
     def GetFacePicID(self): return self.attrTuple[0] # 头像框ID DWORD
-    def GetUnlockDefault(self): return self.attrTuple[1] # 是否默认激活 BYTE
-    def GetExpireMinutes(self): return self.attrTuple[2] # 时效分钟,0永久 DWORD
-    def GetLightAttrType(self): return self.attrTuple[3] # 点亮属性类型 list
-    def GetLightAttrValue(self): return self.attrTuple[4] # 点亮属性值 list
-    def GetLightFightPower(self): return self.attrTuple[5] # 点亮附加战力 DWORD
+    def GetExpireMinutes(self): return self.attrTuple[1] # 时效分钟,0永久 DWORD
+    def GetUnlockWay(self): return self.attrTuple[2] # 解锁方式 BYTE
+    def GetUnlockValue(self): return self.attrTuple[3] # 解锁方式值 DWORD
+    def GetUnlockNeedCnt(self): return self.attrTuple[4] # 解锁所需个数 BYTE
+    def GetUpNeedCnt(self): return self.attrTuple[5] # 升级所需个数 BYTE
+    def GetStarMax(self): return self.attrTuple[6] # 最高星级 BYTE
+    def GetAttrIDList(self): return self.attrTuple[7] # 属性ID列表 list
+    def GetInitAttrValueList(self): return self.attrTuple[8] # 初始属性值列表 list
+    def GetAttrPerStarAddList(self): return self.attrTuple[9] # 每星加成值列表 list
 
-# 头像框升星表
-class IPY_PlayerFacePicStar():
+# 气泡表
+class IPY_ChatBox():
     
     def __init__(self):
         self.attrTuple = None
         return
         
-    def GetFacePicID(self): return self.attrTuple[0] # 头像框ID DWORD
-    def GetFacePicStar(self): return self.attrTuple[1] # 头像框星级 BYTE
-    def GetStarUpNeedItemList(self): return self.attrTuple[2] # 升该星所需物品 [[物品ID,个数], ...] list
-    def GetStarAttrType(self): return self.attrTuple[3] # 累计总属性类型 list
-    def GetStarAttrValue(self): return self.attrTuple[4] # 累计总属性值 list
+    def GetBoxID(self): return self.attrTuple[0] # 气泡框ID BYTE
+    def GetExpireMinutes(self): return self.attrTuple[1] # 时效分钟,0永久 DWORD
+    def GetUnlockWay(self): return self.attrTuple[2] # 解锁方式 BYTE
+    def GetUnlockValue(self): return self.attrTuple[3] # 解锁方式值 DWORD
+    def GetUnlockNeedCnt(self): return self.attrTuple[4] # 解锁所需个数 BYTE
+    def GetUpNeedCnt(self): return self.attrTuple[5] # 升级所需个数 BYTE
+    def GetStarMax(self): return self.attrTuple[6] # 最高星级 BYTE
+    def GetAttrIDList(self): return self.attrTuple[7] # 属性ID列表 list
+    def GetInitAttrValueList(self): return self.attrTuple[8] # 初始属性值列表 list
+    def GetAttrPerStarAddList(self): return self.attrTuple[9] # 每星加成值列表 list
 
 # 技能搭配表
 class IPY_SkillMatch():
@@ -5104,35 +5104,6 @@
     def GetFuncID(self): return self.attrTuple[0] # 功能ID DWORD
     def GetAward(self): return self.attrTuple[1] # 属性类型 dict
 
-# 聊天气泡表
-class IPY_ChatBubbleBox():
-    
-    def __init__(self):
-        self.attrTuple = None
-        return
-        
-    def GetBoxID(self): return self.attrTuple[0] # 气泡框ID BYTE
-    def GetNeedLV(self): return self.attrTuple[1] # 所需等级 WORD
-    def GetNeedVIPLVGift(self): return self.attrTuple[2] # 所需购买VIP等级礼包 BYTE
-    def GetUnlockDefault(self): return self.attrTuple[3] # 是否默认激活 BYTE
-    def GetExpireMinutes(self): return self.attrTuple[4] # 时效分钟,0永久 DWORD
-    def GetLightAttrType(self): return self.attrTuple[5] # 点亮属性类型 list
-    def GetLightAttrValue(self): return self.attrTuple[6] # 点亮属性值 list
-    def GetLightFightPower(self): return self.attrTuple[7] # 点亮附加战力 DWORD
-
-# 聊天气泡升星表
-class IPY_ChatBubbleBoxStar():
-    
-    def __init__(self):
-        self.attrTuple = None
-        return
-        
-    def GetBoxID(self): return self.attrTuple[0] # 气泡框ID BYTE
-    def GetBoxStar(self): return self.attrTuple[1] # 气泡框星级 BYTE
-    def GetStarUpNeedItemList(self): return self.attrTuple[2] # 升该星所需物品 [[物品ID,个数], ...] list
-    def GetStarAttrType(self): return self.attrTuple[3] # 累计总属性类型 list
-    def GetStarAttrValue(self): return self.attrTuple[4] # 累计总属性值 list
-
 # 表情包表
 class IPY_EmojiPack():
     
@@ -6338,12 +6309,11 @@
         self.__LoadFileData("MainChapter", onlyCheck)
         self.__LoadFileData("MainLevel", onlyCheck)
         self.__LoadFileData("NPCLineup", onlyCheck)
-        self.__LoadFileData("Dienstgrad", onlyCheck)
-        self.__LoadFileData("TitleStarUp", onlyCheck)
+        self.__LoadFileData("Title", onlyCheck)
+        self.__LoadFileData("Model", onlyCheck)
         self.__LoadFileData("PlayerFace", onlyCheck)
-        self.__LoadFileData("PlayerFaceStar", onlyCheck)
         self.__LoadFileData("PlayerFacePic", onlyCheck)
-        self.__LoadFileData("PlayerFacePicStar", onlyCheck)
+        self.__LoadFileData("ChatBox", onlyCheck)
         self.__LoadFileData("SkillMatch", onlyCheck)
         self.__LoadFileData("RolePoint", onlyCheck)
         self.__LoadFileData("LingQiAttr", onlyCheck)
@@ -6483,8 +6453,6 @@
         self.__LoadFileData("ActWishingWell", onlyCheck)
         self.__LoadFileData("WishingWell", onlyCheck)
         self.__LoadFileData("FunctionForecast", onlyCheck)
-        self.__LoadFileData("ChatBubbleBox", onlyCheck)
-        self.__LoadFileData("ChatBubbleBoxStar", onlyCheck)
         self.__LoadFileData("EmojiPack", onlyCheck)
         self.__LoadFileData("ActRechargePrize", onlyCheck)
         self.__LoadFileData("RechargePrizeTemplate", onlyCheck)
@@ -6942,19 +6910,19 @@
         self.CheckLoadData("NPCLineup")
         return self.ipyNPCLineupCache[index]
 
-    def GetDienstgradCount(self):
-        self.CheckLoadData("Dienstgrad")
-        return self.ipyDienstgradLen
-    def GetDienstgradByIndex(self, index):
-        self.CheckLoadData("Dienstgrad")
-        return self.ipyDienstgradCache[index]
+    def GetTitleCount(self):
+        self.CheckLoadData("Title")
+        return self.ipyTitleLen
+    def GetTitleByIndex(self, index):
+        self.CheckLoadData("Title")
+        return self.ipyTitleCache[index]
 
-    def GetTitleStarUpCount(self):
-        self.CheckLoadData("TitleStarUp")
-        return self.ipyTitleStarUpLen
-    def GetTitleStarUpByIndex(self, index):
-        self.CheckLoadData("TitleStarUp")
-        return self.ipyTitleStarUpCache[index]
+    def GetModelCount(self):
+        self.CheckLoadData("Model")
+        return self.ipyModelLen
+    def GetModelByIndex(self, index):
+        self.CheckLoadData("Model")
+        return self.ipyModelCache[index]
 
     def GetPlayerFaceCount(self):
         self.CheckLoadData("PlayerFace")
@@ -6963,13 +6931,6 @@
         self.CheckLoadData("PlayerFace")
         return self.ipyPlayerFaceCache[index]
 
-    def GetPlayerFaceStarCount(self):
-        self.CheckLoadData("PlayerFaceStar")
-        return self.ipyPlayerFaceStarLen
-    def GetPlayerFaceStarByIndex(self, index):
-        self.CheckLoadData("PlayerFaceStar")
-        return self.ipyPlayerFaceStarCache[index]
-
     def GetPlayerFacePicCount(self):
         self.CheckLoadData("PlayerFacePic")
         return self.ipyPlayerFacePicLen
@@ -6977,12 +6938,12 @@
         self.CheckLoadData("PlayerFacePic")
         return self.ipyPlayerFacePicCache[index]
 
-    def GetPlayerFacePicStarCount(self):
-        self.CheckLoadData("PlayerFacePicStar")
-        return self.ipyPlayerFacePicStarLen
-    def GetPlayerFacePicStarByIndex(self, index):
-        self.CheckLoadData("PlayerFacePicStar")
-        return self.ipyPlayerFacePicStarCache[index]
+    def GetChatBoxCount(self):
+        self.CheckLoadData("ChatBox")
+        return self.ipyChatBoxLen
+    def GetChatBoxByIndex(self, index):
+        self.CheckLoadData("ChatBox")
+        return self.ipyChatBoxCache[index]
 
     def GetSkillMatchCount(self):
         self.CheckLoadData("SkillMatch")
@@ -7956,20 +7917,6 @@
     def GetFunctionForecastByIndex(self, index):
         self.CheckLoadData("FunctionForecast")
         return self.ipyFunctionForecastCache[index]
-
-    def GetChatBubbleBoxCount(self):
-        self.CheckLoadData("ChatBubbleBox")
-        return self.ipyChatBubbleBoxLen
-    def GetChatBubbleBoxByIndex(self, index):
-        self.CheckLoadData("ChatBubbleBox")
-        return self.ipyChatBubbleBoxCache[index]
-
-    def GetChatBubbleBoxStarCount(self):
-        self.CheckLoadData("ChatBubbleBoxStar")
-        return self.ipyChatBubbleBoxStarLen
-    def GetChatBubbleBoxStarByIndex(self, index):
-        self.CheckLoadData("ChatBubbleBoxStar")
-        return self.ipyChatBubbleBoxStarCache[index]
 
     def GetEmojiPackCount(self):
         self.CheckLoadData("EmojiPack")
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
index 93163c5..9c669d6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
@@ -596,9 +596,6 @@
     #根据物品效果使用{物品效果ID:call的py名}
     itemEffIdCallFuncDic = {
                             ChConfig.Def_Effect_UseItemGiveZhenQi:"Item_UseItemGiveZhenQi", # 使用道具给予真气
-                            ChConfig.Def_Effect_AddDienstgrad:"Item_AddDienstgrad", #道具获得称号
-                            ChConfig.Def_Effect_Face:"Item_Face",
-                            ChConfig.Def_Effect_FacePic:"Item_Face",
                             ChConfig.Def_Effect_ItemAddLV:"Item_AddLV", #升级道具
                             ChConfig.Def_Effect_GuajiAward:"Item_GuajiAward", #直接给挂机收益
                             ChConfig.Def_Effect_CleanGuilt:"Item_CleanGuilt", # 洗红名
@@ -611,7 +608,6 @@
                             ChConfig.Def_Effect_AddFBCnt:"Item_AddFBCnt", # 增加副本可进入次数
                             ChConfig.Def_Effect_AddKillBossCnt:"Item_AddKillBossCnt", # 增加BOSS可击杀次数
                             ChConfig.Def_Effect_AddMagicWeaponUpExp:"Item_AddMagicWeaponUpExp", # 增加法宝升星经验
-                            ChConfig.Def_Effect_ChatBubbleBox:"Item_ChatBubbleBox", # 激活聊天气泡框
                             ChConfig.Def_Effect_EmojiPack:"Item_EmojiPack",
                             ChConfig.Def_Effect_FamilyEmblem:"Item_FamilyEmblem",
                             ChConfig.Def_Effect_ItemGiveWeekPartyPoint:"Item_WeekPartyPoint", # 增加活动巡礼积分
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddDienstgrad.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddDienstgrad.py
deleted file mode 100644
index d7bee61..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddDienstgrad.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-#-------------------------------------------------------------------------------
-#
-##@package Item_AddDienstgrad
-#
-# @todo: 使用物品获得增加称号
-# @author xmnathan
-# @date 2014-11-05 18:00
-# @version 1.1
-#
-# 详细描述:
-# @change: "2014-11-06 09:50" xmnathan 添加获得称号物品效果值
-#---------------------------------------------------------------------
-"""Version = 2014-11-06 09:50"""
-#---------------------------------------------------------------------
-#导入
-import ChConfig
-import ItemCommon
-import PlayerDienstgrad
-#---------------------------------------------------------------------
-#全局变量
-
-## 使用物品获得玩家称号
-#  @param curPlayer
-#  @param curRoleItem
-#  @param tick
-#  @return None
-def UseItem(curPlayer, curRoleItem, tick):
-    useItemEff = curRoleItem.GetEffectByIndex(0)
-    curEffID = useItemEff.GetEffectID()
-    if curEffID != ChConfig.Def_Effect_AddDienstgrad:
-        return False
-    effectA1 = useItemEff.GetEffectValue(0) 
-    if effectA1 == 0:
-        return False
-    #效果值1的A值作为称号ID,添加称号
-    if not PlayerDienstgrad.PlayerAddDienstgrad(curPlayer, effectA1):
-        return False
-    #物品添加称号
-    ItemCommon.DelItem(curPlayer, curRoleItem, 1, True, ChConfig.ItemDel_AddDienstgrad)
-    return True
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_ChatBubbleBox.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_ChatBubbleBox.py
deleted file mode 100644
index ff2f1b6..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_ChatBubbleBox.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-##@package UseItem.Item_ChatBubbleBox
-#
-# @todo:激活聊天气泡框
-# @author hxp
-# @date 2018-11-01
-# @version 1.0
-#
-# 详细描述: 激活聊天气泡框
-#
-#-------------------------------------------------------------------------------
-#"""Version = 2018-11-01 21:30"""
-#-------------------------------------------------------------------------------
-
-import ItemCommon
-import PlayerChatBox
-import ChConfig
-
-def BatchUseItem(curPlayer, curRoleItem, tick, useCnt, exData):
-    ##批量使用物品
-    curEff = curRoleItem.GetEffectByIndex(0)
-    bubbleBoxID = curEff.GetEffectValue(0)
-    if not bubbleBoxID:
-        return
-    
-    if not PlayerChatBox.AddChatBox(curPlayer, bubbleBoxID):
-        return
-    
-    ItemCommon.DelItem(curPlayer, curRoleItem, useCnt, True, ChConfig.ItemDel_ChatBubbleBox)
-    return True, useCnt
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_Face.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_Face.py
deleted file mode 100644
index ea4b5d3..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_Face.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-##@package UseItem.Item_Face
-#
-# @todo:激活头像
-# @author hxp
-# @date 2024-09-12
-# @version 1.0
-#
-# 详细描述: 激活头像
-#
-#-------------------------------------------------------------------------------
-#"""Version = 2024-09-12 12:00"""
-#-------------------------------------------------------------------------------
-
-import ChConfig
-import ItemCommon
-import PlayerFace
-
-def UseItem(curPlayer, curRoleItem, tick):
-    useItemEff = curRoleItem.GetEffectByIndex(0)
-    curEffID = useItemEff.GetEffectID()
-    effectA1 = useItemEff.GetEffectValue(0) 
-    if effectA1 == 0:
-        return
-    if curEffID == ChConfig.Def_Effect_Face:
-        if not PlayerFace.AddFace(curPlayer, effectA1):
-            return
-    elif curEffID == ChConfig.Def_Effect_FacePic:
-        if not PlayerFace.AddFacePic(curPlayer, effectA1):
-            return
-    else:
-        return
-    ItemCommon.DelItem(curPlayer, curRoleItem, 1)
-    return True
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
index d8572d3..da96c9a 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -49,7 +49,6 @@
 import FBCommon
 import PlayerWishingWell
 import PlayerSuccess
-import PlayerDienstgrad
 import PlayerFreeGoods
 import PlayerCrossRealmPK
 import PlayerCrossChampionship
@@ -117,8 +116,6 @@
 import PlayerLove
 import GameObj
 import PlayerChangeJob
-import PlayerFace
-import PlayerChatBox
 import PlayerXiangong
 import PlayerGoldRush
 import PlayerActLoginNew
@@ -138,6 +135,7 @@
 import PlayerHero
 import PlayerOnline
 import TurnAttack
+import PlayerHJG
 import ObjPool
 
 import datetime
@@ -577,10 +575,6 @@
 #    Sync_AutoFightSetting(curPlayer)
     
     PlayerFamily.OnPlayerLogin(curPlayer, tick)
-    #改到 GameServerRefresh GameSever_PlayerInitOK后处理才能保证玩家已经在Gameserver注册
-    #PlayerDienstgrad.RefreshBillBoardDienstgrad(curPlayer)
-    # 称号
-    PlayerDienstgrad.Sync_AllDienstgradOnLogin(curPlayer)
     
     # 时装
     PlayerCoat.OnLogin_Coat(curPlayer)
@@ -746,8 +740,7 @@
         PyMongoMain.GetUserCtrlDB().OnPlayerLogin(curPlayer)
         PlayerHero.OnPlayerLogin(curPlayer)
         PlayerMail.OnPlayerLogin(curPlayer)
-        PlayerChatBox.OnPlayerLogin(curPlayer)
-        PlayerFace.OnPlayerLogin(curPlayer)
+        PlayerHJG.OnPlayerLogin(curPlayer)
         PlayerXiangong.OnPlayerLogin(curPlayer)
         PlayerGubao.OnPlayerLogin(curPlayer)
         PlayerShentong.OnPlayerLogin(curPlayer)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
index 8b8ae0a..d9a6fbc 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
@@ -21,7 +21,6 @@
 import base64
 import ChConfig
 import PyGameData
-import PlayerDienstgrad
 import IpyGameDataPY
 import PlayerHorse
 import PlayerPet
@@ -225,7 +224,6 @@
     PyGameData.g_crossRegPlayerAttrDict.pop(playerID, None)
     PyGameData.g_crossSyncTickDict.pop(playerID, None)
     PyGameData.g_crossPlayerDictChangeInfo.pop(playerID, None)
-    PyGameData.g_crossPlayerDienstgradChangeInfo.pop(playerID, None)
     PyGameData.g_crossPlayerItemsChangeInfo.pop(playerID, None)
     PyGameData.g_crossPlayerSkillsChangeInfo.pop(playerID, None)
     GameWorld.DebugLog("清除同步跨服数据的临时缓存", playerID)
@@ -296,16 +294,6 @@
 #    curItem2 = curPack.GetAt(2)
 #    curItem2.AssignItem(curSingleItem)
 #===============================================================================
-    
-def OnDienstgradChange(curPlayer, dienstgradID, state):
-    ## 称号变更
-    if not IsNeedProcessCrossPlayer(curPlayer):
-        return
-    playerID = curPlayer.GetPlayerID()
-    dienstgradStateDict = PyGameData.g_crossPlayerDienstgradChangeInfo.get(playerID, {})
-    dienstgradStateDict[dienstgradID] = state
-    PyGameData.g_crossPlayerDienstgradChangeInfo[playerID] = dienstgradStateDict
-    return
 
 def OnPlayerFightPowerChange(curPlayer):
     ## 玩家战力变更时
@@ -347,7 +335,6 @@
         data = CommFunc.WriteBYTE(data, MergeData_Player)
         data = __WriteSyncPlayerAttrData(curPlayer, data) # 玩家属性
         data = __WriteSyncPlayerDictData(curPlayer, data) # 字典
-        data = __WriteSyncPlayerDienstgradData(curPlayer, data) # 称号
         data = __WriteSyncPlayerItems(curPlayer, data)# 物品
         data = __WriteSyncPlayerSkills(curPlayer, data)# 技能
         
@@ -371,7 +358,6 @@
     
     pos = __ReadSyncPlayerAttrData(curPlayer, pdata, pos) # 玩家属性
     pos = __ReadSyncPlayerDictData(curPlayer, pdata, pos) # 字典
-    pos = __ReadSyncPlayerDienstgradData(curPlayer, pdata, pos) # 称号
     pos = __ReadSyncPlayerItems(curPlayer, pdata, pos)  # 物品
     pos = __ReadSyncPlayerSkills(curPlayer, pdata, pos)# 技能
     
@@ -461,39 +447,6 @@
         PlayerControl.NomalDictSetProperty(curPlayer, key, value, dType)
         GameWorld.DebugLog("    key=%s, value=%s, dType=%s" % (key, value, dType))
         
-    return pos
-
-def __WriteSyncPlayerDienstgradData(curPlayer, data):
-    ## 写入需要同步的玩家称号
-    playerID = curPlayer.GetPlayerID()
-    if playerID not in PyGameData.g_crossPlayerDienstgradChangeInfo:
-        return CommFunc.WriteBYTE(data, 0)
-    changeDienstgradDict = PyGameData.g_crossPlayerDienstgradChangeInfo.pop(playerID)
-    
-    count = len(changeDienstgradDict)
-    GameWorld.DebugLog("变更的玩家称号个数: %s" % count)
-    data = CommFunc.WriteBYTE(data, count)
-    for dienstgradID, state in changeDienstgradDict.items():
-        data = CommFunc.WriteDWORD(data, dienstgradID)
-        data = CommFunc.WriteBYTE(data, state)
-        GameWorld.DebugLog("    dienstgradID=%s, state=%s" % (dienstgradID, state))
-        
-    return data
-
-def __ReadSyncPlayerDienstgradData(curPlayer, pdata, pos):
-    ## 读取同步的玩家称号
-    pdata = base64.b64decode(pdata)
-    count, pos = CommFunc.ReadBYTE(pdata, pos)
-    GameWorld.DebugLog("变更的玩家称号个数: %s" % count)
-    for _ in xrange(count):
-        dienstgradID, pos = CommFunc.ReadDWORD(pdata, pos)
-        state, pos = CommFunc.ReadBYTE(pdata, pos)
-        GameWorld.DebugLog("    dienstgradID=%s, state=%s" % (dienstgradID, state))
-        if state:
-            PlayerDienstgrad.PlayerAddDienstgrad(curPlayer, dienstgradID, isRefreshAttr=False)
-        else:
-            PlayerDienstgrad.PlayerDelDienstgrad(curPlayer, dienstgradID, False)
-            
     return pos
 
 def __WriteSyncPlayerItems(curPlayer, data):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameServerRefresh.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameServerRefresh.py
index 9834fa0..cae2a59 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameServerRefresh.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameServerRefresh.py
@@ -110,9 +110,6 @@
         PlayerEventCounter.PlayerOnYear(curPlayer)
         Set_PlayerGameServerInitOK_OnYear(curPlayer, 0)
         
-    #刷新排行榜称号
-    #PlayerDienstgrad.RefreshBillBoardDienstgrad(curPlayer)
-    
     GameWorld.Log('GameSever_PlayerInitOK' , curPlayer.GetID())
     ChPlayer.DoPlayerRealLoginOK(curPlayer, tick)
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerChatBox.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerChatBox.py
index 244d7f0..5142697 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerChatBox.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerChatBox.py
@@ -16,7 +16,7 @@
 #-------------------------------------------------------------------------------
 
 import GameWorld
-import ShareDefine
+import PlayerHJG
 import PlayerControl
 import IPY_GameWorld
 import ChPyNetSendPack
@@ -24,25 +24,23 @@
 import NetPackCommon
 import ItemCommon
 import ChConfig
+import ObjPool
 
 import time
 
 def OnPlayerLogin(curPlayer):
     SyncChatBoxInfo(curPlayer)
-    SyncEmojiPackInfo(curPlayer)
+    #SyncEmojiPackInfo(curPlayer)
     return
 
 def OnMinute(curPlayer):
     curTime = int(time.time())
     delBoxList = []
     ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in range(ipyDataMgr.GetChatBubbleBoxCount()):
-        ipyData = ipyDataMgr.GetChatBubbleBoxByIndex(index)
+    for index in range(ipyDataMgr.GetChatBoxCount()):
+        ipyData = ipyDataMgr.GetChatBoxByIndex(index)
         boxID = ipyData.GetBoxID()
-        if ipyData.GetUnlockDefault():
-            # 默认激活的不处理
-            continue
-        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID):
+        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID):
             # 未激活的不处理
             continue
         endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxEndTime % boxID)
@@ -55,38 +53,51 @@
     if delBoxList:
         RefreshBoxAttr(curPlayer)
         
-    # 表情包
-    for index in range(ipyDataMgr.GetEmojiPackCount()):
-        ipyData = ipyDataMgr.GetEmojiPackByIndex(index)
-        packID = ipyData.GetEmojiPackID()
-        if ipyData.GetUnlockDefault():
-            # 默认激活的不处理
-            continue
-        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_EmojiPackState, packID):
-            # 未激活的不处理
-            continue
-        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_EmojiPackEndTime % packID)
-        if not endTime or endTime > curTime:
-            # 永久或未过期
-            continue
-        DelEmojiPack(curPlayer, packID, "EmojiPackTimeout")
+#    # 表情包
+#    for index in range(ipyDataMgr.GetEmojiPackCount()):
+#        ipyData = ipyDataMgr.GetEmojiPackByIndex(index)
+#        packID = ipyData.GetEmojiPackID()
+#        if ipyData.GetUnlockDefault():
+#            # 默认激活的不处理
+#            continue
+#        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_EmojiPackState, packID):
+#            # 未激活的不处理
+#            continue
+#        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_EmojiPackEndTime % packID)
+#        if not endTime or endTime > curTime:
+#            # 永久或未过期
+#            continue
+#        DelEmojiPack(curPlayer, packID, "EmojiPackTimeout")
         
     return
 
-def AddChatBox(curPlayer, boxID, setExpireTimes=None):
+def AddChatBox(curPlayer, boxID, setExpireTimes=None, isFree=False):
     if boxID <= 0:
         return
     playerID = curPlayer.GetPlayerID()
-    ipyData = IpyGameDataPY.GetIpyGameData("ChatBubbleBox", boxID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
     if not ipyData:
         return
-    if ipyData.GetUnlockDefault():
-        GameWorld.DebugLog("气泡框默认解锁的不用添加: boxID=%s" % (boxID), playerID)
+    if ipyData.GetUnlockWay() != 2:
+        GameWorld.DebugLog("非道具激活的不用添加: boxID=%s" % (boxID), playerID)
         return
+    if not isFree:
+        itemID = ipyData.GetUnlockValue()
+        itemCount = ipyData.GetUnlockNeedCnt()
+        if not itemID or not itemCount:
+            return
+        needItemList = [[itemID, itemCount]]
+        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+        lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+        if lackItemDict:
+            GameWorld.DebugLog("激活所需物品不足! boxID=%s,lackItemDict=%s" % (boxID, lackItemDict), playerID)
+            return
+        ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "AddChatBox")
+        
     ipyExpireSeconds = ipyData.GetExpireMinutes() * 60
     
     curTime = int(time.time())
-    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID)
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID)
     endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxEndTime % boxID)
     GameWorld.Log("添加气泡框: boxID=%s,setExpireTimes=%s,state=%s,endTime=%s,ipyExpireSeconds=%s,curTime=%s" 
                   % (boxID, setExpireTimes, state, endTime, ipyExpireSeconds, curTime), playerID)
@@ -95,23 +106,23 @@
     # 指定时长的,如GM指定
     if setExpireTimes >= 0:
         updEndTime = curTime + setExpireTimes
-        GameWorld.Log("    指定气泡框时长: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
+        GameWorld.Log("    指定时长: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
         
     # 永久
     elif ipyExpireSeconds == 0:
         updEndTime = 0
-        GameWorld.Log("    添加永久气泡框: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
+        GameWorld.Log("    永久时长: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
         
     else:
         # 未过期
         if endTime > curTime:
             updEndTime = endTime + ipyExpireSeconds
-            GameWorld.Log("    累加气泡框时长: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
+            GameWorld.Log("    累加时长: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
         else:
             updEndTime = curTime + ipyExpireSeconds
-            GameWorld.Log("    重新激活气泡框: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
+            GameWorld.Log("    重新激活: boxID=%s,updEndTime=%s" % (boxID, updEndTime), playerID)
             
-    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID, 1)
+    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID, 1)
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxEndTime % boxID, updEndTime)
     RefreshBoxAttr(curPlayer)
     SyncChatBoxInfo(curPlayer, [boxID])
@@ -119,19 +130,19 @@
 
 def DelChatBox(curPlayer, boxID, isRefreshAttr=True, notifyMail=""):
     playerID = curPlayer.GetPlayerID()
-    ipyData = IpyGameDataPY.GetIpyGameData("ChatBubbleBox", boxID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
     if not ipyData:
         return
-    if ipyData.GetUnlockDefault():
+    if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID):
         return
-    GameWorld.Log("删除玩家聊天气泡框: boxID=%s,notifyMail=%s" % (boxID, notifyMail), playerID)
-    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID, 0)
+    GameWorld.Log("删除气泡框: boxID=%s,notifyMail=%s" % (boxID, notifyMail), playerID)
+    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID, 0)
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxEndTime % boxID, 0)
     # 星级不重置,重新激活后再次生效
     
-    if PlayerControl.GetChatBubbleBox(curPlayer) == boxID:
+    if PlayerControl.GetChatBox(curPlayer) == boxID:
         canUseID = GetCanUseBoxID(curPlayer)
-        PlayerControl.SetChatBubbleBox(curPlayer, canUseID)
+        PlayerControl.SetChatBox(curPlayer, canUseID)
         GameWorld.DebugLog("玩家聊天气泡框被删除,重新设置可用ID=%s" % canUseID, playerID)
         
     if isRefreshAttr:
@@ -144,8 +155,8 @@
 def GetCanUseBoxID(curPlayer):
     ## 获取一个可用的气泡框
     ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in range(ipyDataMgr.GetChatBubbleBoxCount())[::-1]:
-        ipyData = ipyDataMgr.GetChatBubbleBoxByIndex(index)
+    for index in range(ipyDataMgr.GetChatBoxCount())[::-1]:
+        ipyData = ipyDataMgr.GetChatBoxByIndex(index)
         boxID = ipyData.GetBoxID()
         if IsBoxCanUse(curPlayer, boxID, ipyData):
             return boxID
@@ -153,141 +164,92 @@
 
 def IsBoxCanUse(curPlayer, boxID, ipyData=None):
     ## 气泡框是否可用
-    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID)
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID)
     if state:
         return True
     
     if not ipyData:
-        ipyData = IpyGameDataPY.GetIpyGameData("ChatBubbleBox", boxID)
+        ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
     if ipyData:
-        if ipyData.GetUnlockDefault():
-            return True
-        
-        needLV = ipyData.GetNeedLV()
-        if needLV and curPlayer.GetLV() < needLV:
-            #GameWorld.DebugLog("    等级不足,无法使用该气泡框!needLV=%s" % needLV, curPlayer.GetPlayerID())
-            return False
-        
-        if needLV:
+        unlockWay = ipyData.GetUnlockWay()
+        if unlockWay == 1: # 默认激活的
             return True
         
     return False
 
 def RefreshBoxAttr(curPlayer):
-    CalcBoxAttr(curPlayer)
-    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
+    PlayerHJG.RefreshHJGAttr(curPlayer)
     return
 
-def CalcBoxAttr(curPlayer):
-    
-    fightPowerEx = 0
-    allAttrList = [{} for i in range(4)]
-    
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in range(ipyDataMgr.GetChatBubbleBoxCount()):
-        ipyData = ipyDataMgr.GetChatBubbleBoxByIndex(index)
-        boxID = ipyData.GetBoxID()
-        if not IsBoxCanUse(curPlayer, boxID, ipyData):
-            continue
-        
-        fightPowerEx += ipyData.GetLightFightPower()
-        # 激活属性
-        lightAttrType = ipyData.GetLightAttrType()
-        lightAttrValue = ipyData.GetLightAttrValue()
-        for i, attrID in enumerate(lightAttrType):
-            attrValue = lightAttrValue[i]
-            PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
-        
-        # 星级属性
-        boxStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxStar % boxID)
-        starIpyData = IpyGameDataPY.GetIpyGameDataNotLog("ChatBubbleBoxStar", boxID, boxStar)
-        if starIpyData:
-            starAttrType = starIpyData.GetStarAttrType()
-            starAttrValue = starIpyData.GetStarAttrValue()
-            for i, attrID in enumerate(starAttrType):
-                attrValue = starAttrValue[i]
-                PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
-                
-    # 保存计算值
-    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_ChatBox, allAttrList)
-    PlayerControl.SetMFPExFightPower(curPlayer, ShareDefine.Def_MFPType_ChatBox, fightPowerEx)
-    return
-
-#// A2 30 设置聊天气泡框 #tagCMSetChatBubbleBox
-#
-#struct    tagCMSetChatBubbleBox
-#{
-#    tagHead         Head;
-#    BYTE        BubbleBoxType;    //气泡框类型
-#};
-def OnSetChatBubbleBox(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    useBoxID = clientData.BubbleBoxType
+def OnUseChatBox(curPlayer, useBoxID):
     playerID = curPlayer.GetPlayerID()
     if not IsBoxCanUse(curPlayer, useBoxID):
         GameWorld.DebugLog("聊天气泡框不可用,无法设置! useBoxID=%s" % useBoxID, playerID)    
         return
     GameWorld.DebugLog("设置使用的聊天气泡框ID: useBoxID=%s" % useBoxID, playerID)    
-    PlayerControl.SetChatBubbleBox(curPlayer, useBoxID)
+    PlayerControl.SetChatBox(curPlayer, useBoxID)
     return
 
-#// A2 36 聊天气泡框升星 #tagCMChatBubbleBoxStarUP
-#
-#struct    tagCMChatBubbleBoxStarUP
-#{
-#    tagHead         Head;
-#    WORD        BoxID;    //气泡ID
-#};
-def OnChatBubbleBoxStarUP(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+def OnChatBoxStarUP(curPlayer, boxID):
     playerID = curPlayer.GetPlayerID()
-    boxID = clientData.BoxID
-    
     if not IsBoxCanUse(curPlayer, boxID):
         GameWorld.DebugLog("聊天气泡框不可用! boxID=%s" % (boxID), playerID)
         return
-    
-    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxStar % boxID)        
-    nextStar = curStar + 1
-    nextIpyData = IpyGameDataPY.GetIpyGameData("ChatBubbleBoxStar", boxID, nextStar)
-    if not nextIpyData:
-        GameWorld.DebugLog("不存在该气泡框星级! boxID=%s,nextStar=%s" % (boxID, nextStar), playerID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
+    if not ipyData:
         return
-    needItemList = nextIpyData.GetStarUpNeedItemList()
-    if not needItemList:
+    starMax = ipyData.GetStarMax()
+    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxStar % boxID)
+    if curStar >= starMax:
+        GameWorld.DebugLog("星级已满! boxID=%s,curStar=%s >= %s" % (boxID, curStar, starMax), playerID)
         return
+    if ipyData.GetUnlockWay() != 2:
+        return
+    itemID = ipyData.GetUnlockValue()
+    itemCount = ipyData.GetUnlockNeedCnt()
+    if not itemID or not itemCount:
+        return
+    needItemList = [[itemID, itemCount]]
     itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
     lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
     if lackItemDict:
-        GameWorld.DebugLog("气泡框升星所需物品不足! boxID=%s,nextStar=%s,needItemList=%s,lackItemDict=%s" 
-                           % (boxID, nextStar, needItemList, lackItemDict), playerID)
+        GameWorld.DebugLog("升星所需物品不足! boxID=%s,lackItemDict=%s" % (boxID, lackItemDict), playerID)
         return
     ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "ChatBoxStarUP")
     
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxStar % boxID, nextStar)
-    
-    GameWorld.DebugLog("气泡框升星! boxID=%s,curStar=%s,nextStar=%s" % (boxID, curStar, nextStar), playerID)
-    
+    nextStar = curStar + 1
+    GameWorld.DebugLog("升星! boxID=%s,nextStar=%s" % (boxID, nextStar), playerID)
+    SetChatBoxStar(curPlayer, boxID, nextStar)
+    return
+
+def SetChatBoxStar(curPlayer, boxID, setStar):
+    if not IsBoxCanUse(curPlayer, boxID):
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("ChatBox", boxID)
+    if not ipyData:
+        return
+    setStar = min(setStar, ipyData.GetStarMax())
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ChatBoxStar % boxID, setStar)
     RefreshBoxAttr(curPlayer)
     SyncChatBoxInfo(curPlayer, [boxID])
-    return
+    return True
 
 def SyncChatBoxInfo(curPlayer, boxIDList=None):
     if boxIDList == None:
         syncIDList = []
         ipyDataMgr = IpyGameDataPY.IPY_Data()
-        for index in range(ipyDataMgr.GetChatBubbleBoxCount()):
-            ipyData = ipyDataMgr.GetChatBubbleBoxByIndex(index)
+        for index in range(ipyDataMgr.GetChatBoxCount()):
+            ipyData = ipyDataMgr.GetChatBoxByIndex(index)
             syncIDList.append(ipyData.GetBoxID())
     else:
         syncIDList = boxIDList
         
     boxList = []
     for boxID in syncIDList:
-        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBubbleBoxState, boxID)
+        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ChatBoxState, boxID)
         if not state and boxIDList == None:
             continue
-        box = ChPyNetSendPack.tagMCChatBubbleBox()
+        box = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCChatBox)
         box.BoxID = boxID
         box.State = state
         box.EndTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxEndTime % boxID)
@@ -297,7 +259,7 @@
     if not boxList:
         return
     
-    clientPack = ChPyNetSendPack.tagMCChatBubbleBoxState()
+    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCChatBoxInfo)
     clientPack.BoxList = boxList
     clientPack.Count = len(clientPack.BoxList)
     NetPackCommon.SendFakePack(curPlayer, clientPack)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index fd02f54..f2e7c54 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -4406,6 +4406,10 @@
     wave = value % 100
     return chapterID, levelNum, wave
 
+## 获取佩戴的称号ID
+def GetTitleID(curPlayer): return curPlayer.GetExAttr3()
+def SetTitleID(curPlayer, titleID): curPlayer.SetExAttr3(titleID, False, False)
+
 ## 协助目标玩家ID
 def GetAssistTagPlayerID(curPlayer): return 0
 
@@ -4414,12 +4418,9 @@
 def SetTeamCheckState(curPlayer, checkState): return
 ## 副本功能线路ID, 这里做db存储,防止在合并地图副本中掉线重上时前端无法加载正确的场景资源,登录加载场景时机为0102包
 def SetFBFuncLineID(curPlayer, mapID, funcLineID):
-    value = mapID * 1000 + funcLineID
-    if value != curPlayer.GetExAttr3():
-        curPlayer.SetExAttr3(value, False, True)
     return
-def GetFBFuncMapID(curPlayer): return curPlayer.GetExAttr3() / 1000
-def GetFBFuncLineID(curPlayer): return curPlayer.GetExAttr3() % 1000
+def GetFBFuncMapID(curPlayer): return 0
+def GetFBFuncLineID(curPlayer): return 0
 
 ## 跨服状态所在地图ID: 0-非跨服状态,非0-跨服状态对应的地图ID
 def GetCrossMapID(curPlayer): return curPlayer.GetExAttr5()
@@ -4449,8 +4450,8 @@
 def SetVIPLVUpTime(curPlayer, lvUpTime): return
 
 ##聊天气泡框
-def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
-def SetChatBubbleBox(curPlayer, value): return curPlayer.SetExAttr10(value, False, True)
+def GetChatBox(curPlayer): return curPlayer.GetExAttr10()
+def SetChatBox(curPlayer, value): return curPlayer.SetExAttr10(value, False, True)
 
 ##游戏充值支付代币
 def GetPayCoinTotal(curPlayer): return GetPayCoin(curPlayer) + GetPlayerCurrency(curPlayer, ShareDefine.TYPE_Price_PayCoinDay)
@@ -4462,11 +4463,6 @@
     if payCoinDay > 0:
         PayMoney(curPlayer, ShareDefine.TYPE_Price_PayCoin, payCoinDay, "PayCoinOnDay")
     return
-
-## 获取佩戴的称号ID
-def GetTitleID(curPlayer):
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    return curDienstgradMgr.GetCurGradID()
 
 ##伴侣
 def GetCoupleID(curPlayer):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerDienstgrad.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerDienstgrad.py
deleted file mode 100644
index f1bdd07..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerDienstgrad.py
+++ /dev/null
@@ -1,687 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#
-#
-##@package PlayerDienstgrad.py
-#
-# @todo: 玩家称号管理
-# @author: alee
-# @date: 2017-07-26 22:00
-# @version 1.0
-# 详细描述:
-# @change: 2017-10-18 21:00 alee 策划需求去除点亮称号逻辑
-#------------------------------------------------------------------------------ 
-"""Version = 2017-07-26 22:00"""
-#------------------------------------------------------------------------------ 
-
-#导入
-import GameWorld
-import PlayerControl
-import IPY_GameWorld
-import ChConfig
-import ReadChConfig
-import IpyGameDataPY
-import SkillCommon
-import SkillShell
-import PassiveBuffEffMng
-import DataRecordPack
-import CrossPlayerData
-import GameFuncComm
-import ShareDefine
-import ChPyNetSendPack
-import NetPackCommon
-import ItemCommon
-
-import time
-#-------------------------------------------------------------
-#####通过Player对象接口#####
-
-
-## 查找玩家指定称号
-#  @param curPlayer
-#  @param dienstgradID 称号ID
-#  @return 称号实例
-def PlayerGetDienstgrad(curPlayer, dienstgradID):    
-    if curPlayer == None:
-        #玩家不在线
-        return None
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curDienstgrad = curDienstgradMgr.GetDienstgrad(dienstgradID)
-    return curDienstgrad
-
-
-def GetDienstgradData(dienstgradID):
-    return IpyGameDataPY.GetIpyGameData('Dienstgrad', dienstgradID)
-
-def PlayerDelAddDienstgrad(curPlayer, delDienstgradIDList, addDienstgradIDList):
-    ## 玩家删除称号的同时,增加称号,一般用于称号互斥的增删变更同步处理
-    if not delDienstgradIDList and not addDienstgradIDList:
-        return
-    
-    isRefresh = False
-    for dienstgradID in delDienstgradIDList:
-        if PlayerDelDienstgrad(curPlayer, dienstgradID, isRefreshAttr=False):
-            isRefresh = True
-        
-    for dienstgradID in addDienstgradIDList:
-        if PlayerAddDienstgrad(curPlayer, dienstgradID, isDelRepeat=False, isRefreshAttr=False):
-            isRefresh = True
-        
-    #重新刷新角色属性
-    if isRefresh:
-        CalcAllDienstgradAttr(curPlayer)
-        playerControl = PlayerControl.PlayerControl(curPlayer)
-        playerControl.RefreshPlayerAttrState()
-    return isRefresh
-
-## 添加玩家称号
-#  @param curPlayer
-#  @param dienstgradID 称号ID
-#  @param isDelRepeat 是否删除重复称号
-#  @return 是否添加成功
-def PlayerAddDienstgrad(curPlayer, dienstgradID, isDelRepeat=True, isRefreshAttr=True, expireTime=0):
-
-    if dienstgradID <= 0:
-        return False
-    
-    #查系统表数据
-    curDienstgradData = GetDienstgradData(dienstgradID)
-    if curDienstgradData == None:
-        return False
-    
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    
-    #curOldGradID = curDienstgradMgr.GetCurGradID()
-    
-    #重复添加称号, 限时的需要删除重设刷新时间
-    curDienstgrad = curDienstgradMgr.GetDienstgrad(dienstgradID)
-    if curDienstgrad:
-        if isDelRepeat:
-            curDienstgradMgr.DeleteDienstgrad(dienstgradID)
-        else:
-            return True
-        
-        
-    #检查互斥的称号类型
-#    curType = curDienstgradData.GetType()
-#    ExcludeDienstgradType = ReadChConfig.GetEvalChConfig("ExcludeDienstgradType")
-#    if curType in ExcludeDienstgradType:
-#        #互斥的称号类型 需要删掉同类型称号
-#        curTypeIDList = IpyGameDataPY.DienstgradData.GetTypeIDList(curType)
-#        for id in curTypeIDList:
-#            if id == dienstgradID:
-#                continue
-#            curDienstgrad = curDienstgradMgr.GetDienstgrad(id)
-#            if curDienstgrad == None:
-#                #玩家称号不存在
-#                continue
-#            #如果当前装备称号被删,需要广播
-#            if curOldGradID == id:
-#                PlayerTakeOffDienstgrad(curPlayer)
-#            
-#            curDienstgradMgr.DeleteDienstgrad(id)
-#            #通知称号删除
-#            curDienstgradMgr.Sync_PlayerDelDienstgrad(id)
-    
-    #添加称号
-    curDienstgrad = curDienstgradMgr.AddDienstgrad(dienstgradID) 
-    
-    if expireTime != 0:
-        curDienstgrad.SetExpireTime(expireTime)
-    curDienstgradMgr.Sync_PlayerGetDienstgrad(dienstgradID)
-    
-    # 学习技能
-    skillList = curDienstgradData.GetSkills()
-
-    for skillID in skillList:
-        __GiveSkill(curPlayer, skillID)
-        
-    CrossPlayerData.OnDienstgradChange(curPlayer, dienstgradID, 1)
-    if dienstgradID == IpyGameDataPY.GetFuncCfg("TitleAddPoint"):
-        __DoTitleAddPoint(curPlayer)
-    
-    #重新刷新角色属性
-    if isRefreshAttr:
-        CalcAllDienstgradAttr(curPlayer)
-        playerControl = PlayerControl.PlayerControl(curPlayer)
-        playerControl.RefreshPlayerAttrState()
-    return True
-
-
-# 获得称号加点
-def __DoTitleAddPoint(curPlayer):
-    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_AddPoint):
-        # 未开启前不可加点,因为DoAddPointOpen会一次性补齐,避免意外情况多加了点数
-        return
-    addPointDict = IpyGameDataPY.GetFuncEvalCfg("LVUPAddPoint", 1, {})
-    titleAddPoint = PlayerControl.GetTitleAddExtraPoint(curPlayer)
-    if titleAddPoint <=0:
-        return
-    curLV = curPlayer.GetLV()
-    addFreePoint = 0
-    for rangLVs, point in addPointDict.items():
-        if curLV < rangLVs[0]:
-            continue
-        addFreePoint += titleAddPoint * (min(curLV, rangLVs[1]) - rangLVs[0] + 1)
-    freePoint = curPlayer.GetFreePoint()
-    updFreePoint = freePoint + addFreePoint
-    curPlayer.SetFreePoint(updFreePoint)
-    GameWorld.DebugLog("获得称号增加自由属性点: freePoint=%s,addFreePoint=%s,curLV=%s,updFreePoint=%s" 
-                       % (freePoint, addFreePoint, curLV, updFreePoint))
-    
-    return
-
-# 从称号获得技能
-def __GiveSkill(curPlayer, skillResID):
-    
-    skillData = GameWorld.GetGameData().FindSkillByType(skillResID, 1)
-    if skillData == None:
-        GameWorld.DebugLog("__GiveSkill() hasn't find skill(%s)" % skillResID)
-        return
-    if not SkillCommon.CheckSkillJob(curPlayer, skillData):
-        return
-    if not SkillShell.CheckLearnSkillCondition(curPlayer, skillData):
-        GameWorld.DebugLog("__GiveSkill() learn skill(%s) condition isn't enough" % skillResID)
-        return
-    skillManager = curPlayer.GetSkillManager()
-    if skillManager.FindSkillBySkillTypeID(skillResID):
-        GameWorld.DebugLog("__GiveSkill() have learned skill(%s)" % skillResID)
-        return
-
-    skillManager.LVUpSkillBySkillTypeID(skillResID)
-    
-    PassiveBuffEffMng.GetPassiveEffManager().RegistPassiveEff(curPlayer, skillResID)    
-    
-    PlayerControl.PlayerControl(curPlayer).RefreshSkillFightPowerEx(skillResID, 0)
-    return
-
-
-# 称号过期删除技能
-def __DelSkill(curPlayer, curDienstgradData):
-    # 学习技能
-    skillList = curDienstgradData.GetSkills()
-    isDel = False
-    for skillResID in skillList:
-        skillManager = curPlayer.GetSkillManager()
-        if not skillManager.FindSkillBySkillTypeID(skillResID):
-            continue
-    
-        skillManager.DeleteSkillBySkillTypeID(skillResID)
-        isDel = True
-        
-    if not isDel:
-        return
-    
-    # 重刷被动技能
-    PassiveBuffEffMng.GetPassiveEffManager().RegistPassiveEff(curPlayer)    
-    # 重刷技能战力
-    PlayerControl.PlayerControl(curPlayer).RefreshAllSkill()
-    return
-
-## 删除玩家称号
-#  @param curPlayer
-#  @param dienstgradID 称号ID
-#  @return None
-def PlayerDelDienstgrad(curPlayer, dienstgradID, isRefreshAttr=True, notifyMail=""):
-    if curPlayer == None:
-        #玩家不在线
-        return
-    
-    if dienstgradID <= 0:
-        return
-    
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curDienstgrad = curDienstgradMgr.GetDienstgrad(dienstgradID)
-    if curDienstgrad == None:
-        #玩家称号不存在
-        return
-    
-    #如果当前装备称号被删,需要广播
-    if curDienstgradMgr.GetCurGradID() == dienstgradID:
-        PlayerTakeOffDienstgrad(curPlayer)
-        
-    #===========================================================================
-    # if curDienstgradMgr.GetUseGradID() == dienstgradID:
-    #    UnUseDienstgrad(curPlayer)
-    #===========================================================================
-    
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % dienstgradID, 0)
-    curDienstgradMgr.DeleteDienstgrad(dienstgradID)
-    #通知称号删除
-    curDienstgradMgr.Sync_PlayerDelDienstgrad(dienstgradID)
-    
-    curDienstgradData = GetDienstgradData(dienstgradID)
-    if curDienstgradData:
-        # 删除对应技能
-        __DelSkill(curPlayer, curDienstgradData)
-    DataRecordPack.Cache_FightPowerChangeInfo(curPlayer, ChConfig.PowerDownType_Title, {'dienstgradID':dienstgradID})
-    
-    CrossPlayerData.OnDienstgradChange(curPlayer, dienstgradID, 0)
-    #重新刷新角色属性
-    if isRefreshAttr:
-        CalcAllDienstgradAttr(curPlayer)
-        playerControl = PlayerControl.PlayerControl(curPlayer)
-        playerControl.RefreshPlayerAttrState()
-        
-    if notifyMail != "":
-        PlayerControl.SendMailByKey(notifyMail, [curPlayer.GetPlayerID()], [], [dienstgradID, dienstgradID])
-        
-    return True
-
-## 穿着玩家称号
-#  @param curPlayer
-#  @param dienstgradID 称号ID
-#  @return None   
-def PlayerFitOnDienstgrad(curPlayer, dienstgradID):
-
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curDienstgrad = curDienstgradMgr.GetDienstgrad(dienstgradID)
-    if curDienstgrad == None:
-        #玩家称号不存在
-        return
-    curOldGradID = curDienstgradMgr.GetCurGradID()
-    if curOldGradID == dienstgradID:
-        #已装备该称号
-        return
-    curDienstgradMgr.SetCurGradID(dienstgradID)
-    curDienstgradMgr.Notify_PlayerChangeDienstgrad(dienstgradID)
-
-    return
-
-## 卸下玩家称号
-#  @param curPlayer
-#  @return None
-def PlayerTakeOffDienstgrad(curPlayer):
-
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curOldGradID = curDienstgradMgr.GetCurGradID()
-    if curOldGradID == 0:
-        return
-    curDienstgradMgr.SetCurGradID(0)
-    curDienstgradMgr.Notify_PlayerChangeDienstgrad(0)
-
-    return
-
-## 不使用(佩戴)称号,用于激活属性,不显示场景中
-#  @param curPlayer
-#  @return None
-def UnUseDienstgrad(curPlayer):
-
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curOldGradID = curDienstgradMgr.GetUseGradID()
-    if curOldGradID == 0:
-        return False
-    curDienstgradMgr.SetUseGradID(0)
-
-    return True
-    
-    
-## 使用(佩戴)称号,用于激活属性, 不显示场景中
-#  @param curPlayer
-#  @param dienstgradID 称号ID
-#  @return None   
-def UseDienstgrad(curPlayer, dienstgradID):
-
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curDienstgrad = curDienstgradMgr.GetDienstgrad(dienstgradID)
-    if curDienstgrad == None:
-        #玩家称号不存在
-        return False
-    curOldGradID = curDienstgradMgr.GetUseGradID()
-    if curOldGradID == dienstgradID:
-        #已装备该称号
-        return False
-    curDienstgradMgr.SetUseGradID(dienstgradID)
-
-    return True
-    
-#-------------------------------------------------------------
-#####通过index玩家索引接口#####
-
-## 查找玩家指定称号
-#  @param index 玩家索引
-#  @param dienstgradID 称号ID
-#  @return 称号实例
-def GetDienstgrad(index, dienstgradID):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    return PlayerGetDienstgrad(curPlayer, dienstgradID)
-
-## 添加玩家称号
-#  @param index 玩家索引
-#  @param dienstgradID 称号ID
-#  @return 是否添加成功
-def AddDienstgrad(index, dienstgradID):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    return PlayerAddDienstgrad(curPlayer, dienstgradID) 
-
-## 删除玩家称号
-#  @param index 玩家索引
-#  @param dienstgradID 称号ID
-#  @return None
-def DelDienstgrad(index, dienstgradID):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    PlayerDelDienstgrad(curPlayer, dienstgradID)
-    
-    
-## 穿着玩家称号
-#  @param index 玩家索引
-#  @param dienstgradID 称号ID
-#  @return None   
-def FitOnDienstgrad(index, dienstgradID):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    PlayerFitOnDienstgrad(curPlayer, dienstgradID)
-
-## 卸下玩家称号
-#  @param index 玩家索引
-#  @return None
-def TakeOffDienstgrad(index):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    PlayerTakeOffDienstgrad(curPlayer)
-    return
-
-#-------------------------------------------------------------
-#####封包处理#####
-
-##//03 35 主角头衔刷新#tagCPlayerDienstgradRefresh
-#  @param index 玩家索引
-#  @param tick
-#  @return None      
-def OnCPlayerDienstgradRefresh(index, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    if curPlayer == None:
-        #玩家不在线
-        return
-    Sync_AllDienstgradOnLogin(curPlayer)
-    return
-
-def Sync_AllDienstgradOnLogin(curPlayer):
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curDienstgradMgr.Sync_AllDienstgrad()
-    curDienstgradMgr.Notify_PlayerChangeDienstgrad(curDienstgradMgr.GetCurGradID())
-    SyncTitleStarInfo(curPlayer)
-    return
-
-#===============================================================================
-# //B2 01 使用称号(有属性不显示场景中) #tagPyCMUseDienstgrad
-# 
-# struct    tagPyCMUseDienstgrad
-# {
-#    tagHead        Head;
-#    DWORD        GradID;        //头衔ID
-#    BYTE        State;        //使用状态 0取消使用 1使用 注意0307包为穿戴场景中显示
-# };
-#===============================================================================
-def UseDienstgradPack(index, clientData, tick):
-
-    #===========================================================================
-    # curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    # curGradID = clientData.GradID
-    # curGradState = clientData.State
-    # 
-    # result = False
-    # if curGradID == 0:
-    #    result = UnUseDienstgrad(curPlayer)
-    # else:
-    #    if curGradState:
-    #        result = UseDienstgrad(curPlayer, curGradID)
-    #    else:
-    #        result = UnUseDienstgrad(curPlayer)
-    #        
-    # if result:
-    #    CalcAllDienstgradAttr(curPlayer)
-    #    playerControl = PlayerControl.PlayerControl(curPlayer)
-    #    playerControl.RefreshPlayerAttrState()
-    #===========================================================================
-    return
-
-
-##//03 37 主角装卸头衔#tagCPlayerChangeDienstgrad
-#  @param index 玩家索引
-#  @param tick
-#  @return None    
-def OnCPlayerChangeDienstgrad(index, tick):   
-    sendPack = IPY_GameWorld.IPY_CPlayerChangeDienstgrad()
-    #//头衔ID
-    curGradID = sendPack.GetGradID()
-    #//装备状态 0未装备1已装备
-    curGradState = sendPack.GetState()
-    
-    if curGradID == 0:
-        TakeOffDienstgrad(index)
-        return
-    
-    if curGradState:
-        FitOnDienstgrad(index, curGradID)
-    else:
-        TakeOffDienstgrad(index)
-        
-#// A5 36 称号升星 #tagCMTitleStarUp
-#
-#struct    tagCMTitleStarUp
-#{
-#    tagHead        Head;
-#    DWORD        TitleID;        //称号ID
-#};
-def OnTitleStarUp(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    playerID = curPlayer.GetPlayerID()
-    titleID = clientData.TitleID
-    
-    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)        
-    nextStar = curStar + 1
-    nextIpyData = IpyGameDataPY.GetIpyGameData("TitleStarUp", titleID, nextStar)
-    if not nextIpyData:
-        GameWorld.DebugLog("称号不存在该星级,无法升星. titleID=%s,curStar=%s" % (titleID, curStar), playerID)
-        return
-    needItemList = nextIpyData.GetStarUpNeedItemList()
-    if not needItemList:
-        return
-    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
-    lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
-    if lackItemDict:
-        GameWorld.DebugLog("称号升星所需物品不足! titleID=%s,nextStar=%s,needItemList=%s,lackItemDict=%s" 
-                           % (titleID, nextStar, needItemList, lackItemDict), playerID)
-        return
-    
-    ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "TitleStarUp")
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % titleID, nextStar)
-    
-    GameWorld.DebugLog("称号升星. titleID=%s,curStar=%s,nextStar=%s" % (titleID, curStar, nextStar), playerID)
-    
-    CalcAllDienstgradAttr(curPlayer)
-    playerControl = PlayerControl.PlayerControl(curPlayer)
-    playerControl.RefreshPlayerAttrState()
-    
-    SyncTitleStarInfo(curPlayer, titleID)
-    return
-
-def GMSetTitleStar(curPlayer, titleID, setValue=None):
-    ## GM设置星级
-    
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curDienstgrad = curDienstgradMgr.GetDienstgrad(titleID)
-    if curDienstgrad == None:
-        return False, "The player has not activated the titleID(%s)" % titleID
-    
-    if setValue == None:
-        curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)
-        setStar = curStar + 1 # 没指定星级时默认升星
-    else:
-        setStar = setValue
-        
-    if setStar > 0:
-        if not IpyGameDataPY.GetIpyGameData("TitleStarUp", titleID, setStar):
-            return False, "The titleID(%s) star(%s) is not exist." % (titleID, setStar)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % titleID, setStar)
-    GameWorld.Log("GM设置称号星级: titleID=%s,setStar=%s" % (titleID, setStar), curPlayer.GetPlayerID())
-    
-    CalcAllDienstgradAttr(curPlayer)
-    playerControl = PlayerControl.PlayerControl(curPlayer)
-    playerControl.RefreshPlayerAttrState()
-    
-    SyncTitleStarInfo(curPlayer, titleID)
-    return True, ""
-
-#-------------------------------------------------------------
-## 获取已激活称号列表
-#  @param curPlayer
-#  @return 称号列表
-def GetDienstgradActiveInfo(curPlayer):
-    titleActiveList = []
-    gradCnt = curPlayer.GetDienstgradManager().GetCount()
-    for i in xrange(gradCnt):
-        curGradID = curPlayer.GetDienstgradManager().AtGradID(i)
-        if curGradID == 0:
-            continue
-
-        titleActiveList.append(curGradID)
-    return titleActiveList
-
-def GetDienstgradActiveTypeCountInfo(curPlayer):
-    activeTypeCountDict = {}
-    dienstgradManager = curPlayer.GetDienstgradManager()
-    gradCnt = dienstgradManager.GetCount()
-    for i in xrange(gradCnt):
-        curGradID = dienstgradManager.AtGradID(i)
-        if curGradID == 0:
-            continue
-        curDienstgradData = GetDienstgradData(curGradID)
-        if curDienstgradData == None:
-            continue
-        curType = curDienstgradData.GetType()
-        activeTypeCountDict[curType] = activeTypeCountDict.get(curType, 0) + 1
-    return activeTypeCountDict
-
-def CalcAllDienstgradAttr(curPlayer):
-    # 计算全部称号属性
-    allAttrList = [{} for i in range(4)]
-    allAttrListStar = [{} for _ in range(4)]
-    
-    initFPAdd = 0 #初始战力
-    dienstgradManager = curPlayer.GetDienstgradManager()
-    gradCnt = dienstgradManager.GetCount()
-    for i in xrange(gradCnt):
-        curGradID = dienstgradManager.AtGradID(i)
-        if curGradID == 0:
-            continue
-        curDienstgradData = GetDienstgradData(curGradID)
-        if curDienstgradData == None:
-            continue
-        
-        initFPAdd += curDienstgradData.GetInitFightPower()
-        attrTypeList = curDienstgradData.GetLightType()
-        attrValueList = curDienstgradData.GetLightAttribute()
-    
-        for i, attrID in enumerate(attrTypeList):
-            PlayerControl.CalcAttrDict_Type(attrID, attrValueList[i], allAttrList)
-            
-        curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % curGradID) 
-        starIpyData = IpyGameDataPY.GetIpyGameDataNotLog("TitleStarUp", curGradID, curStar)
-        if starIpyData:
-            starAttrType = starIpyData.GetStarAttrType()
-            starAttrValue = starIpyData.GetStarAttrValue()
-            for i, attrID in enumerate(starAttrType):
-                attrValue = starAttrValue[i]
-                PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrListStar)
-                
-    # 保存计算值
-    PlayerControl.SetMFPExFightPower(curPlayer, ShareDefine.Def_MFPType_Dienstgrad, initFPAdd)
-    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_Dienstgrad, allAttrList)
-    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_TitleStar, allAttrListStar)
-    return
-
-## 称号每日更新处理
-#  @param curPlayer
-#  @return None
-def OnDay(curPlayer):
-    return
-
-##检查称号超时
-#  @param curPlayer
-#  @return None
-def CheckDienstgradTimeout(curPlayer):
-    gradCnt = curPlayer.GetDienstgradManager().GetCount()
-    needClearList = []
-
-    #遍历所有称号,检查超时
-    for i in xrange(gradCnt):
-        curGrad = curPlayer.GetDienstgradManager().At(i)
-        if not curGrad:
-            continue
-        curGradID = curGrad.GetGradID()
-        if curGradID == 0:
-            continue
-        curDienstgradData = GetDienstgradData(curGradID)
-        if curDienstgradData == None:
-            continue
-        
-        curExpireTime = curGrad.GetExpireTime()     # 特殊指定有效期
-        if not curExpireTime:
-            curExpireTime = curDienstgradData.GetExpireTime()
-            # 0代表不限时
-            if curExpireTime == 0:
-                continue
-        
-        curCreateTime = curPlayer.GetDienstgradManager().AtCreateTime(i)
-        pastSeconds = GameWorld.GetPastSeconds(curCreateTime)
-        if pastSeconds < curExpireTime:
-            continue
-        needClearList.append(curGradID) #不在遍历过程中删除,先保存需要删除的称号
-    
-    #依次删除称号
-    for curGradID in needClearList:
-        PlayerDelDienstgrad(curPlayer, curGradID, notifyMail="TitleTimeout")
-    return
-
-#-------------------特殊处理称号逻辑-------------------
-
-##玩家第一次登陆给称号
-#  @param curPlayer
-#  @return None
-def GiveFirstLoginDienstgrad(curPlayer):
-    dienstgradIDDict = ReadChConfig.GetEvalChConfig('FirstLogin_GiveDienstgrad')
-    platFormName = GameWorld.GetPlayerPlatform(curPlayer)
-    dienstgradIDList = dienstgradIDDict.get(platFormName)
-    if not dienstgradIDList: #未配置的平台默认取key为0的内容
-        dienstgradIDList = dienstgradIDDict.get(0, [])
-        
-    for dienstgradID in dienstgradIDList:
-        PlayerAddDienstgrad(curPlayer, dienstgradID)
-        #PlayerFitOnDienstgrad(curPlayer, dienstgradID)
-    return
-
-def SyncTitleStarInfo(curPlayer, titleID=None):
-    force = False
-    if titleID > 0:
-        force = True
-        syncIDList = [titleID]
-    else:
-        syncIDList = []
-        ipyDataMgr = IpyGameDataPY.IPY_Data()
-        for index in range(ipyDataMgr.GetDienstgradCount()):
-            ipyData = ipyDataMgr.GetDienstgradByIndex(index)
-            syncIDList.append(ipyData.GetID())
-            
-    if not syncIDList:
-        return
-    
-    titleStarList = []
-    for titleID in syncIDList:
-        curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)
-        if not curStar and not force:
-            continue
-        starInfo = ChPyNetSendPack.tagMCTitleStar()
-        starInfo.Clear()
-        starInfo.TitleID = titleID
-        starInfo.Star = curStar
-        titleStarList.append(starInfo)
-        
-    if not titleStarList:
-        return
-    
-    clientPack = ChPyNetSendPack.tagMCTitleStarInfo()
-    clientPack.Clear()
-    clientPack.TitleStarList = titleStarList
-    clientPack.Count = len(clientPack.TitleStarList)
-    NetPackCommon.SendFakePack(curPlayer, clientPack)
-    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFace.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFace.py
index c93652b..e1c405f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFace.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFace.py
@@ -16,14 +16,16 @@
 #-------------------------------------------------------------------------------
 
 import GameWorld
-import ShareDefine
 import PlayerControl
 import IPY_GameWorld
 import ChPyNetSendPack
 import IpyGameDataPY
 import NetPackCommon
 import ItemCommon
+import PlayerHero
+import PlayerHJG
 import ChConfig
+import ObjPool
 
 import random
 import time
@@ -41,12 +43,6 @@
     for index in range(ipyDataMgr.GetPlayerFaceCount()):
         ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
         faceID = ipyData.GetFaceID()
-        if ipyData.GetUnlockDefault():
-            # 默认激活的不处理
-            continue
-        if ipyData.GetCustomPlayerID():
-            # 玩家定制的不处理
-            continue
         if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID):
             # 未激活的不处理
             continue
@@ -64,9 +60,6 @@
     for index in range(ipyDataMgr.GetPlayerFacePicCount()):
         ipyData = ipyDataMgr.GetPlayerFacePicByIndex(index)
         facePicID = ipyData.GetFacePicID()
-        if ipyData.GetUnlockDefault():
-            # 默认激活的不处理
-            continue
         if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID):
             # 未激活的不处理
             continue
@@ -81,19 +74,29 @@
         RefreshFacePicAttr(curPlayer)
     return
 
-def AddFace(curPlayer, faceID, setExpireTimes=None):
+def AddFace(curPlayer, faceID, setExpireTimes=None, isFree=False):
     if faceID <= 0:
         return
     playerID = curPlayer.GetPlayerID()
     ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
     if not ipyData:
         return
-    if ipyData.GetUnlockDefault():
-        GameWorld.DebugLog("默认解锁的头像不用添加: faceID=%s" % (faceID), playerID)
+    if ipyData.GetUnlockWay() != 2:
+        GameWorld.DebugLog("非道具激活的不用添加: faceID=%s" % (faceID), playerID)
         return
-    if ipyData.GetCustomPlayerID():
-        GameWorld.DebugLog("玩家定制的头像不用添加: faceID=%s" % (faceID), playerID)
-        return
+    if not isFree:
+        itemID = ipyData.GetUnlockValue()
+        itemCount = ipyData.GetUnlockNeedCnt()
+        if not itemID or not itemCount:
+            return
+        needItemList = [[itemID, itemCount]]
+        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+        lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+        if lackItemDict:
+            GameWorld.DebugLog("激活所需物品不足! faceID=%s,lackItemDict=%s" % (faceID, lackItemDict), playerID)
+            return
+        ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "AddFace")
+        
     ipyExpireSeconds = ipyData.GetExpireMinutes() * 60
     
     curTime = int(time.time())
@@ -133,9 +136,7 @@
     ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
     if not ipyData:
         return
-    if ipyData.GetUnlockDefault():
-        return
-    if ipyData.GetCustomPlayerID():
+    if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID):
         return
     GameWorld.Log("删除头像: faceID=%s,notifyMail=%s" % (faceID, notifyMail), playerID)
     GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID, 0)
@@ -162,32 +163,143 @@
     for index in range(ipyDataMgr.GetPlayerFaceCount()):
         ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
         faceID = ipyData.GetFaceID()
-        if not ipyData.GetUnlockDefault():
+        if ipyData.GetUnlockWay() != 1:
             continue
         defaultFaceIDList.append(faceID)
     return defaultFaceIDList
 
-def GetDefaultFacePicIDList():
-    defaultFacePicIDList = []
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in range(ipyDataMgr.GetPlayerFacePicCount()):
-        ipyData = ipyDataMgr.GetPlayerFacePicByIndex(index)
-        facePicID = ipyData.GetFacePicID()
-        if not ipyData.GetUnlockDefault():
-            continue
-        defaultFacePicIDList.append(facePicID)
-    return defaultFacePicIDList
+def IsFaceCanUse(curPlayer, faceID, ipyData=None):
+    ## 头像是否可用
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID)
+    if state:
+        return True
+    
+    if not ipyData:
+        ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
+    if ipyData:
+        unlockWay = ipyData.GetUnlockWay()
+        unlockValue = ipyData.GetUnlockValue()
+        if unlockWay == 1: # 默认激活的
+            return True
+        if unlockWay == 3: # 关联武将
+            heroID = unlockValue
+            return True if PlayerHero.GetHeroActivite(curPlayer, heroID) else False
+        
+    return False
 
-def AddFacePic(curPlayer, facePicID, setExpireTimes=None):
+def RefreshFaceAttr(curPlayer):
+    PlayerHJG.RefreshHJGAttr(curPlayer)
+    return
+
+def OnUseFace(curPlayer, faceID):
+    playerID = curPlayer.GetPlayerID()
+    if not IsFaceCanUse(curPlayer, faceID):
+        GameWorld.DebugLog("该头像不可用! faceID=%s" % (faceID), playerID)
+        return    
+    GameWorld.DebugLog("头像幻化! faceID=%s" % (faceID), playerID)
+    curPlayer.SetFace(faceID)
+    return
+
+def OnFaceStarUP(curPlayer, faceID):
+    playerID = curPlayer.GetPlayerID()
+    if not IsFaceCanUse(curPlayer, faceID):
+        GameWorld.DebugLog("该头像不可用! faceID=%s" % (faceID), playerID)
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
+    if not ipyData:
+        return
+    starMax = ipyData.GetStarMax()
+    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)
+    if curStar >= starMax:
+        GameWorld.DebugLog("头像星级已满! faceID=%s,curStar=%s >= %s" % (faceID, curStar, starMax), playerID)
+        return
+    if ipyData.GetUnlockWay() != 2:
+        return
+    itemID = ipyData.GetUnlockValue()
+    itemCount = ipyData.GetUnlockNeedCnt()
+    if not itemID or not itemCount:
+        return
+    needItemList = [[itemID, itemCount]]
+    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+    lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+    if lackItemDict:
+        GameWorld.DebugLog("头像升星所需物品不足! faceID=%s,lackItemDict=%s" % (faceID, lackItemDict), playerID)
+        return
+    ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "FaceStarUP")
+    
+    nextStar = curStar + 1
+    GameWorld.DebugLog("头像升星! faceID=%s,nextStar=%s" % (faceID, nextStar), playerID)
+    SetFaceStar(curPlayer, faceID, nextStar)
+    return
+
+def SetFaceStar(curPlayer, faceID, setStar):
+    if not IsFaceCanUse(curPlayer, faceID):
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
+    if not ipyData:
+        return
+    setStar = min(setStar, ipyData.GetStarMax())
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FaceStar % faceID, setStar)
+    RefreshFaceAttr(curPlayer)
+    SyncFaceInfo(curPlayer, [faceID])
+    return True
+
+def SyncFaceInfo(curPlayer, faceIDList=None):
+    if faceIDList == None:
+        syncIDList = []
+        ipyDataMgr = IpyGameDataPY.IPY_Data()
+        for index in range(ipyDataMgr.GetPlayerFaceCount()):
+            ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
+            syncIDList.append(ipyData.GetFaceID())
+    else:
+        syncIDList = faceIDList
+        
+    faceList = []
+    for faceID in syncIDList:
+        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID)
+        if not state and faceIDList == None:
+            continue
+        face = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagMCFace)
+        face.FaceID = faceID
+        face.State = state
+        face.EndTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceEndTime % faceID)
+        face.Star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)
+        faceList.append(face)
+        
+    if not faceList:
+        return
+    
+    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagMCFaceInfo)
+    clientPack.FaceList = faceList
+    clientPack.Count = len(clientPack.FaceList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+## ------------------------------------------------------------------------------------------------
+
+def AddFacePic(curPlayer, facePicID, setExpireTimes=None, isFree=False):
     if facePicID <= 0:
         return
     playerID = curPlayer.GetPlayerID()
     ipyData = IpyGameDataPY.GetIpyGameData("PlayerFacePic", facePicID)
     if not ipyData:
         return
-    if ipyData.GetUnlockDefault():
-        GameWorld.DebugLog("默认解锁的头像框不用添加: facePicID=%s" % (facePicID), playerID)
+    if ipyData.GetUnlockWay() != 2:
+        GameWorld.DebugLog("非道具激活的不用添加: facePicID=%s" % (facePicID), playerID)
         return
+    if not isFree:
+        itemID = ipyData.GetUnlockValue()
+        itemCount = ipyData.GetUnlockNeedCnt()
+        if not itemID or not itemCount:
+            return
+        needItemList = [[itemID, itemCount]]
+        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+        lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+        if lackItemDict:
+            GameWorld.DebugLog("激活所需物品不足! facePicID=%s,lackItemDict=%s" % (facePicID, lackItemDict), playerID)
+            return
+        ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "AddFacePic")
+        
     ipyExpireSeconds = ipyData.GetExpireMinutes() * 60
     
     curTime = int(time.time())
@@ -227,7 +339,7 @@
     ipyData = IpyGameDataPY.GetIpyGameData("PlayerFacePic", facePicID)
     if not ipyData:
         return
-    if ipyData.GetUnlockDefault():
+    if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID):
         return
     GameWorld.Log("删除头像框: facePicID=%s,notifyMail=%s" % (facePicID, notifyMail), playerID)
     GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID, 0)
@@ -247,21 +359,16 @@
         PlayerControl.SendMailByKey(notifyMail, [playerID], [], [facePicID])
     return True
 
-def IsFaceCanUse(curPlayer, faceID, ipyData=None):
-    ## 头像是否可用
-    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FaceState, faceID)
-    if state:
-        return True
-    
-    if not ipyData:
-        ipyData = IpyGameDataPY.GetIpyGameData("PlayerFace", faceID)
-    if ipyData:
-        if ipyData.GetUnlockDefault():
-            return True
-        if ipyData.GetCustomPlayerID() and ipyData.GetCustomPlayerID() == curPlayer.GetPlayerID():
-            return True
-        
-    return False
+def GetDefaultFacePicIDList():
+    defaultFacePicIDList = []
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetPlayerFacePicCount()):
+        ipyData = ipyDataMgr.GetPlayerFacePicByIndex(index)
+        facePicID = ipyData.GetFacePicID()
+        if ipyData.GetUnlockWay() != 1:
+            continue
+        defaultFacePicIDList.append(facePicID)
+    return defaultFacePicIDList
 
 def IsFacePicCanUse(curPlayer, facePicID, ipyData=None):
     ## 头像框是否可用
@@ -272,188 +379,18 @@
     if not ipyData:
         ipyData = IpyGameDataPY.GetIpyGameData("PlayerFacePic", facePicID)
     if ipyData:
-        if ipyData.GetUnlockDefault():
+        unlockWay = ipyData.GetUnlockWay()
+        if unlockWay == 1: # 默认激活的
             return True
         
     return False
 
-def RefreshFaceAttr(curPlayer):
-    CalcFaceAttr(curPlayer)
-    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
-    return
-
 def RefreshFacePicAttr(curPlayer):
-    CalcFacePicAttr(curPlayer)
-    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
+    PlayerHJG.RefreshHJGAttr(curPlayer)
     return
 
-def CalcFaceAttr(curPlayer):
-    ## 计算头像属性
-    
-    fightPowerEx = 0
-    allAttrList = [{} for i in range(4)]
-    
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in range(ipyDataMgr.GetPlayerFaceCount()):
-        ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
-        faceID = ipyData.GetFaceID()
-        if not IsFaceCanUse(curPlayer, faceID, ipyData):
-            continue
-                
-        fightPowerEx += ipyData.GetLightFightPower()
-        # 激活属性
-        lightAttrType = ipyData.GetLightAttrType()
-        lightAttrValue = ipyData.GetLightAttrValue()
-        for i, attrID in enumerate(lightAttrType):
-            attrValue = lightAttrValue[i]
-            PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
-        
-        # 星级属性
-        faceStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)
-        starIpyData = IpyGameDataPY.GetIpyGameDataNotLog("PlayerFaceStar", faceID, faceStar)
-        if starIpyData:
-            starAttrType = starIpyData.GetStarAttrType()
-            starAttrValue = starIpyData.GetStarAttrValue()
-            for i, attrID in enumerate(starAttrType):
-                attrValue = starAttrValue[i]
-                PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
-                
-    # 保存计算值
-    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_Face, allAttrList)
-    PlayerControl.SetMFPExFightPower(curPlayer, ShareDefine.Def_MFPType_Face, fightPowerEx)
-    return
-
-def CalcFacePicAttr(curPlayer):
-    ## 计算头像框属性
-    
-    fightPowerEx = 0
-    allAttrList = [{} for _ in range(4)]
-    
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in range(ipyDataMgr.GetPlayerFacePicCount()):
-        ipyData = ipyDataMgr.GetPlayerFacePicByIndex(index)
-        facePicID = ipyData.GetFacePicID()
-        if not IsFacePicCanUse(curPlayer, facePicID, ipyData):
-            continue
-                
-        fightPowerEx += ipyData.GetLightFightPower()
-        # 激活属性
-        lightAttrType = ipyData.GetLightAttrType()
-        lightAttrValue = ipyData.GetLightAttrValue()
-        for i, attrID in enumerate(lightAttrType):
-            attrValue = lightAttrValue[i]
-            PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
-        
-        # 星级属性
-        facePicStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % facePicID)
-        starIpyData = IpyGameDataPY.GetIpyGameDataNotLog("PlayerFacePicStar", facePicID, facePicStar)
-        if starIpyData:
-            starAttrType = starIpyData.GetStarAttrType()
-            starAttrValue = starIpyData.GetStarAttrValue()
-            for i, attrID in enumerate(starAttrType):
-                attrValue = starAttrValue[i]
-                PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
-                
-    # 保存计算值
-    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_FacePic, allAttrList)
-    PlayerControl.SetMFPExFightPower(curPlayer, ShareDefine.Def_MFPType_FacePic, fightPowerEx)
-    return
-
-#// B2 26 头像幻化 #tagCMFaceChange
-#
-#struct    tagCMFaceChange
-#{
-#    tagHead        Head;
-#    DWORD        FaceID;    // 幻化的ID
-#};
-def OnFaceChange(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+def OnUseFacePic(curPlayer, facePicID):
     playerID = curPlayer.GetPlayerID()
-    faceID = clientData.FaceID
-    
-    if not IsFaceCanUse(curPlayer, faceID):
-        GameWorld.DebugLog("该头像不可用! faceID=%s" % (faceID), playerID)
-        return    
-    GameWorld.DebugLog("头像幻化! faceID=%s" % (faceID), playerID)
-    curPlayer.SetFace(faceID)
-    return
-
-#// B2 27 头像升星 #tagCMFaceStarUP
-#
-#struct    tagCMFaceStarUP
-#{
-#    tagHead        Head;
-#    DWORD        FaceID;
-#};
-def OnFaceStarUP(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    playerID = curPlayer.GetPlayerID()
-    faceID = clientData.FaceID
-    
-    if not IsFaceCanUse(curPlayer, faceID):
-        GameWorld.DebugLog("该头像不可用! faceID=%s" % (faceID), playerID)
-        return
-    
-    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)        
-    nextStar = curStar + 1
-    nextIpyData = IpyGameDataPY.GetIpyGameData("PlayerFaceStar", faceID, nextStar)
-    if not nextIpyData:
-        GameWorld.DebugLog("不存在该头像星级! faceID=%s,nextStar=%s" % (faceID, nextStar), playerID)
-        return
-    needItemList = nextIpyData.GetStarUpNeedItemList()
-    if not needItemList:
-        return
-    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
-    lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
-    if lackItemDict:
-        GameWorld.DebugLog("头像升星所需物品不足! faceID=%s,nextStar=%s,needItemList=%s,lackItemDict=%s" 
-                           % (faceID, nextStar, needItemList, lackItemDict), playerID)
-        return
-    ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "FaceStarUP")
-    
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FaceStar % faceID, nextStar)
-    
-    GameWorld.DebugLog("头像升星! faceID=%s,curStar=%s,nextStar=%s" % (faceID, curStar, nextStar), playerID)
-    
-    RefreshFaceAttr(curPlayer)
-    SyncFaceInfo(curPlayer, [faceID])
-    return
-
-def GMSetFaceStar(curPlayer, faceID, setValue=None):
-    ## GM设置星级
-    
-    if not IsFaceCanUse(curPlayer, faceID):
-        return False, "The player has not activated the faceID(%s)" % faceID
-    
-    if setValue == None:
-        curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)
-        setStar = curStar + 1 # 没指定星级时默认升星
-    else:
-        setStar = setValue
-        
-    if setStar > 0:
-        if not IpyGameDataPY.GetIpyGameData("PlayerFaceStar", faceID, setStar):
-            return False, "The faceID(%s) star(%s) is not exist." % (faceID, setStar)
-        
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FaceStar % faceID, setStar)
-    GameWorld.Log("GM设置头像星级: faceID=%s,setStar=%s" % (faceID, setStar), curPlayer.GetPlayerID())
-    
-    RefreshFaceAttr(curPlayer)
-    SyncFaceInfo(curPlayer, [faceID])
-    return True, ""
-
-#// B2 28 头像框幻化 #tagCMFacePicChange
-#
-#struct    tagCMFacePicChange
-#{
-#    tagHead        Head;
-#    DWORD        FacePicID;    // 幻化的ID
-#};
-def OnFacePicChange(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    playerID = curPlayer.GetPlayerID()
-    facePicID = clientData.FacePicID
-    
     if not IsFacePicCanUse(curPlayer, facePicID):
         GameWorld.DebugLog("该头像框不可用! facePicID=%s" % (facePicID), playerID)
         return    
@@ -461,100 +398,49 @@
     curPlayer.SetFacePic(facePicID)
     return
 
-#// B2 29 头像框升星 #tagCMFacePicStarUP
-#
-#struct    tagCMFacePicStarUP
-#{
-#    tagHead        Head;
-#    DWORD        FacePicID;
-#};
-def OnFacePicStarUP(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+def OnFacePicStarUP(curPlayer, facePicID):
     playerID = curPlayer.GetPlayerID()
-    facePicID = clientData.FacePicID
-    
     if not IsFacePicCanUse(curPlayer, facePicID):
         GameWorld.DebugLog("该头像框不可用! facePicID=%s" % (facePicID), playerID)
         return
-    
-    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % facePicID)        
-    nextStar = curStar + 1
-    nextIpyData = IpyGameDataPY.GetIpyGameData("PlayerFacePicStar", facePicID, nextStar)
-    if not nextIpyData:
-        GameWorld.DebugLog("不存在该头像框星级! facePicID=%s,nextStar=%s" % (facePicID, nextStar), playerID)
+    ipyData = IpyGameDataPY.GetIpyGameData("PlayerFacePic", facePicID)
+    if not ipyData:
         return
-    needItemList = nextIpyData.GetStarUpNeedItemList()
-    if not needItemList:
+    starMax = ipyData.GetStarMax()
+    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % facePicID)
+    if curStar >= starMax:
+        GameWorld.DebugLog("头像框星级已满! facePicID=%s,curStar=%s >= %s" % (facePicID, curStar, starMax), playerID)
         return
+    if ipyData.GetUnlockWay() != 2:
+        return
+    itemID = ipyData.GetUnlockValue()
+    itemCount = ipyData.GetUnlockNeedCnt()
+    if not itemID or not itemCount:
+        return
+    needItemList = [[itemID, itemCount]]
     itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
     lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
     if lackItemDict:
-        GameWorld.DebugLog("头像框升星所需物品不足! facePicID=%s,nextStar=%s,needItemList=%s,lackItemDict=%s" 
-                           % (facePicID, nextStar, needItemList, lackItemDict), playerID)
+        GameWorld.DebugLog("头像框升星所需物品不足! facePicID=%s,lackItemDict=%s" % (facePicID, lackItemDict), playerID)
         return
     ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "FacePicStarUP")
     
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FacePicStar % facePicID, nextStar)
-    
-    GameWorld.DebugLog("头像框升星! facePicID=%s,curStar=%s,nextStar=%s" % (facePicID, curStar, nextStar), playerID)
-    
-    RefreshFacePicAttr(curPlayer)
-    SyncFacePicInfo(curPlayer, [facePicID])
+    nextStar = curStar + 1
+    GameWorld.DebugLog("头像框升星! facePicID=%s,nextStar=%s" % (facePicID, nextStar), playerID)
+    SetFacePicStar(curPlayer, facePicID, nextStar)
     return
 
-def GMSetFacePicStar(curPlayer, facePicID, setValue=None):
-    ## GM设置星级
-    
+def SetFacePicStar(curPlayer, facePicID, setStar):
     if not IsFacePicCanUse(curPlayer, facePicID):
-        return False, "The player has not activated the facePicID(%s)" % facePicID
-    
-    if setValue == None:
-        curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % facePicID)
-        setStar = curStar + 1 # 没指定星级时默认升星
-    else:
-        setStar = setValue
-        
-    if setStar > 0:
-        if not IpyGameDataPY.GetIpyGameData("PlayerFacePicStar", facePicID, setStar):
-            return False, "The setStar(%s) star(%s) is not exist." % (setStar, setStar)
-        
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("PlayerFacePic", facePicID)
+    if not ipyData:
+        return
+    setStar = min(setStar, ipyData.GetStarMax())
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FacePicStar % facePicID, setStar)
-    GameWorld.Log("GM设置头像框星级: facePicID=%s,setStar=%s" % (facePicID, setStar), curPlayer.GetPlayerID())
-    
     RefreshFacePicAttr(curPlayer)
     SyncFacePicInfo(curPlayer, [facePicID])
-    return True, ""
-
-def SyncFaceInfo(curPlayer, faceIDList=None):
-    if faceIDList == None:
-        syncIDList = []
-        ipyDataMgr = IpyGameDataPY.IPY_Data()
-        for index in range(ipyDataMgr.GetPlayerFaceCount()):
-            ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
-            syncIDList.append(ipyData.GetFaceID())
-    else:
-        syncIDList = faceIDList
-        
-    faceList = []
-    for faceID in syncIDList:
-        state = 1 if IsFaceCanUse(curPlayer, faceID) else 0
-        if not state and faceIDList == None:
-            continue
-        face = ChPyNetSendPack.tagMCFace()
-        face.FaceID = faceID
-        face.State = state
-        face.EndTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceEndTime % faceID)
-        face.Star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)
-        faceList.append(face)
-        
-    if not faceList:
-        return
-    
-    clientPack = ChPyNetSendPack.tagMCFaceInfo()
-    clientPack.FaceList = faceList
-    clientPack.Count = len(clientPack.FaceList)
-    NetPackCommon.SendFakePack(curPlayer, clientPack)
-    return
+    return True
 
 def SyncFacePicInfo(curPlayer, facePicIDList=None):
     if facePicIDList == None:
@@ -571,7 +457,7 @@
         state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, facePicID)
         if not state and facePicIDList == None:
             continue
-        facePic = ChPyNetSendPack.tagMCFacePic()
+        facePic = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagMCFacePic)
         facePic.FacePicID = facePicID
         facePic.State = state
         facePic.EndTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicEndTime % facePicID)
@@ -581,7 +467,7 @@
     if not facePicList:
         return
     
-    clientPack = ChPyNetSendPack.tagMCFacePicInfo()
+    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagMCFacePicInfo)
     clientPack.FacePicList = facePicList
     clientPack.Count = len(clientPack.FacePicList)
     NetPackCommon.SendFakePack(curPlayer, clientPack)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHJG.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHJG.py
new file mode 100644
index 0000000..bdf5c14
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHJG.py
@@ -0,0 +1,684 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerHJG
+#
+# @todo:幻境阁
+# @author hxp
+# @date 2025-10-15
+# @version 1.0
+#
+# 详细描述: 幻境阁(管理 形象、头像、头像框、气泡、称号)
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-10-15 09:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ItemCommon
+import PlayerOnline
+import PlayerChatBox
+import PlayerControl
+import IpyGameDataPY
+import ChPyNetSendPack
+import IPY_GameWorld
+import NetPackCommon
+import PlayerFace
+import PlayerHero
+import ChConfig
+import ObjPool
+
+import random
+import time
+
+HJGType_Model = 1
+HJGType_Face = 2
+HJGType_FacePic = 3
+HJGType_ChatBox = 4
+HJGType_Title = 5
+
+def OnPlayerLogin(curPlayer):
+    SyncTitleInfo(curPlayer)
+    SyncModelInfo(curPlayer)
+    PlayerFace.OnPlayerLogin(curPlayer)
+    PlayerChatBox.OnPlayerLogin(curPlayer)
+    return
+
+def OnMinute(curPlayer):
+    OnMinuteTitle(curPlayer)
+    OnMinuteModel(curPlayer)
+    PlayerFace.OnMinute(curPlayer)
+    PlayerChatBox.OnMinute(curPlayer)
+    return
+
+#// B2 25 幻境阁操作 #tagCSHJGOP
+#
+#struct    tagCSHJGOP
+#{
+#    tagHead         Head;
+#    BYTE        Type;    // 类型 1-形象;2-头像;3-头像框;4-气泡;5-称号    
+#    BYTE        OPType;    // 操作 1-激活;2-佩戴;3-卸下;4-升星
+#    DWORD        OPID;    // 操作对应的ID,如形象ID等
+#};
+def OnHJGOP(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    hjgType = clientData.Type
+    opType = clientData.OPType
+    opID = clientData.OPID
+    
+    # 激活
+    if opType == 1:
+        OnHJGActivate(curPlayer, hjgType, opID)
+    # 佩戴
+    elif opType == 2:
+        OnHJGUse(curPlayer, hjgType, opID)
+    # 卸下
+    elif opType == 3:
+        # 暂仅称号支持卸下
+        if hjgType == HJGType_Title:
+            OnTakeOffTitle(curPlayer, opID)
+    # 升级
+    elif opType == 4:
+        OnHJGStarUP(curPlayer, hjgType, opID)
+        
+    return
+
+def OnHJGActivate(curPlayer, hjgType, opID):
+    ## 幻境阁激活
+    if hjgType == HJGType_Model:
+        AddModel(curPlayer, opID)
+    elif hjgType == HJGType_Face:
+        PlayerFace.AddFace(curPlayer, opID)
+    elif hjgType == HJGType_FacePic:
+        PlayerFace.AddFacePic(curPlayer, opID)
+    elif hjgType == HJGType_ChatBox:
+        PlayerChatBox.AddChatBox(curPlayer, opID)
+    elif hjgType == HJGType_Title:
+        AddTitle(curPlayer, opID)
+    return
+
+def OnHJGUse(curPlayer, hjgType, opID):
+    ## 幻境阁使用/佩戴
+    if hjgType == HJGType_Model:
+        OnUseModel(curPlayer, opID)
+    elif hjgType == HJGType_Face:
+        PlayerFace.OnUseFace(curPlayer, opID)
+    elif hjgType == HJGType_FacePic:
+        PlayerFace.OnUseFacePic(curPlayer, opID)
+    elif hjgType == HJGType_ChatBox:
+        PlayerChatBox.OnUseChatBox(curPlayer, opID)
+    elif hjgType == HJGType_Title:
+        OnUseTitle(curPlayer, opID)
+    return
+
+def OnHJGStarUP(curPlayer, hjgType, opID):
+    ## 幻境阁升星
+    if hjgType == HJGType_Model:
+        OnModelStarUP(curPlayer, opID)
+    elif hjgType == HJGType_Face:
+        PlayerFace.OnFaceStarUP(curPlayer, opID)
+    elif hjgType == HJGType_FacePic:
+        PlayerFace.OnFacePicStarUP(curPlayer, opID)
+    elif hjgType == HJGType_ChatBox:
+        PlayerChatBox.OnChatBoxStarUP(curPlayer, opID)
+    elif hjgType == HJGType_Title:
+        OnTitleStarUP(curPlayer, opID)
+    return
+
+def RefreshHJGAttr(curPlayer):
+    CalcHJGAttr(curPlayer)
+    PlayerOnline.GetOnlinePlayer(curPlayer).RefreshRoleAttr()
+    return
+
+def CalcHJGAttr(curPlayer):
+    
+    playerID = curPlayer.GetPlayerID()
+    attrDict = {}
+    
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    # 称号
+    for index in range(ipyDataMgr.GetTitleCount()):
+        ipyData = ipyDataMgr.GetTitleByIndex(index)
+        titleID = ipyData.GetTitleID()
+        if not IsTitleCanUse(curPlayer, titleID, ipyData):
+            continue
+        attrIDList = ipyData.GetAttrIDList()
+        if not attrIDList:
+            continue
+        initAttrValueList = ipyData.GetInitAttrValueList()
+        perStarAddList = ipyData.GetAttrPerStarAddList()
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)
+        for aIndex, attrID in enumerate(attrIDList):
+            initValue = initAttrValueList[aIndex] if len(initAttrValueList) > aIndex else 0
+            perStarAdd = perStarAddList[aIndex] if len(perStarAddList) > aIndex else 0
+            attrValue = initValue + perStarAdd * star
+            attrDict[attrID] = attrDict.get(attrID, 0) + attrValue
+    #GameWorld.DebugLog("幻境阁累加称号,总属性: %s" % attrDict)
+    
+    # 形象
+    for index in range(ipyDataMgr.GetModelCount()):
+        ipyData = ipyDataMgr.GetModelByIndex(index)
+        modelID = ipyData.GetModelID()
+        if not IsModelCanUse(curPlayer, modelID, ipyData):
+            continue
+        attrIDList = ipyData.GetAttrIDList()
+        if not attrIDList:
+            continue
+        initAttrValueList = ipyData.GetInitAttrValueList()
+        perStarAddList = ipyData.GetAttrPerStarAddList()
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelStar % modelID)
+        for aIndex, attrID in enumerate(attrIDList):
+            initValue = initAttrValueList[aIndex] if len(initAttrValueList) > aIndex else 0
+            perStarAdd = perStarAddList[aIndex] if len(perStarAddList) > aIndex else 0
+            attrValue = initValue + perStarAdd * star
+            attrDict[attrID] = attrDict.get(attrID, 0) + attrValue
+    #GameWorld.DebugLog("幻境阁累加形象,总属性: %s" % attrDict)
+    
+    # 头像
+    for index in range(ipyDataMgr.GetPlayerFaceCount()):
+        ipyData = ipyDataMgr.GetPlayerFaceByIndex(index)
+        faceID = ipyData.GetFaceID()
+        if not PlayerFace.IsFaceCanUse(curPlayer, faceID, ipyData):
+            continue
+        attrIDList = ipyData.GetAttrIDList()
+        if not attrIDList:
+            continue
+        initAttrValueList = ipyData.GetInitAttrValueList()
+        perStarAddList = ipyData.GetAttrPerStarAddList()
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % faceID)
+        for aIndex, attrID in enumerate(attrIDList):
+            initValue = initAttrValueList[aIndex] if len(initAttrValueList) > aIndex else 0
+            perStarAdd = perStarAddList[aIndex] if len(perStarAddList) > aIndex else 0
+            attrValue = initValue + perStarAdd * star
+            attrDict[attrID] = attrDict.get(attrID, 0) + attrValue
+    #GameWorld.DebugLog("幻境阁累加头像,总属性: %s" % attrDict)
+    
+    # 头像框
+    for index in range(ipyDataMgr.GetPlayerFacePicCount()):
+        ipyData = ipyDataMgr.GetPlayerFacePicByIndex(index)
+        facePicID = ipyData.GetFacePicID()
+        if not PlayerFace.IsFacePicCanUse(curPlayer, facePicID, ipyData):
+            continue
+        attrIDList = ipyData.GetAttrIDList()
+        if not attrIDList:
+            continue
+        initAttrValueList = ipyData.GetInitAttrValueList()
+        perStarAddList = ipyData.GetAttrPerStarAddList()
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % facePicID)
+        for aIndex, attrID in enumerate(attrIDList):
+            initValue = initAttrValueList[aIndex] if len(initAttrValueList) > aIndex else 0
+            perStarAdd = perStarAddList[aIndex] if len(perStarAddList) > aIndex else 0
+            attrValue = initValue + perStarAdd * star
+            attrDict[attrID] = attrDict.get(attrID, 0) + attrValue
+    #GameWorld.DebugLog("幻境阁累加头框,总属性: %s" % attrDict)
+    
+    # 气泡框
+    for index in range(ipyDataMgr.GetChatBoxCount()):
+        ipyData = ipyDataMgr.GetChatBoxByIndex(index)
+        boxID = ipyData.GetBoxID()
+        if not PlayerChatBox.IsBoxCanUse(curPlayer, boxID, ipyData):
+            continue
+        attrIDList = ipyData.GetAttrIDList()
+        if not attrIDList:
+            continue
+        initAttrValueList = ipyData.GetInitAttrValueList()
+        perStarAddList = ipyData.GetAttrPerStarAddList()
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ChatBoxStar % boxID)
+        for aIndex, attrID in enumerate(attrIDList):
+            initValue = initAttrValueList[aIndex] if len(initAttrValueList) > aIndex else 0
+            perStarAdd = perStarAddList[aIndex] if len(perStarAddList) > aIndex else 0
+            attrValue = initValue + perStarAdd * star
+            attrDict[attrID] = attrDict.get(attrID, 0) + attrValue
+    #GameWorld.DebugLog("幻境阁累加气泡,总属性: %s" % attrDict)
+    
+    # 保存计算值
+    GameWorld.DebugLog("幻境阁属性: %s" % attrDict, playerID)
+    PlayerOnline.GetOnlinePlayer(curPlayer).SetCalcAttr(ChConfig.Def_CalcAttr_HJG, attrDict)
+    return
+
+## ----------------------------------------- 称号 --------------------------------------------------
+
+def OnMinuteTitle(curPlayer):
+    curTime = int(time.time())
+    
+    delIDList = []
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetTitleCount()):
+        ipyData = ipyDataMgr.GetTitleByIndex(index)
+        titleID = ipyData.GetTitleID()
+        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID):
+            # 未激活的不处理
+            continue
+        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleEndTime % titleID)
+        if not endTime or endTime > curTime:
+            # 永久或未过期
+            continue
+        if DelTitle(curPlayer, titleID, False, "TitleTimeout"):
+            delIDList.append(titleID)
+            
+    if delIDList:
+        RefreshHJGAttr(curPlayer)
+    return
+
+def AddTitle(curPlayer, titleID, setExpireTimes=None, isFree=False):
+    if titleID <= 0:
+        return
+    playerID = curPlayer.GetPlayerID()
+    ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+    if not ipyData:
+        return
+    if ipyData.GetUnlockWay() != 2:
+        GameWorld.DebugLog("非道具激活的不用添加: titleID=%s" % (titleID), playerID)
+        return
+    if not isFree:
+        itemID = ipyData.GetUnlockValue()
+        itemCount = ipyData.GetUnlockNeedCnt()
+        if not itemID or not itemCount:
+            return
+        needItemList = [[itemID, itemCount]]
+        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+        lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+        if lackItemDict:
+            GameWorld.DebugLog("激活所需物品不足! titleID=%s,lackItemDict=%s" % (titleID, lackItemDict), playerID)
+            return
+        ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "AddTitle")
+        
+    ipyExpireSeconds = ipyData.GetExpireMinutes() * 60
+    
+    curTime = int(time.time())
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID)
+    endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleEndTime % titleID)
+    GameWorld.Log("添加称号: titleID=%s,setExpireTimes=%s,state=%s,endTime=%s,ipyExpireSeconds=%s,curTime=%s" 
+                  % (titleID, setExpireTimes, state, endTime, ipyExpireSeconds, curTime), playerID)
+    updEndTime = endTime
+    
+    # 指定时长的,如GM指定
+    if setExpireTimes > 0:
+        updEndTime = curTime + setExpireTimes
+        GameWorld.Log("    指定时长: titleID=%s,updEndTime=%s" % (titleID, updEndTime), playerID)
+        
+    # 永久
+    elif ipyExpireSeconds == 0 or setExpireTimes == 0:
+        updEndTime = 0
+        GameWorld.Log("    永久时长: titleID=%s,updEndTime=%s" % (titleID, updEndTime), playerID)
+        
+    else:
+        # 未过期
+        if endTime > curTime:
+            updEndTime = endTime + ipyExpireSeconds
+            GameWorld.Log("    累加时长: titleID=%s,updEndTime=%s" % (titleID, updEndTime), playerID)
+        else:
+            updEndTime = curTime + ipyExpireSeconds
+            GameWorld.Log("    重新激活: titleID=%s,updEndTime=%s" % (titleID, updEndTime), playerID)
+            
+    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID, 1)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleEndTime % titleID, updEndTime)
+    RefreshHJGAttr(curPlayer)
+    SyncTitleInfo(curPlayer, [titleID])
+    return True
+
+def DelTitle(curPlayer, titleID, isRefreshAttr=True, notifyMail=""):
+    playerID = curPlayer.GetPlayerID()
+    ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+    if not ipyData:
+        return
+    if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID):
+        return
+    GameWorld.Log("删除称号: titleID=%s,notifyMail=%s" % (titleID, notifyMail), playerID)
+    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleEndTime % titleID, 0)
+    # 星级不重置,重新激活后再次生效
+    
+    if PlayerControl.GetTitleID(curPlayer) == titleID:
+        defaultIDList = GetDefaultTitleIDList()
+        randID = random.choice(defaultIDList) if defaultIDList else 0
+        PlayerControl.SetTitleID(curPlayer, randID)
+        GameWorld.DebugLog("玩家佩戴的称号被删除,随机重置默认! randID=%s" % randID, playerID)
+        
+    if isRefreshAttr:
+        RefreshHJGAttr(curPlayer)
+    SyncTitleInfo(curPlayer, [titleID])
+    if notifyMail:
+        PlayerControl.SendMailByKey(notifyMail, [playerID], [], [titleID])
+        
+    return True
+
+def GetDefaultTitleIDList():
+    defaultIDList = []
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetTitleCount()):
+        ipyData = ipyDataMgr.GetTitleByIndex(index)
+        titleID = ipyData.GetTitleID()
+        if ipyData.GetUnlockWay() != 1:
+            continue
+        defaultIDList.append(titleID)
+    return defaultIDList
+
+def IsTitleCanUse(curPlayer, titleID, ipyData=None):
+    ## 称号是否可用
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID)
+    if state:
+        return True
+    
+    if not ipyData:
+        ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+    if ipyData:
+        unlockWay = ipyData.GetUnlockWay()
+        if unlockWay == 1: # 默认激活的
+            return True
+        
+    return False
+
+def OnUseTitle(curPlayer, titleID):
+    playerID = curPlayer.GetPlayerID()
+    if not IsTitleCanUse(curPlayer, titleID):
+        GameWorld.DebugLog("该称号不可用! titleID=%s" % (titleID), playerID)
+        return    
+    GameWorld.DebugLog("使用称号! titleID=%s" % (titleID), playerID)
+    PlayerControl.SetTitleID(curPlayer, titleID)
+    return
+
+def OnTakeOffTitle(curPlayer, titleID):
+    if PlayerControl.GetTitleID(curPlayer) != titleID:
+        return
+    PlayerControl.SetTitleID(curPlayer, 0)
+    return
+
+def OnTitleStarUP(curPlayer, titleID):
+    playerID = curPlayer.GetPlayerID()
+    if not IsTitleCanUse(curPlayer, titleID):
+        GameWorld.DebugLog("该称号不可用! titleID=%s" % (titleID), playerID)
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+    if not ipyData:
+        return
+    starMax = ipyData.GetStarMax()
+    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)
+    if curStar >= starMax:
+        GameWorld.DebugLog("星级已满! titleID=%s,curStar=%s >= %s" % (titleID, curStar, starMax), playerID)
+        return
+    if ipyData.GetUnlockWay() != 2:
+        return
+    itemID = ipyData.GetUnlockValue()
+    itemCount = ipyData.GetUnlockNeedCnt()
+    if not itemID or not itemCount:
+        return
+    needItemList = [[itemID, itemCount]]
+    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+    lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+    if lackItemDict:
+        GameWorld.DebugLog("升星所需物品不足! titleID=%s,lackItemDict=%s" % (titleID, lackItemDict), playerID)
+        return
+    ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "TitleStarUP")
+    
+    nextStar = curStar + 1
+    GameWorld.DebugLog("升星! titleID=%s,nextStar=%s" % (titleID, nextStar), playerID)
+    SetTitleStar(curPlayer, titleID, nextStar)
+    return
+
+def SetTitleStar(curPlayer, titleID, setStar):
+    if not IsTitleCanUse(curPlayer, titleID):
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("Title", titleID)
+    if not ipyData:
+        return
+    setStar = min(setStar, ipyData.GetStarMax())
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TitleStar % titleID, setStar)
+    RefreshHJGAttr(curPlayer)
+    SyncTitleInfo(curPlayer, [titleID])
+    return True
+
+def SyncTitleInfo(curPlayer, titleIDList=None):
+    if titleIDList == None:
+        syncIDList = []
+        ipyDataMgr = IpyGameDataPY.IPY_Data()
+        for index in range(ipyDataMgr.GetTitleCount()):
+            ipyData = ipyDataMgr.GetTitleByIndex(index)
+            syncIDList.append(ipyData.GetTitleID())
+    else:
+        syncIDList = titleIDList
+        
+    titleList = []
+    for titleID in syncIDList:
+        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, titleID)
+        if not state and titleIDList == None:
+            continue
+        title = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCTitle)
+        title.TitleID = titleID
+        title.State = state
+        title.EndTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleEndTime % titleID)
+        title.Star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)
+        titleList.append(title)
+        
+    if not titleList:
+        return
+    
+    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCTitleInfo)
+    clientPack.TitleList = titleList
+    clientPack.Count = len(clientPack.TitleList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+## -------------------------------------------------------------------------------------------------
+
+## ----------------------------------------- 形象 --------------------------------------------------
+
+def OnMinuteModel(curPlayer):
+    curTime = int(time.time())
+    
+    delIDList = []
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetModelCount()):
+        ipyData = ipyDataMgr.GetModelByIndex(index)
+        modelID = ipyData.GetModelID()
+        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID):
+            # 未激活的不处理
+            continue
+        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelEndTime % modelID)
+        if not endTime or endTime > curTime:
+            # 永久或未过期
+            continue
+        if DelModel(curPlayer, modelID, False, "ModelTimeout"):
+            delIDList.append(modelID)
+            
+    if delIDList:
+        RefreshHJGAttr(curPlayer)
+    return
+
+def AddModel(curPlayer, modelID, setExpireTimes=None, isFree=False):
+    if modelID <= 0:
+        return
+    playerID = curPlayer.GetPlayerID()
+    ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+    if not ipyData:
+        return
+    if ipyData.GetUnlockWay() != 2:
+        GameWorld.DebugLog("非道具激活的不用添加: modelID=%s" % (modelID), playerID)
+        return
+    if not isFree:
+        itemID = ipyData.GetUnlockValue()
+        itemCount = ipyData.GetUnlockNeedCnt()
+        if not itemID or not itemCount:
+            return
+        needItemList = [[itemID, itemCount]]
+        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+        lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+        if lackItemDict:
+            GameWorld.DebugLog("激活所需物品不足! modelID=%s,lackItemDict=%s" % (modelID, lackItemDict), playerID)
+            return
+        ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "AddModel")
+        
+    ipyExpireSeconds = ipyData.GetExpireMinutes() * 60
+    
+    curTime = int(time.time())
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID)
+    endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelEndTime % modelID)
+    GameWorld.Log("添加形象: modelID=%s,setExpireTimes=%s,state=%s,endTime=%s,ipyExpireSeconds=%s,curTime=%s" 
+                  % (modelID, setExpireTimes, state, endTime, ipyExpireSeconds, curTime), playerID)
+    updEndTime = endTime
+    
+    # 指定时长的,如GM指定
+    if setExpireTimes > 0:
+        updEndTime = curTime + setExpireTimes
+        GameWorld.Log("    指定时长: modelID=%s,updEndTime=%s" % (modelID, updEndTime), playerID)
+        
+    # 永久
+    elif ipyExpireSeconds == 0 or setExpireTimes == 0:
+        updEndTime = 0
+        GameWorld.Log("    永久时长: modelID=%s,updEndTime=%s" % (modelID, updEndTime), playerID)
+        
+    else:
+        # 未过期
+        if endTime > curTime:
+            updEndTime = endTime + ipyExpireSeconds
+            GameWorld.Log("    累加时长: modelID=%s,updEndTime=%s" % (modelID, updEndTime), playerID)
+        else:
+            updEndTime = curTime + ipyExpireSeconds
+            GameWorld.Log("    重新激活: modelID=%s,updEndTime=%s" % (modelID, updEndTime), playerID)
+            
+    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID, 1)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelEndTime % modelID, updEndTime)
+    RefreshHJGAttr(curPlayer)
+    SyncModelInfo(curPlayer, [modelID])
+    return True
+
+def DelModel(curPlayer, modelID, isRefreshAttr=True, notifyMail=""):
+    playerID = curPlayer.GetPlayerID()
+    ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+    if not ipyData:
+        return
+    if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID):
+        return
+    GameWorld.Log("删除形象: modelID=%s,notifyMail=%s" % (modelID, notifyMail), playerID)
+    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelEndTime % modelID, 0)
+    # 星级不重置,重新激活后再次生效
+    
+    if curPlayer.GetModelMark() == modelID:
+        defaultIDList = GetDefaultModelIDList()
+        randID = random.choice(defaultIDList) if defaultIDList else 0
+        curPlayer.SetModelMark(randID)
+        GameWorld.DebugLog("玩家使用的形象被删除,随机重置默认! randID=%s" % randID, playerID)
+        
+    if isRefreshAttr:
+        RefreshHJGAttr(curPlayer)
+    SyncModelInfo(curPlayer, [modelID])
+    if notifyMail:
+        PlayerControl.SendMailByKey(notifyMail, [playerID], [], [modelID])
+        
+    return True
+
+def GetDefaultModelIDList():
+    defaultIDList = []
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetModelCount()):
+        ipyData = ipyDataMgr.GetModelByIndex(index)
+        modelID = ipyData.GetModelID()
+        if ipyData.GetUnlockWay() != 1:
+            continue
+        defaultIDList.append(modelID)
+    return defaultIDList
+
+def IsModelCanUse(curPlayer, modelID, ipyData=None):
+    ## 形象是否可用
+    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID)
+    if state:
+        return True
+    
+    if not ipyData:
+        ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+    if ipyData:
+        unlockWay = ipyData.GetUnlockWay()
+        unlockValue = ipyData.GetUnlockValue()
+        if unlockWay == 1: # 默认激活的
+            return True
+        if unlockWay == 3: # 关联武将
+            heroID = unlockValue
+            return True if PlayerHero.GetHeroActivite(curPlayer, heroID) else False
+        
+    return False
+
+def OnUseModel(curPlayer, modelID):
+    playerID = curPlayer.GetPlayerID()
+    if not IsModelCanUse(curPlayer, modelID):
+        GameWorld.DebugLog("该形象不可用! modelID=%s" % (modelID), playerID)
+        return    
+    GameWorld.DebugLog("使用形象! modelID=%s" % (modelID), playerID)
+    curPlayer.SetModelMark(modelID)
+    return
+
+def OnModelStarUP(curPlayer, modelID):
+    playerID = curPlayer.GetPlayerID()
+    if not IsModelCanUse(curPlayer, modelID):
+        GameWorld.DebugLog("该形象不可用! modelID=%s" % (modelID), playerID)
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+    if not ipyData:
+        return
+    starMax = ipyData.GetStarMax()
+    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelStar % modelID)
+    if curStar >= starMax:
+        GameWorld.DebugLog("星级已满! modelID=%s,curStar=%s >= %s" % (modelID, curStar, starMax), playerID)
+        return
+    if ipyData.GetUnlockWay() != 2:
+        return
+    itemID = ipyData.GetUnlockValue()
+    itemCount = ipyData.GetUnlockNeedCnt()
+    if not itemID or not itemCount:
+        return
+    needItemList = [[itemID, itemCount]]
+    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
+    lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needItemList, itemPack)
+    if lackItemDict:
+        GameWorld.DebugLog("升星所需物品不足! modelID=%s,lackItemDict=%s" % (modelID, lackItemDict), playerID)
+        return
+    ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, "ModelStarUP")
+    
+    nextStar = curStar + 1
+    GameWorld.DebugLog("升星! modelID=%s,nextStar=%s" % (modelID, nextStar), playerID)
+    SetModelStar(curPlayer, modelID, nextStar)
+    return
+
+def SetModelStar(curPlayer, modelID, setStar):
+    if not IsModelCanUse(curPlayer, modelID):
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("Model", modelID)
+    if not ipyData:
+        return
+    setStar = min(setStar, ipyData.GetStarMax())
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ModelStar % modelID, setStar)
+    RefreshHJGAttr(curPlayer)
+    SyncModelInfo(curPlayer, [modelID])
+    return True
+
+def SyncModelInfo(curPlayer, modelIDList=None):
+    if modelIDList == None:
+        syncIDList = []
+        ipyDataMgr = IpyGameDataPY.IPY_Data()
+        for index in range(ipyDataMgr.GetModelCount()):
+            ipyData = ipyDataMgr.GetModelByIndex(index)
+            syncIDList.append(ipyData.GetModelID())
+    else:
+        syncIDList = modelIDList
+        
+    modelList = []
+    for modelID in syncIDList:
+        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ModelState, modelID)
+        if not state and modelIDList == None:
+            continue
+        model = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCModel)
+        model.ModelID = modelID
+        model.State = state
+        model.EndTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelEndTime % modelID)
+        model.Star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ModelStar % modelID)
+        modelList.append(model)
+        
+    if not modelList:
+        return
+    
+    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCModelInfo)
+    clientPack.ModelList = modelList
+    clientPack.Count = len(clientPack.ModelList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+## -------------------------------------------------------------------------------------------------
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py
index ee604f5..fb9f7fa 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py
@@ -26,6 +26,7 @@
 import PlayerPrestigeSys
 import PlayerGubao
 import PlayerHero
+import PlayerHJG
 import GameWorld
 import ChConfig
 import ChEquip
@@ -414,6 +415,7 @@
     PlayerHero.CalcHeroAddAttr(curPlayer)
     PlayerPrestigeSys.CalcOfficialRankAttr(curPlayer)
     PlayerGubao.CalcGubaoAttr(curPlayer)
+    PlayerHJG.CalcHJGAttr(curPlayer)
     return
 
 def doRefreshLineupAttr(curPlayer, olPlayer, lineup):
@@ -637,6 +639,7 @@
     bookAttrDict = olPlayer.GetCalcAttr(ChConfig.Def_CalcAttr_HeroBook)
     realmAttrDict = olPlayer.GetCalcAttr(ChConfig.Def_CalcAttr_Realm)
     gubaoAttrDict = olPlayer.GetCalcAttr(ChConfig.Def_CalcAttr_Gubao)
+    hjgAttrDict = olPlayer.GetCalcAttr(ChConfig.Def_CalcAttr_HJG)
     
     GameWorld.DebugLog("    国家武将统计=%s" % countryHeroInfo, playerID)
     GameWorld.DebugLog("    羁绊武将统计=%s" % fetterHeroInfo, playerID)
@@ -653,6 +656,7 @@
     GameWorld.DebugLog("    主公图鉴属性=%s" % bookAttrDict, playerID)
     GameWorld.DebugLog("    主公官职属性=%s" % realmAttrDict, playerID)
     GameWorld.DebugLog("    主公古宝属性=%s" % gubaoAttrDict, playerID)
+    GameWorld.DebugLog("    主幻境阁属性=%s" % hjgAttrDict, playerID)
     
     PlayerLV = curPlayer.GetLV()
     OfficialLV = curPlayer.GetOfficialRank()
@@ -690,6 +694,9 @@
             gubaoValue = gubaoAttrDict.get(attrID, 0)
             gubaoPer = gubaoAttrDict.get(attrPerID, 0) / 10000.0 if attrPerID else 0
             
+            hjgValue = hjgAttrDict.get(attrID, 0)
+            hjgPer = hjgAttrDict.get(attrPerID, 0) / 10000.0 if attrPerID else 0
+            
             lineupInitAddPer, lineupLVAddPer, lineupBreakLVAddPer, lineupStarAddPer = 0, 0, 0, 0
             if attrID in ChConfig.BaseAttrIDList:
                 lineupInitAddPer, lineupLVAddPer, lineupBreakLVAddPer, lineupStarAddPer = InitAddPer, LVAddPer, BreakLVAddPer, StarAddPer
@@ -716,7 +723,7 @@
                 
             # 计算
             attrParamDict = {"lvValue":lvValue, "equipValue":equipValue, "bookValue":bookValue, "bookPer":bookPer, "realmValue":realmValue, "realmPer":realmPer, 
-                             "gubaoValue":gubaoValue, "gubaoPer":gubaoPer, 
+                             "gubaoValue":gubaoValue, "gubaoPer":gubaoPer, "hjgValue":hjgValue, "hjgPer":hjgPer,
                              "lineupInitAddPer":lineupInitAddPer, "lineupLVAddPer":lineupLVAddPer, "lineupBreakLVAddPer":lineupBreakLVAddPer, "lineupStarAddPer":lineupStarAddPer,
                              "heroSelfValue":heroSelfValue, "heroSelfPer":heroSelfPer, "inheritPer":inheritPer,
                              "lineupHaloValue":lineupHaloValue, "lineupHaloPer":lineupHaloPer, "fetterValue":fetterValue, "fetterPer":fetterPer,
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
index fef7d1b..7ed5d99 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
@@ -25,7 +25,6 @@
 import OperControlManager
 import ShareDefine
 import ReadChConfig
-import PlayerDienstgrad
 import IpyGameDataPY
 import GameObj
 import GameMap
@@ -36,13 +35,11 @@
 import PlayerSuccess
 import PassiveBuffEffMng
 import FunctionNPCCommon
-import FormulaControl
 import PlayerFlashSale
-import PlayerChatBox
-import PlayerFace
 import PlayerBackup
 import PlayerOnline
 import PlayerGoldRush
+import PlayerHJG
 
 #---------------------------------------------------------------------
 #---------------------------------------------------------------------
@@ -1069,12 +1066,7 @@
         return
     curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_Minute, tick)
     
-    # 时效称号
-    PlayerDienstgrad.CheckDienstgradTimeout(curPlayer)
-    # 时效头像
-    PlayerFace.OnMinute(curPlayer)
-    # 聊天气泡
-    PlayerChatBox.OnMinute(curPlayer)
+    PlayerHJG.OnMinute(curPlayer)
     return
 
 # 一定时间自动释放的被动技能
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
index 51bab1a..c9c991f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
@@ -78,7 +78,7 @@
         #发送到跨服,待扩展
         return
     
-    bubbleBox = PlayerControl.GetChatBubbleBox(curPlayer) # 气泡框
+    bubbleBox = PlayerControl.GetChatBox(curPlayer) # 气泡框
     
     clientPack = ChPyNetSendPack.tagMCTalk()
     clientPack.ChannelType = channelType
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AddDienstgrad.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AddDienstgrad.py
deleted file mode 100644
index f807884..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AddDienstgrad.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-#-------------------------------------------------------------------------------
-#
-##@package Player.RemoteQuery.GY_Query_AddDienstgrad
-#
-# @todo:添加称号
-# @author xdh
-# @date 2016-09-22
-# @version 1.0
-#
-# 详细描述: 添加称号
-#
-#---------------------------------------------------------------------
-"""Version = 2016-09-22 22:00"""
-
-#导入
-import PlayerDienstgrad
-import GameWorld
-#---------------------------------------------------------------------
-
-#逻辑实现
-## 请求逻辑
-#  @param query_Type 请求类型
-#  @param query_ID 请求的玩家ID
-#  @param packCMDList 发包命令 [ ]
-#  @param tick 当前时间
-#  @return "True" or "False" or ""
-#  @remarks 函数详细说明.
-def DoLogic(query_Type, query_ID, packCMDList, tick):
-    
-    return ''
-#---------------------------------------------------------------------
-
-
-#执行结果
-## 执行结果
-#  @param curPlayer 发出请求的玩家
-#  @param callFunName 功能名称
-#  @param funResult 查询的结果
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def DoResult(curPlayer, callFunName, funResult, tick):
-    dienstgradID = GameWorld.ToIntDef(funResult, 0)
-    curDienstgrad = curPlayer.GetDienstgradManager().GetDienstgrad(dienstgradID)
-    if not curDienstgrad:
-        PlayerDienstgrad.PlayerAddDienstgrad(curPlayer, dienstgradID)
-        GameWorld.DebugLog("    添加称号: %s" % dienstgradID)
-    
-    return
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_GMTAddTitle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_GMTAddTitle.py
deleted file mode 100644
index 2c3032d..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_GMTAddTitle.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-##@package Player.RemoteQuery.GY_Query_GMTAddTitle
-#
-# @todo:激活称号
-# @author hxp
-# @date 2020-10-30
-# @version 1.0
-#
-# 详细描述: 激活称号
-#
-#-------------------------------------------------------------------------------
-#"""Version = 2020-10-30 17:00"""
-#-------------------------------------------------------------------------------
-
-import GameWorld
-import DataRecordPack
-import GMCommon
-import PlayerDienstgrad
-import ChConfig
-
-#---------------------------------------------------------------------
-#全局变量
-#---------------------------------------------------------------------
-#---------------------------------------------------------------------
-#逻辑实现 
-## 请求逻辑  
-#  @param query_Type 请求类型
-#  @param query_ID 玩家ID
-#  @param packCMDList 发包命令 
-#  @param tick 当前时间
-#  @return "True" or "False" or ""
-#  @remarks 函数详细说明.
-def DoLogic(query_Type, query_ID, packCMDList, tick):
-    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(query_ID)
-    
-    if not curPlayer or curPlayer.IsEmpty():
-        return
-    
-    Result = GMCommon.Def_Success
-    orderId, isOnlineGMT, titleID, expireTime, opType, setValue = packCMDList
-    
-    errorMsg = ""
-    isOK = False
-    if opType == "add":
-        isOK = PlayerDienstgrad.PlayerAddDienstgrad(curPlayer, titleID, expireTime=expireTime)
-    elif opType == "del":
-        isOK = PlayerDienstgrad.PlayerDelDienstgrad(curPlayer, titleID)
-    elif opType == "starUp":
-        isOK, errorMsg = PlayerDienstgrad.GMSetTitleStar(curPlayer, titleID)
-    elif opType == "setStar":
-        isOK, errorMsg = PlayerDienstgrad.GMSetTitleStar(curPlayer, titleID, setValue)
-    elif opType == "query":
-        isOK = True
-        
-    if not isOK:
-        if errorMsg:
-            errorMsg = "%s fail! %s" % (opType, errorMsg)
-        else:
-            errorMsg = "%s fail! Please check that the ID(%s) is correct." % (opType, titleID)
-        GameWorld.Log("GMT_AddTitle, errorMsg=%s" % errorMsg, curPlayer.GetPlayerID())
-        resultMsg = str([orderId, errorMsg, 'GMT_AddTitle', GMCommon.Def_Unknow])
-        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'GMToolResult', resultMsg, len(resultMsg))
-        return
-    
-    curDienstgradMgr = curPlayer.GetDienstgradManager()
-    curGrad = curDienstgradMgr.GetDienstgrad(titleID)
-    endTimeStr = "未激活"
-    if curGrad:
-        endTime = GetEndTime(curGrad, titleID)
-        endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
-        
-    curStar = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % titleID)
-    resultDict = {"titleID":titleID, "expireTime":expireTime, "isOnlineGMT":isOnlineGMT, "opType":opType, "star":curStar, "endTimeStr":endTimeStr}
-    GameWorld.Log("GMT_AddTitle, isOnlineGMT=%s,resultDict=%s" % (isOnlineGMT, resultDict), curPlayer.GetPlayerID())
-    #流向 记录
-    DataRecordPack.DR_ToolGMOperate(query_ID, curPlayer.GetPlayerName(), curPlayer.GetAccID(), 'GMT_AddTitle', resultDict)
-    
-    if isOnlineGMT:
-        resultMsg = str([orderId, resultDict, 'GMT_AddTitle', Result])
-        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'GMToolResult', resultMsg, len(resultMsg))
-        
-    return
-
-def GetEndTime(curGrad, titleID):
-    if not curGrad:
-        return 0
-    curExpireTime = curGrad.GetExpireTime() # 特殊指定有效期
-    if not curExpireTime:
-        curDienstgradData = PlayerDienstgrad.GetDienstgradData(titleID)
-        if curDienstgradData:
-            curExpireTime = curDienstgradData.GetExpireTime()
-    if curExpireTime <= 0:
-        return 0
-    createTimeStr = curGrad.GetCreateTimeStr()
-    return GameWorld.ChangeTimeStrToNum(createTimeStr) + curExpireTime
-
-#---------------------------------------------------------------------
-#执行结果
-## 执行结果
-#  @param curPlayer 发出请求的玩家
-#  @param callFunName 功能名称
-#  @param funResult 查询的结果
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def DoResult(curPlayer, callFunName, funResult, tick):
-    return
-
-
-
-
-
-
-
-
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_GMTFace.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_GMTFace.py
deleted file mode 100644
index 97666b8..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_GMTFace.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-##@package Player.RemoteQuery.GY_Query_GMTFace
-#
-# @todo:头像头像框
-# @author hxp
-# @date 2024-09-12
-# @version 1.0
-#
-# 详细描述: 头像头像框
-#
-#-------------------------------------------------------------------------------
-#"""Version = 2024-09-12 12:00"""
-#-------------------------------------------------------------------------------
-
-import GameWorld
-import DataRecordPack
-import PlayerFace
-import GMCommon
-import ChConfig
-
-#---------------------------------------------------------------------
-#全局变量
-#---------------------------------------------------------------------
-#---------------------------------------------------------------------
-#逻辑实现 
-## 请求逻辑  
-#  @param query_Type 请求类型
-#  @param query_ID 玩家ID
-#  @param packCMDList 发包命令 
-#  @param tick 当前时间
-#  @return "True" or "False" or ""
-#  @remarks 函数详细说明.
-def DoLogic(query_Type, query_ID, packCMDList, tick):
-    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(query_ID)
-    
-    if not curPlayer or curPlayer.IsEmpty():
-        return
-    
-    Result = GMCommon.Def_Success
-    orderId, isOnlineGMT, faceType, opID, expireTime, opType, setValue = packCMDList
-    
-    state, endTime, star = 0, 0, 0
-    isOK = False
-    errorMsg = ""
-    if faceType == "face":
-        if opType == "add":
-            isOK = PlayerFace.AddFace(curPlayer, opID, expireTime)
-        elif opType == "del":
-            isOK = PlayerFace.DelFace(curPlayer, opID)
-        elif opType == "starUp":
-            isOK, errorMsg = PlayerFace.GMSetFaceStar(curPlayer, opID)
-        elif opType == "setStar":
-            isOK, errorMsg = PlayerFace.GMSetFaceStar(curPlayer, opID, setValue)
-        elif opType == "query":
-            isOK = True
-        state = PlayerFace.IsFaceCanUse(curPlayer, opID)
-        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceEndTime % opID)
-        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % opID)
-    elif faceType == "facePic":
-        if opType == "add":
-            isOK = PlayerFace.AddFacePic(curPlayer, opID, expireTime)
-        elif opType == "del":
-            isOK = PlayerFace.DelFacePic(curPlayer, opID)
-        elif opType == "starUp":
-            isOK, errorMsg = PlayerFace.GMSetFacePicStar(curPlayer, opID)
-        elif opType == "setStar":
-            isOK, errorMsg = PlayerFace.GMSetFacePicStar(curPlayer, opID, setValue)
-        elif opType == "query":
-            isOK = True
-        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, opID)
-        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicEndTime % opID)
-        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % opID)
-        
-    if not isOK:
-        if errorMsg:
-            errorMsg = "%s %s fail! %s" % (opType, faceType, errorMsg)
-        else:
-            errorMsg = "%s %s fail! Please check that the ID(%s) is correct." % (opType, faceType, opID)
-        GameWorld.Log("GMT_Face, errorMsg=%s" % errorMsg, curPlayer.GetPlayerID())
-        resultMsg = str([orderId, errorMsg, 'GMT_Face', GMCommon.Def_Unknow])
-        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'GMToolResult', resultMsg, len(resultMsg))
-        return
-    
-    endTimeStr = "未激活"
-    if state:
-        endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
-    resultDict = {"opID":opID, "expireTime":expireTime, "isOnlineGMT":isOnlineGMT, "opType":opType, 
-                  "faceType":faceType, "state":state, "endTimeStr":endTimeStr, "star":star}
-    GameWorld.Log("GMT_Face, isOnlineGMT=%s,resultDict=%s" % (isOnlineGMT, resultDict), curPlayer.GetPlayerID())
-    #流向 记录
-    DataRecordPack.DR_ToolGMOperate(query_ID, curPlayer.GetPlayerName(), curPlayer.GetAccID(), 'GMT_Face', resultDict)
-    
-    if isOnlineGMT:
-        resultMsg = str([orderId, resultDict, 'GMT_Face', Result])
-        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'GMToolResult', resultMsg, len(resultMsg))
-        
-    return
-
-#---------------------------------------------------------------------
-#执行结果
-## 执行结果
-#  @param curPlayer 发出请求的玩家
-#  @param callFunName 功能名称
-#  @param funResult 查询的结果
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def DoResult(curPlayer, callFunName, funResult, tick):
-    return
-
-
-
-
-
-
-
-
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index de5ba70..10fa567 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -109,7 +109,6 @@
 g_crossRegPlayerAttrDict = {} #跨服注册时登记的会影响战力的属性值 {playerID:[value, ...], ...}
 g_crossSyncTickDict = {} #需要同步跨服数据的玩家同步tick字典 {playerID:tick, ...}
 g_crossPlayerDictChangeInfo = {} #跨服玩家字典变化信息 {playerID:{(key, dType):value, ...}, ...}
-g_crossPlayerDienstgradChangeInfo = {} #跨服玩家称号变化信息 {playerID:{id:isAdd, ...}, ...}
 g_crossPlayerItemsChangeInfo = {} #跨服玩家物品变化信息 {playerID:{"背包类型-物品位":itemMD5, ...}, ...}
 g_crossPlayerSkillsChangeInfo = {} #跨服玩家技能变化信息 {playerID:[技能ID], ...}
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/GMToolLogicProcess/Commands/GMT_Face.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/GMToolLogicProcess/Commands/GMT_Face.py
new file mode 100644
index 0000000..fbe6332
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/GMToolLogicProcess/Commands/GMT_Face.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package PyMongoDB.GMToolLogicProcess.Commands.GMT_Face
+#
+# @todo:GM工具命令 - 幻境阁
+# @author hxp
+# @date 2025-10-15
+# @version 1.0
+#
+# 详细描述: GM工具命令 - 幻境阁
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-10-15 09:30"""
+#-------------------------------------------------------------------------------
+
+import GMCommon
+import GameWorld
+import PlayerFace
+import PlayerHJG
+import ChConfig
+
+## 收到gm命令执行
+# @param gmCmdDict:gm命令字典
+# @return None 
+def OnExec(gmCmdDict):
+    #命令测试没通过,后续再调试
+    GameWorld.Log("GMT_Face: %s" % gmCmdDict)
+    errorMsg = ""
+    from GMToolLogicProcess import  ProjSpecialProcess
+    Result, curPlayer = ProjSpecialProcess.GMCmdPlayerValidation(gmCmdDict, False)
+    if Result != GMCommon.Def_Success:
+        return Result, errorMsg
+    
+    faceType = gmCmdDict.get('faceType', '')
+    opType = gmCmdDict.get('opType', '')
+    opID = GameWorld.ToIntDef(gmCmdDict.get('opID', '0'))
+    expireTime = GameWorld.ToIntDef(gmCmdDict.get('expireTime', '0'))
+    setValue = GameWorld.ToIntDef(gmCmdDict.get('setValue', '0'))
+    
+    state, endTime, star = 0, 0, 0
+    isOK = False
+    errorMsg = ""
+    if faceType == "face":
+        if opType == "add":
+            isOK = PlayerFace.AddFace(curPlayer, opID, expireTime, isFree=True)
+        elif opType == "del":
+            isOK = PlayerFace.DelFace(curPlayer, opID)
+        elif opType == "starUp":
+            setValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % opID) + 1
+            isOK = PlayerFace.SetFaceStar(curPlayer, opID, setValue)
+        elif opType == "setStar":
+            isOK = PlayerFace.SetFaceStar(curPlayer, opID, setValue)
+        elif opType == "query":
+            isOK = True
+        state = PlayerFace.IsFaceCanUse(curPlayer, opID)
+        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceEndTime % opID)
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FaceStar % opID)
+    elif faceType == "facePic":
+        if opType == "add":
+            isOK = PlayerFace.AddFacePic(curPlayer, opID, expireTime, isFree=True)
+        elif opType == "del":
+            isOK = PlayerFace.DelFacePic(curPlayer, opID)
+        elif opType == "starUp":
+            setValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % opID) + 1
+            isOK = PlayerFace.SetFacePicStar(curPlayer, opID, setValue)
+        elif opType == "setStar":
+            isOK = PlayerFace.SetFacePicStar(curPlayer, opID, setValue)
+        elif opType == "query":
+            isOK = True
+        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_FacePicState, opID)
+        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicEndTime % opID)
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FacePicStar % opID)
+    elif faceType == "title":
+        if opType == "add":
+            isOK = PlayerHJG.AddTitle(curPlayer, opID, expireTime, isFree=True)
+        elif opType == "del":
+            isOK = PlayerHJG.DelTitle(curPlayer, opID)
+        elif opType == "starUp":
+            setValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % opID) + 1
+            isOK = PlayerHJG.SetTitleStar(curPlayer, opID, setValue)
+        elif opType == "setStar":
+            isOK = PlayerHJG.SetTitleStar(curPlayer, opID, setValue)
+        elif opType == "query":
+            isOK = True
+        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_TitleState, opID)
+        endTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleEndTime % opID)
+        star = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TitleStar % opID)
+        
+    if not isOK:
+        if errorMsg:
+            errorMsg = "%s %s fail! %s" % (opType, faceType, errorMsg)
+        else:
+            errorMsg = "%s %s fail! Please check that the ID(%s) is correct." % (opType, faceType, opID)
+        return GMCommon.Def_ParamErr, errorMsg
+    
+    endTimeStr = "未激活"
+    if state:
+        endTimeStr = "永久" if not endTime else GameWorld.ChangeTimeNumToStr(endTime)
+    resultDict = {"opID":opID, "expireTime":expireTime, "opType":opType, 
+                  "faceType":faceType, "state":state, "endTimeStr":endTimeStr, "star":star}
+    GameWorld.Log("GMT_Face: resultDict=%s" % resultDict, curPlayer.GetPlayerID())
+    return Result, resultDict

--
Gitblit v1.8.0