From fdebf36f0d9201c6a6949a08cdfeebb718c25ce2 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 23 五月 2025 19:35:53 +0800
Subject: [PATCH] 16 卡牌服务端(聊天、广播、通用记录、查看玩家;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CreateFamily.py                   |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/CollectionDefine.py     |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini                                           |   40 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py                        |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBGameRec.py                    |  383 +++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                                |  416 +-----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                            |  848 ++++++------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                                 |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py                     |   12 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_PlayerMirror.py   |   43 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py                   |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py                          |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                            |   10 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBPlayerViewCache.py            |  176 --
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                       |   18 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py                          |  716 ++--------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py                        |    8 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                                |   53 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py                     |  298 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py      |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/LogicProcess/UserCtrlDB.py          |   34 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py                               |    9 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py                              |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/DataServerPlayerData.py |  218 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py                         |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTJG.py                           |    4 
 /dev/null                                                                                                         |  493 -------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                        |   31 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py                    |    1 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py                                  |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py                  |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py                                |  133 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                   |   44 
 33 files changed, 1,855 insertions(+), 2,177 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index 1ed0e32..4c272c7 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -960,7 +960,7 @@
 
 ;玩家查看数据缓存
 [PlayerViewCache]
-ScriptName = Player\PlayerViewCacheTube.py
+ScriptName = Player\PlayerViewCache.py
 Writer = xmnathan
 Releaser = xmnathan
 RegType = 0
@@ -1121,20 +1121,11 @@
 Writer = hxp
 Releaser = hxp
 RegType = 0
-RegisterPackCount = 3
+RegisterPackCount = 1
 
-PacketCMD_1=0xA2
-PacketSubCMD_1=0x16
-PacketCallFunc_1=OnPyTalk
-
-PacketCMD_2=0xA2
-PacketSubCMD_2=0x17
-PacketCallFunc_2=OnUsePYSpeaker
-
-PacketCMD_3=0xA2
-PacketSubCMD_3=0x26
-PacketCallFunc_3=OnVoiceChat
-
+PacketCMD_1=0xB3
+PacketSubCMD_1=0x20
+PacketCallFunc_1=OnTalk
 
 ;属性果实
 [PlayerAttrFruit]
@@ -1588,18 +1579,6 @@
 PacketCMD_5=0xA5
 PacketSubCMD_5=0xC4
 PacketCallFunc_5=OnDogzEquipPlus
-
-;个推
-[PlayerGeTui]
-ScriptName = Player\PlayerGeTui.py
-Writer = Alee
-Releaser = Alee
-RegType = 0
-RegisterPackCount = 1
-
-PacketCMD_1=0xB2
-PacketSubCMD_1=0x5
-PacketCallFunc_1=GeTuiSetting
 
 ;充值
 [PlayerCoin]
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
index c0d28cd..72366ae 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
@@ -524,46 +524,6 @@
 PacketSubCMD_1=0x3
 PacketCallFunc_1=PetStateChange
 
-
-;聊天
-[Talk]
-ScriptName = Player\PlayerTalk.py
-Writer = Mark
-Releaser = Mark
-RegType = 0
-RegisterPackCount = 7
-
-PacketCMD_1=0x2
-PacketSubCMD_1=0x7
-PacketCallFunc_1=TalkArea
-
-
-PacketCMD_2=0x2
-PacketSubCMD_2=0x3
-PacketCallFunc_2=TalkFamily
-
-PacketCMD_3=0x2
-PacketSubCMD_3=0x5
-PacketCallFunc_3=TalkTeam
-
-
-PacketCMD_4=0x2
-PacketSubCMD_4=0x1
-PacketCallFunc_4=TalkWorld
-
-PacketCMD_5=0x2
-PacketSubCMD_5=0x6
-PacketCallFunc_5=TalkPrivateName
-
-PacketCMD_6=0x2
-PacketSubCMD_6=0x9
-PacketCallFunc_6=TalkPrivate
-
-PacketCMD_7=0x2
-PacketSubCMD_7=0x8
-PacketCallFunc_7=TalkCountry
-
-
 ;战斗
 [Battle]
 ScriptName = Player\PlayerBattle.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py
index 848d310..e71314d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py
@@ -40,7 +40,6 @@
 import ChNetSendPack
 import NetPackCommon
 import PassiveBuffEffMng
-import PlayerGeTui
 import IpyGameDataPY
 #---------------------------------------------------------------------
 g_skillHurtList = IPY_GameWorld.IPY_HurtList()
@@ -363,7 +362,6 @@
     if GameObj.GetHP(defender) <= 0:
         defender.SetDict(ChConfig.Def_NPCDead_KillerType, attacker.GetGameObjType())
         defender.SetDict(ChConfig.Def_NPCDead_KillerID, attacker.GetID())
-        #PlayerGeTui.TJGDead(defender, attacker.GetName())
         if defender.GetGameObjType() == IPY_GameWorld.gotNPC:
             skillID = 0 if not useSkill else useSkill.GetSkillID()
             # 记录死亡原因
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py
index 4430e63..179e455 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py
@@ -27,7 +27,6 @@
 import IPY_GameWorld
 import PlayerControl
 import OperControlManager
-import PlayerViewCacheTube
 import PassiveBuffEffMng
 import GameWorldProcess
 import ChNetSendPack
@@ -38,7 +37,6 @@
 import SkillShell
 import CommFunc
 import FBCommon
-import PlayerFB
 import GameMap
 import FBLogic
 import GameObj
@@ -449,7 +447,7 @@
 #};
 def OnSycnPlayerPackData(index, clientData, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, forcePackData=True)
+    #PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, forcePackData=True)
     return
 
 #// B4 11 镜像战斗 #tagCMMirrorFight
@@ -562,8 +560,8 @@
         return True
     
     # 玩家自身需要用镜像的情况
-    if isSysbg and playerID and playerID in mirrorIDList:
-        PlayerViewCacheTube.NormalSyncPackData(curPlayer)
+    #if isSysbg and playerID and playerID in mirrorIDList:
+    #    PlayerViewCacheTube.NormalSyncPackData(curPlayer)
         
     sendMsg = str(sendMsg)
     GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "ReuestPlayerPackData", sendMsg, len(sendMsg))
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 0e29885..8272077 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -2170,34 +2170,9 @@
 Def_NPCErrorMaxDist = 99999
 
 #玩家聊天-------------------------------------------
-#聊天通用间隔时间
-Def_PlayerTalkTick = 1000
-#玩家聊天频道最大个数
-Def_PlayerTalkChannelMaxCount = 10
-#玩家聊天,单句最大字节数
-Def_PlayerTalkMaxCount = 8000           #原来为100
-#轻频频道
-#轻频频道相同内容允许时间(10秒2次)
-Def_PlayerTalkQingTime = 5000
-#区域频道
-#区域聊天频道时间间隔(1秒)
-Def_PlayerTalkAreaTime = 1000           #原来为180000 目前测试
-#区域聊天频道等级限制
-Def_PlayerTalkAreaLV = 1
-#国家频道
-#国家聊天频道时间间隔(10秒)
-Def_PlayerTalkCountryTime = 10000        #文档中为18000
-#国家聊天频道等级限制
-Def_PlayerTalkCountryLV = 41
-#国家频道聊天花费
-Def_PlayerTalkCoutryMoney = 10
-#世界频道
-#世界频道聊天花费(银子或银票)
-Def_PlayerTalkWorldMoney = 1000
-#世界聊天时间间隔(1秒)
-Def_PlayerTalkWorldTime = 1000
-#不可以轻频聊天的地图
-CanNotQingTalkMapIDList = []
+Def_PlayerTalkTick = 1000 #聊天通用间隔时间
+Def_PlayerTalkMaxCount = 8000   #玩家聊天,单句最大字节数
+Def_ChannelTalkTick = "ChannelTalkTick_%s" # 聊天频道玩家最近一次聊天tick
 
 ###################################################
 #类型定义, 以下内容不要修改
@@ -2713,19 +2688,6 @@
 ) = range(0, Def_QueryType_Count)
 #------------------------------------------------------------------------------ 
 
-#家族某行为类型保存的条数
-ActionTypeSaveCnt = {
-              ShareDefine.Def_ActionType_FamilyPray:10 ,    #家族祈福
-              ShareDefine.Def_ActionType_FamilyArrest:7,     #家族悬赏
-              ShareDefine.Def_ActionType_FamilyMember:1,       #记录家族成员信息
-              ShareDefine.Def_ActionType_LeaderImpeachTime:1,  # 族长下线了多久
-              ShareDefine.Def_ActionType_FamilyBossFB:1,  # 记录家族boss副本信息
-              ShareDefine.Def_ActionType_FamilyStore:30,       #仓库操作记录
-              ShareDefine.Def_ActionType_OfficerModelEquip:10,  # 记录家族有职位的成员模型装备信息(盟主+副盟主*2+战斗队长*5)
-              ShareDefine.Def_ActionType_FamilyEvent:50,  # 记录家族事件
-              }
-
-#---------------------------------------------------------------------
 #数值上限 2^31 - 1
 Def_UpperLimit_DWordEx = ShareDefine.Def_UpperLimit_DWordEx
 #数值上限(20亿)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 4d586a9..09a8e73 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -3145,101 +3145,6 @@
 
 
 #------------------------------------------------------
-#B3 07 语音聊天 #tagCGVoiceChat
-
-class  tagCGVoiceChat(Structure):
-    Head = tagHead()
-    ChannelType = 0    #(BYTE ChannelType)// 1 世界 2 仙盟 3 私聊(好友) 4 队伍 -------查看封包tagCMVoiceChat 5 区域	
-    TargetNameLen = 0    #(BYTE TargetNameLen)
-    TargetName = ""    #(String TargetName)//size = TargetNameLen
-    TargetID = 0    #(DWORD TargetID)// 默认发玩家ID,没有ID才发名称
-    Len = 0    #(WORD Len)
-    Content = list()    #(vector<BYTE> Content)//size = Len
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xB3
-        self.Head.SubCmd = 0x07
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.TargetNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.TargetName,_pos = CommFunc.ReadString(_lpData, _pos,self.TargetNameLen)
-        self.TargetID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        for i in range(self.Len):
-            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
-            self.Content.append(value)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xB3
-        self.Head.SubCmd = 0x07
-        self.ChannelType = 0
-        self.TargetNameLen = 0
-        self.TargetName = ""
-        self.TargetID = 0
-        self.Len = 0
-        self.Content = list()
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        length += 1
-        length += len(self.TargetName)
-        length += 4
-        length += 2
-        length += 1 * self.Len
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.ChannelType)
-        data = CommFunc.WriteBYTE(data, self.TargetNameLen)
-        data = CommFunc.WriteString(data, self.TargetNameLen, self.TargetName)
-        data = CommFunc.WriteDWORD(data, self.TargetID)
-        data = CommFunc.WriteWORD(data, self.Len)
-        for i in range(self.Len):
-            data = CommFunc.WriteBYTE(data, self.Content[i])
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                ChannelType:%d,
-                                TargetNameLen:%d,
-                                TargetName:%s,
-                                TargetID:%d,
-                                Len:%d,
-                                Content:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.ChannelType,
-                                self.TargetNameLen,
-                                self.TargetName,
-                                self.TargetID,
-                                self.Len,
-                                "..."
-                                )
-        return DumpString
-
-
-m_NAtagCGVoiceChat=tagCGVoiceChat()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGVoiceChat.Head.Cmd,m_NAtagCGVoiceChat.Head.SubCmd))] = m_NAtagCGVoiceChat
-
-
-#------------------------------------------------------
 #B3 03 是否允许加入好友的回应#tagCGJoinFriendAnswer
 
 class  tagCGJoinFriendAnswer(Structure):
@@ -6241,7 +6146,7 @@
                   ("GroupValue2", c_int),    #分组值2,与分组值1组合归为同组榜单数据
                   ("StartIndex", c_ushort),    #查看的起始名次索引, 默认0
                   ("ViewCnt", c_ubyte),    #查看条数,默认20,单次最大不超过100
-                  ("ViewID", c_int),    #附带查看指定ID所在名次前后数据,如玩家ID、家族ID等,仅首页查询时有效,即StartIndex为0时
+                  ("ViewID", c_int),    #附带查看指定ID所在名次前后数据,如玩家ID、家族ID等
                   ]
 
     def __init__(self):
@@ -7124,162 +7029,6 @@
 
 
 #------------------------------------------------------
-# A2 17 喇叭聊天 #tagCMPYSpeaker
-
-class  tagCMPYSpeaker(Structure):
-    Head = tagHead()
-    SpeakerType = 0    #(BYTE SpeakerType)//1-本服;2-跨服
-    IsUseGold = 0    #(BYTE IsUseGold)//是否使用钻石
-    ItemIndex = 0    #(BYTE ItemIndex)//使用物品说话时, 物品Index
-    TextLen = 0    #(WORD TextLen)//字符长度
-    Text = ""    #(String Text)//size = TextLen
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xA2
-        self.Head.SubCmd = 0x17
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.SpeakerType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.IsUseGold,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.ItemIndex,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.TextLen,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        self.Text,_pos = CommFunc.ReadString(_lpData, _pos,self.TextLen)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xA2
-        self.Head.SubCmd = 0x17
-        self.SpeakerType = 0
-        self.IsUseGold = 0
-        self.ItemIndex = 0
-        self.TextLen = 0
-        self.Text = ""
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        length += 1
-        length += 1
-        length += 2
-        length += len(self.Text)
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.SpeakerType)
-        data = CommFunc.WriteBYTE(data, self.IsUseGold)
-        data = CommFunc.WriteBYTE(data, self.ItemIndex)
-        data = CommFunc.WriteWORD(data, self.TextLen)
-        data = CommFunc.WriteString(data, self.TextLen, self.Text)
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                SpeakerType:%d,
-                                IsUseGold:%d,
-                                ItemIndex:%d,
-                                TextLen:%d,
-                                Text:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.SpeakerType,
-                                self.IsUseGold,
-                                self.ItemIndex,
-                                self.TextLen,
-                                self.Text
-                                )
-        return DumpString
-
-
-m_NAtagCMPYSpeaker=tagCMPYSpeaker()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMPYSpeaker.Head.Cmd,m_NAtagCMPYSpeaker.Head.SubCmd))] = m_NAtagCMPYSpeaker
-
-
-#------------------------------------------------------
-# A2 16 自定义玩家聊天 #tagCMPyTalk
-
-class  tagCMPyTalk(Structure):
-    Head = tagHead()
-    TalkType = 0    #(BYTE TalkType)// 自定义聊天类型
-    Len = 0    #(WORD Len)
-    Content = ""    #(String Content)//size = Len
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xA2
-        self.Head.SubCmd = 0x16
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.TalkType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        self.Content,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xA2
-        self.Head.SubCmd = 0x16
-        self.TalkType = 0
-        self.Len = 0
-        self.Content = ""
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        length += 2
-        length += len(self.Content)
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.TalkType)
-        data = CommFunc.WriteWORD(data, self.Len)
-        data = CommFunc.WriteString(data, self.Len, self.Content)
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                TalkType:%d,
-                                Len:%d,
-                                Content:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.TalkType,
-                                self.Len,
-                                self.Content
-                                )
-        return DumpString
-
-
-m_NAtagCMPyTalk=tagCMPyTalk()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMPyTalk.Head.Cmd,m_NAtagCMPyTalk.Head.SubCmd))] = m_NAtagCMPyTalk
-
-
-#------------------------------------------------------
 #A2 11 查询世界Boss伤血列表 #tagCMQueryBossHurtList
 
 class  tagCMQueryBossHurtList(Structure):
@@ -8123,101 +7872,6 @@
 
 m_NAtagCMClientTaskCount=tagCMClientTaskCount()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMClientTaskCount.Cmd,m_NAtagCMClientTaskCount.SubCmd))] = m_NAtagCMClientTaskCount
-
-
-#------------------------------------------------------
-#A2 26 语音聊天 #tagCMVoiceChat
-
-class  tagCMVoiceChat(Structure):
-    Head = tagHead()
-    ChannelType = 0    #(BYTE ChannelType)//  5 区域 --- 查看封包tagCGVoiceChat 1 世界 2 仙盟 3 私聊(好友) 4 队伍
-    TargetNameLen = 0    #(BYTE TargetNameLen)
-    TargetName = ""    #(String TargetName)//size = TargetNameLen
-    TargetID = 0    #(DWORD TargetID)// 私聊默认发玩家ID,没有ID才发名称
-    Len = 0    #(WORD Len)
-    Content = list()    #(vector<BYTE> Content)//size = Len
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xA2
-        self.Head.SubCmd = 0x26
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.TargetNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.TargetName,_pos = CommFunc.ReadString(_lpData, _pos,self.TargetNameLen)
-        self.TargetID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        for i in range(self.Len):
-            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
-            self.Content.append(value)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xA2
-        self.Head.SubCmd = 0x26
-        self.ChannelType = 0
-        self.TargetNameLen = 0
-        self.TargetName = ""
-        self.TargetID = 0
-        self.Len = 0
-        self.Content = list()
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        length += 1
-        length += len(self.TargetName)
-        length += 4
-        length += 2
-        length += 1 * self.Len
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.ChannelType)
-        data = CommFunc.WriteBYTE(data, self.TargetNameLen)
-        data = CommFunc.WriteString(data, self.TargetNameLen, self.TargetName)
-        data = CommFunc.WriteDWORD(data, self.TargetID)
-        data = CommFunc.WriteWORD(data, self.Len)
-        for i in range(self.Len):
-            data = CommFunc.WriteBYTE(data, self.Content[i])
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                ChannelType:%d,
-                                TargetNameLen:%d,
-                                TargetName:%s,
-                                TargetID:%d,
-                                Len:%d,
-                                Content:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.ChannelType,
-                                self.TargetNameLen,
-                                self.TargetName,
-                                self.TargetID,
-                                self.Len,
-                                "..."
-                                )
-        return DumpString
-
-
-m_NAtagCMVoiceChat=tagCMVoiceChat()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMVoiceChat.Head.Cmd,m_NAtagCMVoiceChat.Head.SubCmd))] = m_NAtagCMVoiceChat
 
 
 #------------------------------------------------------
@@ -21924,6 +21578,74 @@
 
 
 #------------------------------------------------------
+# B3 20 聊天 #tagCMTalk
+
+class  tagCMPyTalk(Structure):
+    Head = tagHead()
+    ChannelType = 0    #(BYTE ChannelType)// 频道
+    Len = 0    #(WORD Len)
+    Content = ""    #(String Content)//size = Len
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB3
+        self.Head.SubCmd = 0x20
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Content,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB3
+        self.Head.SubCmd = 0x20
+        self.ChannelType = 0
+        self.Len = 0
+        self.Content = ""
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 2
+        length += len(self.Content)
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ChannelType)
+        data = CommFunc.WriteWORD(data, self.Len)
+        data = CommFunc.WriteString(data, self.Len, self.Content)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ChannelType:%d,
+                                Len:%d,
+                                Content:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ChannelType,
+                                self.Len,
+                                self.Content
+                                )
+        return DumpString
+
+
+
+#------------------------------------------------------
 # B4 11 镜像战斗 #tagCMMirrorFight
 
 class  tagCMMirrorFight(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 3cfdf96..cabf022 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -11547,292 +11547,6 @@
 
 
 #------------------------------------------------------
-#B3 10 语音聊天 #tagGCVoiceChat
-
-class  tagGCVoiceChat(Structure):
-    Head = tagHead()
-    ChannelType = 0    #(BYTE ChannelType)// 1 世界 2 仙盟 3 私聊(好友) 4 队伍 5 区域	
-    SrcNameLen = 0    #(BYTE SrcNameLen)
-    SrcName = ""    #(String SrcName)//size = SrcNameLen
-    PlayerID = 0    #(DWORD PlayerID)
-    ToNameLen = 0    #(BYTE ToNameLen)
-    ToName = ""    #(String ToName)//size = ToNameLen
-    ToPlayerID = 0    #(DWORD ToPlayerID)
-    Len = 0    #(WORD Len)
-    Content = list()    #(vector<BYTE> Content)//size = Len
-    ExtraValue = 0    #(DWORD ExtraValue)//附加值
-    Extras = ""    #(char Extras[256])//附加值列表
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xB3
-        self.Head.SubCmd = 0x10
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.SrcNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.SrcName,_pos = CommFunc.ReadString(_lpData, _pos,self.SrcNameLen)
-        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.ToNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.ToName,_pos = CommFunc.ReadString(_lpData, _pos,self.ToNameLen)
-        self.ToPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        for i in range(self.Len):
-            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
-            self.Content.append(value)
-        self.ExtraValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Extras,_pos = CommFunc.ReadString(_lpData, _pos,256)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xB3
-        self.Head.SubCmd = 0x10
-        self.ChannelType = 0
-        self.SrcNameLen = 0
-        self.SrcName = ""
-        self.PlayerID = 0
-        self.ToNameLen = 0
-        self.ToName = ""
-        self.ToPlayerID = 0
-        self.Len = 0
-        self.Content = list()
-        self.ExtraValue = 0
-        self.Extras = ""
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        length += 1
-        length += len(self.SrcName)
-        length += 4
-        length += 1
-        length += len(self.ToName)
-        length += 4
-        length += 2
-        length += 1 * self.Len
-        length += 4
-        length += 256
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.ChannelType)
-        data = CommFunc.WriteBYTE(data, self.SrcNameLen)
-        data = CommFunc.WriteString(data, self.SrcNameLen, self.SrcName)
-        data = CommFunc.WriteDWORD(data, self.PlayerID)
-        data = CommFunc.WriteBYTE(data, self.ToNameLen)
-        data = CommFunc.WriteString(data, self.ToNameLen, self.ToName)
-        data = CommFunc.WriteDWORD(data, self.ToPlayerID)
-        data = CommFunc.WriteWORD(data, self.Len)
-        for i in range(self.Len):
-            data = CommFunc.WriteBYTE(data, self.Content[i])
-        data = CommFunc.WriteDWORD(data, self.ExtraValue)
-        data = CommFunc.WriteString(data, 256, self.Extras)
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                ChannelType:%d,
-                                SrcNameLen:%d,
-                                SrcName:%s,
-                                PlayerID:%d,
-                                ToNameLen:%d,
-                                ToName:%s,
-                                ToPlayerID:%d,
-                                Len:%d,
-                                Content:%s,
-                                ExtraValue:%d,
-                                Extras:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.ChannelType,
-                                self.SrcNameLen,
-                                self.SrcName,
-                                self.PlayerID,
-                                self.ToNameLen,
-                                self.ToName,
-                                self.ToPlayerID,
-                                self.Len,
-                                "...",
-                                self.ExtraValue,
-                                self.Extras
-                                )
-        return DumpString
-
-
-m_NAtagGCVoiceChat=tagGCVoiceChat()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCVoiceChat.Head.Cmd,m_NAtagGCVoiceChat.Head.SubCmd))] = m_NAtagGCVoiceChat
-
-
-#------------------------------------------------------
-# B3 11 聊天缓存通知 #tagGCTalkCache
-
-class  tagGCTalkCacheInfo(Structure):
-    ChannelType = 0    #(BYTE ChannelType)// 1 世界 2 仙盟
-    NameLen = 0    #(BYTE NameLen)
-    Name = ""    #(String Name)//size = SrcNameLen
-    PlayerID = 0    #(DWORD PlayerID)
-    Time = 0    #(DWORD Time)
-    Len = 0    #(WORD Len)
-    Content = ""    #(String Content)//size = Len
-    Extras = ""    #(char Extras[256])//附加值列表
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.Name,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
-        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Time,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        self.Content,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
-        self.Extras,_pos = CommFunc.ReadString(_lpData, _pos,256)
-        return _pos
-
-    def Clear(self):
-        self.ChannelType = 0
-        self.NameLen = 0
-        self.Name = ""
-        self.PlayerID = 0
-        self.Time = 0
-        self.Len = 0
-        self.Content = ""
-        self.Extras = ""
-        return
-
-    def GetLength(self):
-        length = 0
-        length += 1
-        length += 1
-        length += len(self.Name)
-        length += 4
-        length += 4
-        length += 2
-        length += len(self.Content)
-        length += 256
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteBYTE(data, self.ChannelType)
-        data = CommFunc.WriteBYTE(data, self.NameLen)
-        data = CommFunc.WriteString(data, self.NameLen, self.Name)
-        data = CommFunc.WriteDWORD(data, self.PlayerID)
-        data = CommFunc.WriteDWORD(data, self.Time)
-        data = CommFunc.WriteWORD(data, self.Len)
-        data = CommFunc.WriteString(data, self.Len, self.Content)
-        data = CommFunc.WriteString(data, 256, self.Extras)
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                ChannelType:%d,
-                                NameLen:%d,
-                                Name:%s,
-                                PlayerID:%d,
-                                Time:%d,
-                                Len:%d,
-                                Content:%s,
-                                Extras:%s
-                                '''\
-                                %(
-                                self.ChannelType,
-                                self.NameLen,
-                                self.Name,
-                                self.PlayerID,
-                                self.Time,
-                                self.Len,
-                                self.Content,
-                                self.Extras
-                                )
-        return DumpString
-
-
-class  tagGCTalkCache(Structure):
-    Head = tagHead()
-    Count = 0    #(WORD Count)
-    InfoList = list()    #(vector<tagGCTalkCacheInfo> InfoList)//size = Count
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xB3
-        self.Head.SubCmd = 0x11
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        for i in range(self.Count):
-            temInfoList = tagGCTalkCacheInfo()
-            _pos = temInfoList.ReadData(_lpData, _pos)
-            self.InfoList.append(temInfoList)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xB3
-        self.Head.SubCmd = 0x11
-        self.Count = 0
-        self.InfoList = list()
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 2
-        for i in range(self.Count):
-            length += self.InfoList[i].GetLength()
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteWORD(data, self.Count)
-        for i in range(self.Count):
-            data = CommFunc.WriteString(data, self.InfoList[i].GetLength(), self.InfoList[i].GetBuffer())
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                Count:%d,
-                                InfoList:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.Count,
-                                "..."
-                                )
-        return DumpString
-
-
-m_NAtagGCTalkCache=tagGCTalkCache()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCTalkCache.Head.Cmd,m_NAtagGCTalkCache.Head.SubCmd))] = m_NAtagGCTalkCache
-
-
-#------------------------------------------------------
 # B5 04 拍卖行新上架拍品 #tagGCAddAuctionItemInfo
 
 class  tagGCAddAuctionItem(Structure):
@@ -36251,112 +35965,6 @@
 
 
 #------------------------------------------------------
-# A7 07 通知玩家自定义聊天 #tagMCPyTalk
-
-class  tagMCPyTalk(Structure):
-    Head = tagHead()
-    TalkType = 0    #(BYTE TalkType)// 自定义聊天类型
-    NameLen = 0    #(BYTE NameLen)
-    Name = ""    #(String Name)//size = NameLen
-    PlayerID = 0    #(DWORD PlayerID)
-    Len = 0    #(WORD Len)
-    Content = ""    #(String Content)//size = Len
-    ExtraValue = 0    #(DWORD ExtraValue)//附加值
-    Extras = ""    #(char Extras[256])//附加值列表
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        self.Head.Cmd = 0xA7
-        self.Head.SubCmd = 0x07
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        _pos = self.Head.ReadData(_lpData, _pos)
-        self.TalkType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.Name,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
-        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        self.Content,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
-        self.ExtraValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.Extras,_pos = CommFunc.ReadString(_lpData, _pos,256)
-        return _pos
-
-    def Clear(self):
-        self.Head = tagHead()
-        self.Head.Clear()
-        self.Head.Cmd = 0xA7
-        self.Head.SubCmd = 0x07
-        self.TalkType = 0
-        self.NameLen = 0
-        self.Name = ""
-        self.PlayerID = 0
-        self.Len = 0
-        self.Content = ""
-        self.ExtraValue = 0
-        self.Extras = ""
-        return
-
-    def GetLength(self):
-        length = 0
-        length += self.Head.GetLength()
-        length += 1
-        length += 1
-        length += len(self.Name)
-        length += 4
-        length += 2
-        length += len(self.Content)
-        length += 4
-        length += 256
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.TalkType)
-        data = CommFunc.WriteBYTE(data, self.NameLen)
-        data = CommFunc.WriteString(data, self.NameLen, self.Name)
-        data = CommFunc.WriteDWORD(data, self.PlayerID)
-        data = CommFunc.WriteWORD(data, self.Len)
-        data = CommFunc.WriteString(data, self.Len, self.Content)
-        data = CommFunc.WriteDWORD(data, self.ExtraValue)
-        data = CommFunc.WriteString(data, 256, self.Extras)
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                Head:%s,
-                                TalkType:%d,
-                                NameLen:%d,
-                                Name:%s,
-                                PlayerID:%d,
-                                Len:%d,
-                                Content:%s,
-                                ExtraValue:%d,
-                                Extras:%s
-                                '''\
-                                %(
-                                self.Head.OutputString(),
-                                self.TalkType,
-                                self.NameLen,
-                                self.Name,
-                                self.PlayerID,
-                                self.Len,
-                                self.Content,
-                                self.ExtraValue,
-                                self.Extras
-                                )
-        return DumpString
-
-
-m_NAtagMCPyTalk=tagMCPyTalk()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCPyTalk.Head.Cmd,m_NAtagMCPyTalk.Head.SubCmd))] = m_NAtagMCPyTalk
-
-
-#------------------------------------------------------
 # A7 08 通知跑环奖励记录 #tagMCRunTaskAwardInfo
 
 class  tagMCRunTaskAwardRecord(Structure):
@@ -36473,11 +36081,20 @@
 
 class  tagSCQueryPlayerCacheResult(Structure):
     Head = tagHead()
-    PlayerID = 0    #(DWORD PlayerID)//玩家ID
-    PropDataSize = 0    #(DWORD PropDataSize)
-    PropData = ""    #(String PropData)//属性记录
-    ItemDataSize = 0    #(DWORD ItemDataSize)
-    ItemData = ""    #(String ItemData)//物品记录
+    PlayerID = 0    #(DWORD PlayerID)
+    PlayerName = ""    #(char PlayerName[33])
+    LV = 0    #(WORD LV)
+    Job = 0    #(BYTE Job)
+    RealmLV = 0    #(BYTE RealmLV)
+    Face = 0    #(DWORD Face)
+    FacePic = 0    #(DWORD FacePic)
+    TitleID = 0    #(DWORD TitleID)//佩戴的称号
+    ServerID = 0    #(DWORD ServerID)
+    FightPower = 0    #(DWORD FightPower)
+    FightPowerEx = 0    #(DWORD FightPowerEx)
+    FamilyID = 0    #(DWORD FamilyID)
+    FamilyName = ""    #(char FamilyName[33])
+    FamilyEmblemID = 0    #(DWORD FamilyEmblemID)//仙盟徽章ID
     PlusDataSize = 0    #(DWORD PlusDataSize)
     PlusData = ""    #(String PlusData)//扩展记录	
     data = None
@@ -36492,10 +36109,19 @@
         self.Clear()
         _pos = self.Head.ReadData(_lpData, _pos)
         self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.PropDataSize,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.PropData,_pos = CommFunc.ReadString(_lpData, _pos,self.PropDataSize)
-        self.ItemDataSize,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.ItemData,_pos = CommFunc.ReadString(_lpData, _pos,self.ItemDataSize)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.TitleID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.ServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FamilyName,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.FamilyEmblemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         self.PlusDataSize,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         self.PlusData,_pos = CommFunc.ReadString(_lpData, _pos,self.PlusDataSize)
         return _pos
@@ -36506,10 +36132,19 @@
         self.Head.Cmd = 0xA7
         self.Head.SubCmd = 0x05
         self.PlayerID = 0
-        self.PropDataSize = 0
-        self.PropData = ""
-        self.ItemDataSize = 0
-        self.ItemData = ""
+        self.PlayerName = ""
+        self.LV = 0
+        self.Job = 0
+        self.RealmLV = 0
+        self.Face = 0
+        self.FacePic = 0
+        self.TitleID = 0
+        self.ServerID = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        self.FamilyID = 0
+        self.FamilyName = ""
+        self.FamilyEmblemID = 0
         self.PlusDataSize = 0
         self.PlusData = ""
         return
@@ -36518,10 +36153,19 @@
         length = 0
         length += self.Head.GetLength()
         length += 4
+        length += 33
+        length += 2
+        length += 1
+        length += 1
         length += 4
-        length += len(self.PropData)
         length += 4
-        length += len(self.ItemData)
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+        length += 33
+        length += 4
         length += 4
         length += len(self.PlusData)
 
@@ -36531,10 +36175,19 @@
         data = ''
         data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
         data = CommFunc.WriteDWORD(data, self.PlayerID)
-        data = CommFunc.WriteDWORD(data, self.PropDataSize)
-        data = CommFunc.WriteString(data, self.PropDataSize, self.PropData)
-        data = CommFunc.WriteDWORD(data, self.ItemDataSize)
-        data = CommFunc.WriteString(data, self.ItemDataSize, self.ItemData)
+        data = CommFunc.WriteString(data, 33, self.PlayerName)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteBYTE(data, self.RealmLV)
+        data = CommFunc.WriteDWORD(data, self.Face)
+        data = CommFunc.WriteDWORD(data, self.FacePic)
+        data = CommFunc.WriteDWORD(data, self.TitleID)
+        data = CommFunc.WriteDWORD(data, self.ServerID)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        data = CommFunc.WriteDWORD(data, self.FamilyID)
+        data = CommFunc.WriteString(data, 33, self.FamilyName)
+        data = CommFunc.WriteDWORD(data, self.FamilyEmblemID)
         data = CommFunc.WriteDWORD(data, self.PlusDataSize)
         data = CommFunc.WriteString(data, self.PlusDataSize, self.PlusData)
         return data
@@ -36543,20 +36196,38 @@
         DumpString = '''
                                 Head:%s,
                                 PlayerID:%d,
-                                PropDataSize:%d,
-                                PropData:%s,
-                                ItemDataSize:%d,
-                                ItemData:%s,
+                                PlayerName:%s,
+                                LV:%d,
+                                Job:%d,
+                                RealmLV:%d,
+                                Face:%d,
+                                FacePic:%d,
+                                TitleID:%d,
+                                ServerID:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d,
+                                FamilyID:%d,
+                                FamilyName:%s,
+                                FamilyEmblemID:%d,
                                 PlusDataSize:%d,
                                 PlusData:%s
                                 '''\
                                 %(
                                 self.Head.OutputString(),
                                 self.PlayerID,
-                                self.PropDataSize,
-                                self.PropData,
-                                self.ItemDataSize,
-                                self.ItemData,
+                                self.PlayerName,
+                                self.LV,
+                                self.Job,
+                                self.RealmLV,
+                                self.Face,
+                                self.FacePic,
+                                self.TitleID,
+                                self.ServerID,
+                                self.FightPower,
+                                self.FightPowerEx,
+                                self.FamilyID,
+                                self.FamilyName,
+                                self.FamilyEmblemID,
                                 self.PlusDataSize,
                                 self.PlusData
                                 )
@@ -58778,6 +58449,345 @@
 
 
 #------------------------------------------------------
+# B3 10 聊天信息 #tagMCTalk
+
+class  tagMCTalk(Structure):
+    Head = tagHead()
+    ChannelType = 0    #(BYTE ChannelType)// 0-世界;1-跨服;3- 仙盟	
+    NameLen = 0    #(BYTE NameLen)
+    Name = ""    #(String Name)//size = NameLen
+    PlayerID = 0    #(DWORD PlayerID)
+    Len = 0    #(WORD Len)
+    Content = ""    #(String Content)//size = Len
+    BubbleBox = 0    #(DWORD BubbleBox)//聊天气泡框
+    LV = 0    #(WORD LV)//等级
+    Job = 0    #(BYTE Job)//职业
+    RealmLV = 0    #(BYTE RealmLV)//境界
+    Face = 0    #(DWORD Face)//基本脸型
+    FacePic = 0    #(DWORD FacePic)//头像框
+    ServerID = 0    #(DWORD ServerID)//所属区服ID
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB3
+        self.Head.SubCmd = 0x10
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Name,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Content,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
+        self.BubbleBox,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.ServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB3
+        self.Head.SubCmd = 0x10
+        self.ChannelType = 0
+        self.NameLen = 0
+        self.Name = ""
+        self.PlayerID = 0
+        self.Len = 0
+        self.Content = ""
+        self.BubbleBox = 0
+        self.LV = 0
+        self.Job = 0
+        self.RealmLV = 0
+        self.Face = 0
+        self.FacePic = 0
+        self.ServerID = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        length += len(self.Name)
+        length += 4
+        length += 2
+        length += len(self.Content)
+        length += 4
+        length += 2
+        length += 1
+        length += 1
+        length += 4
+        length += 4
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ChannelType)
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.Name)
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteWORD(data, self.Len)
+        data = CommFunc.WriteString(data, self.Len, self.Content)
+        data = CommFunc.WriteDWORD(data, self.BubbleBox)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteBYTE(data, self.RealmLV)
+        data = CommFunc.WriteDWORD(data, self.Face)
+        data = CommFunc.WriteDWORD(data, self.FacePic)
+        data = CommFunc.WriteDWORD(data, self.ServerID)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ChannelType:%d,
+                                NameLen:%d,
+                                Name:%s,
+                                PlayerID:%d,
+                                Len:%d,
+                                Content:%s,
+                                BubbleBox:%d,
+                                LV:%d,
+                                Job:%d,
+                                RealmLV:%d,
+                                Face:%d,
+                                FacePic:%d,
+                                ServerID:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ChannelType,
+                                self.NameLen,
+                                self.Name,
+                                self.PlayerID,
+                                self.Len,
+                                self.Content,
+                                self.BubbleBox,
+                                self.LV,
+                                self.Job,
+                                self.RealmLV,
+                                self.Face,
+                                self.FacePic,
+                                self.ServerID
+                                )
+        return DumpString
+
+
+m_NAtagMCTalk=tagMCTalk()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCTalk.Head.Cmd,m_NAtagMCTalk.Head.SubCmd))] = m_NAtagMCTalk
+
+
+#------------------------------------------------------
+# B3 11 聊天缓存通知 #tagMCTalkCacheList
+
+class  tagMCTalkCacheInfo(Structure):
+    NameLen = 0    #(BYTE NameLen)
+    Name = ""    #(String Name)//size = NameLen
+    PlayerID = 0    #(DWORD PlayerID)
+    Len = 0    #(WORD Len)
+    Content = ""    #(String Content)//size = Len
+    BubbleBox = 0    #(DWORD BubbleBox)//聊天气泡框
+    LV = 0    #(WORD LV)//等级
+    Job = 0    #(BYTE Job)//职业
+    RealmLV = 0    #(BYTE RealmLV)//境界
+    Face = 0    #(DWORD Face)//基本脸型
+    FacePic = 0    #(DWORD FacePic)//头像框
+    ServerID = 0    #(DWORD ServerID)//所属区服ID
+    TalkTime = 0    #(DWORD TalkTime)//该聊天发送时间戳
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Name,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Len,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Content,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
+        self.BubbleBox,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.ServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.TalkTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.NameLen = 0
+        self.Name = ""
+        self.PlayerID = 0
+        self.Len = 0
+        self.Content = ""
+        self.BubbleBox = 0
+        self.LV = 0
+        self.Job = 0
+        self.RealmLV = 0
+        self.Face = 0
+        self.FacePic = 0
+        self.ServerID = 0
+        self.TalkTime = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += len(self.Name)
+        length += 4
+        length += 2
+        length += len(self.Content)
+        length += 4
+        length += 2
+        length += 1
+        length += 1
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.Name)
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteWORD(data, self.Len)
+        data = CommFunc.WriteString(data, self.Len, self.Content)
+        data = CommFunc.WriteDWORD(data, self.BubbleBox)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteBYTE(data, self.RealmLV)
+        data = CommFunc.WriteDWORD(data, self.Face)
+        data = CommFunc.WriteDWORD(data, self.FacePic)
+        data = CommFunc.WriteDWORD(data, self.ServerID)
+        data = CommFunc.WriteDWORD(data, self.TalkTime)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                NameLen:%d,
+                                Name:%s,
+                                PlayerID:%d,
+                                Len:%d,
+                                Content:%s,
+                                BubbleBox:%d,
+                                LV:%d,
+                                Job:%d,
+                                RealmLV:%d,
+                                Face:%d,
+                                FacePic:%d,
+                                ServerID:%d,
+                                TalkTime:%d
+                                '''\
+                                %(
+                                self.NameLen,
+                                self.Name,
+                                self.PlayerID,
+                                self.Len,
+                                self.Content,
+                                self.BubbleBox,
+                                self.LV,
+                                self.Job,
+                                self.RealmLV,
+                                self.Face,
+                                self.FacePic,
+                                self.ServerID,
+                                self.TalkTime
+                                )
+        return DumpString
+
+
+class  tagMCTalkCacheList(Structure):
+    Head = tagHead()
+    ChannelType = 0    #(BYTE ChannelType)// 0-世界;1-跨服;3- 仙盟	
+    Count = 0    #(BYTE Count)
+    InfoList = list()    #(vector<tagMCTalkCacheInfo> InfoList)//size = Count
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB3
+        self.Head.SubCmd = 0x11
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ChannelType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temInfoList = tagMCTalkCacheInfo()
+            _pos = temInfoList.ReadData(_lpData, _pos)
+            self.InfoList.append(temInfoList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB3
+        self.Head.SubCmd = 0x11
+        self.ChannelType = 0
+        self.Count = 0
+        self.InfoList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.Count):
+            length += self.InfoList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ChannelType)
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.InfoList[i].GetLength(), self.InfoList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ChannelType:%d,
+                                Count:%d,
+                                InfoList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ChannelType,
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCTalkCacheList=tagMCTalkCacheList()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCTalkCacheList.Head.Cmd,m_NAtagMCTalkCacheList.Head.SubCmd))] = m_NAtagMCTalkCacheList
+
+
+#------------------------------------------------------
 # B4 11 新增恶意攻击玩家 #tagMCAddMaliciousAtkPlayer
 
 class  tagMCAddMaliciousAtkPlayer(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
index 75e7d11..c4ed296 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
@@ -24,6 +24,7 @@
 import DBPlayerViewCache
 import DBEventTrig
 import DBBillboard
+import DBGameRec
 import DBFamily
 import DBMail
 
@@ -218,6 +219,7 @@
         self.BillboardMgr = DBBillboard.BillboardMgr()
         self.MailMgr = DBMail.MailMgr()
         self.FamilyMgr = DBFamily.FamilyMgr()
+        self.GameRecMgr = DBGameRec.GameRecMgr()
         return
     
     def GetSaveData(self):
@@ -227,6 +229,7 @@
         buff += self.BillboardMgr.GetSaveData()
         buff += self.MailMgr.GetSaveData()
         buff += self.FamilyMgr.GetSaveData()
+        buff += self.GameRecMgr.GetSaveData()
         return buff
     
     def LoadGameData(self, gameBuffer, pos):
@@ -236,6 +239,7 @@
         pos = self.BillboardMgr.LoadPyGameData(gameBuffer, pos, dataslen)
         pos = self.MailMgr.LoadPyGameData(gameBuffer, pos, dataslen)
         pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, dataslen)
+        pos = self.GameRecMgr.LoadPyGameData(gameBuffer, pos, dataslen)
         return pos
     
 def GetDBDataMgr():
@@ -275,3 +279,8 @@
     dbDataMgr = GetDBDataMgr()
     return dbDataMgr.BillboardMgr
 
+def GetGameRecMgr():
+    ## 通用记录数据管理器
+    dbDataMgr = GetDBDataMgr()
+    return dbDataMgr.GameRecMgr
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py
index 8353749..b6b8e0c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py
@@ -1899,10 +1899,141 @@
             self.Name2 = Str[:65]
             
 
+# 通用记录表新 #tagDBGameRec
+class tagDBGameRec(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('RecType', ctypes.c_ushort),
+        ('RecID', ctypes.c_ulong),
+        ('Time', ctypes.c_double),
+        ('Value1', ctypes.c_ulong),
+        ('Value2', ctypes.c_ulong),
+        ('Value3', ctypes.c_ulong),
+        ('Value4', ctypes.c_ulong),
+        ('Value5', ctypes.c_ulong),
+        ('Value6', ctypes.c_ulong),
+        ('Value7', ctypes.c_ulong),
+        ('Value8', ctypes.c_ulong),
+        ('UserDataLen', ctypes.c_ushort),
+        ('UserData', ctypes.c_char_p),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+    def clear(self):
+        self.RecType = 0
+        self.RecID = 0
+        self.Time = 0.0
+        self.Value1 = 0
+        self.Value2 = 0
+        self.Value3 = 0
+        self.Value4 = 0
+        self.Value5 = 0
+        self.Value6 = 0
+        self.Value7 = 0
+        self.Value8 = 0
+        self.UserDataLen = 0
+        self.UserData = ''
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        self.clear()
+        self.RecType, pos = CommFunc.ReadWORD(buf, pos)
+        self.RecID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Time, pos = CommFunc.ReadDouble(buf, pos)
+        self.Value1, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value2, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value3, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value4, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value5, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value6, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value7, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value8, pos = CommFunc.ReadDWORD(buf, pos)
+        self.UserDataLen, pos = CommFunc.ReadWORD(buf, pos)
+        tmp, pos = CommFunc.ReadString(buf, pos, self.UserDataLen)
+        self.UserData = ctypes.c_char_p(tmp)
+        return self.getLength()
+
+    def getBuffer(self):
+        buf = ''
+        buf = CommFunc.WriteWORD(buf, self.RecType)
+        buf = CommFunc.WriteDWORD(buf, self.RecID)
+        buf = CommFunc.WriteDouble(buf, self.Time)
+        buf = CommFunc.WriteDWORD(buf, self.Value1)
+        buf = CommFunc.WriteDWORD(buf, self.Value2)
+        buf = CommFunc.WriteDWORD(buf, self.Value3)
+        buf = CommFunc.WriteDWORD(buf, self.Value4)
+        buf = CommFunc.WriteDWORD(buf, self.Value5)
+        buf = CommFunc.WriteDWORD(buf, self.Value6)
+        buf = CommFunc.WriteDWORD(buf, self.Value7)
+        buf = CommFunc.WriteDWORD(buf, self.Value8)
+        buf = CommFunc.WriteWORD(buf, self.UserDataLen)
+        buf = CommFunc.WriteString(buf, self.UserDataLen, self.UserData)
+        return buf
+
+    def getLength(self):
+        length = 0
+        length += sizeof(ctypes.c_ushort)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_double)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ushort)
+        length += self.UserDataLen
+        return length
+
+    def outputString(self):
+        output = '''// 通用记录表新 #tagDBGameRec:
+            RecType = %s,
+            RecID = %s,
+            Time = %s,
+            Value1 = %s,
+            Value2 = %s,
+            Value3 = %s,
+            Value4 = %s,
+            Value5 = %s,
+            Value6 = %s,
+            Value7 = %s,
+            Value8 = %s,
+            UserDataLen = %s,
+            UserData = %s,
+            ADOResult = %s,
+            '''%(
+                self.RecType,
+                self.RecID,
+                self.Time,
+                self.Value1,
+                self.Value2,
+                self.Value3,
+                self.Value4,
+                self.Value5,
+                self.Value6,
+                self.Value7,
+                self.Value8,
+                self.UserDataLen,
+                self.UserData,
+                self.ADOResult,
+            )
+        return output
+
+
+
 #服务器世界数据表版本号
 GAMEWORLD_DATA_VERSION_NO = ctypes.c_ulong (\
     sizeof(tagDBEventTrig) + sizeof(tagDBFamily) + sizeof(tagDBFamilyMem) + sizeof(tagDBFamilyAction) + 
     sizeof(tagDBPlayerViewCache) + sizeof(tagDBMailPersonal) + sizeof(tagDBMailServer) + sizeof(tagDBMailItem) + 
-    sizeof(tagDBMailPlayerRec) + sizeof(tagDBBillboard) 
+    sizeof(tagDBMailPlayerRec) + sizeof(tagDBBillboard) + sizeof(tagDBGameRec)
     ).value
     
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
index 9ef6384..b7b2bfe 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
@@ -20,6 +20,7 @@
 import GameWorld
 import ShareDefine
 import PlayerControl
+import PlayerViewCache
 import PyMongoMain
 import DBDataMgr
 import ChConfig
@@ -82,12 +83,15 @@
         self.__actionDataList.append(actionData)
         return actionData
     
-    def AddAction(self, fullClear=True):
+    def AddAction(self, maxCount=None):
         ## 添加仙盟Action数据
-        # @param fullClear: 数据条数超过最大数时是否清除最早一条,并创建一条新记录
+        # @param maxCount: 可传入由配置决定的最大条数,如果为None则进一步取程序默认设定的最大条数,都没配置的话默认不限条数
         
+        fullClear = True
+        if maxCount == None:
+            maxCount = ShareDefine.ActionTypeSaveCnt.get(self.actionType, 0)
         actionData = None
-        if self.Count() >= ChConfig.ActionTypeSaveCnt.get(self.actionType, 0):
+        if maxCount and self.Count() >= maxCount:
             if not fullClear:
                 #超过记录记录不了了
                 return actionData
@@ -207,7 +211,7 @@
         ## 根据玩家ID更新成员数据,一般用于离线功能,如添加离线成员,直接使用查看缓存更新
         if playerID != self.GetPlayerID():
             return
-        viewCache = DBDataMgr.GetPlayerViewCacheMgr().FindViewCache(playerID)
+        viewCache = PlayerViewCache.FindViewCache(playerID)
         if not viewCache:
             return
         self.SetPlayerName(viewCache.GetPlayerName())
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBGameRec.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBGameRec.py
new file mode 100644
index 0000000..adf6e3e
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBGameRec.py
@@ -0,0 +1,383 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package DB.StructData.DBGameRec
+#
+# @todo:通用记录表新
+# @author hxp
+# @date 2025-05-23
+# @version 1.0
+#
+# 详细描述: 通用记录表新,原通用记录字符长度记录有限,且针对某个记录类型下的子类型查找每次需要遍历,效率不高
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-05-23 20:00"""
+#-------------------------------------------------------------------------------
+
+import DBStruct
+import GameWorld
+import ShareDefine
+import CommFunc
+import DBComm
+
+import time
+
+class GameRecData():
+    
+    def __init__(self, dbData=None, dataToJson=False):
+        if not dbData:
+            dbData = DBStruct.tagDBGameRec()
+        self.__dbData = dbData
+        self.__dataDict = DBComm.UserDataDict(self.__dbData, "UserData", "UserDataLen", dataToJson)
+        return
+    def GetRecType(self): return self.__dbData.RecType
+    def SetRecType(self, recType): self.__dbData.RecType = recType
+    def GetRecID(self): return self.__dbData.RecID
+    def SetRecID(self, recID): self.__dbData.RecID = recID
+    def GetTime(self): return self.__dbData.Time
+    def SetTime(self, sTime): self.__dbData.Time = sTime
+    def GetValue1(self): return self.__dbData.Value1
+    def SetValue1(self, value1): self.__dbData.Value1 = value1
+    def GetValue2(self): return self.__dbData.Value2
+    def SetValue2(self, value2): self.__dbData.Value2 = value2
+    def GetValue3(self): return self.__dbData.Value3
+    def SetValue3(self, value3): self.__dbData.Value3 = value3
+    def GetValue4(self): return self.__dbData.Value4
+    def SetValue4(self, value4): self.__dbData.Value4 = value4
+    def GetValue5(self): return self.__dbData.Value5
+    def SetValue5(self, value5): self.__dbData.Value5 = value5
+    def GetValue6(self): return self.__dbData.Value6
+    def SetValue6(self, value6): self.__dbData.Value6 = value6
+    def GetValue7(self): return self.__dbData.Value7
+    def SetValue7(self, value7): self.__dbData.Value7 = value7
+    def GetValue8(self): return self.__dbData.Value8
+    def SetValue8(self, value8): self.__dbData.Value8 = value8
+    def GetUserDict(self): return self.__dataDict.GetData()
+    def GetUserData(self): return self.__dataDict.ToString()
+    def SetUserData(self, value): self.__dataDict.SetData(value)
+    def GetBuffer(self):
+        self.__dataDict.ToString()
+        return self.__dbData.getBuffer()
+    
+    def IsMatchValue(self, valueList):
+        # 检查记录值列表是否配置该记录
+        # @param valueList: [value1, value2, ...] value为None时不判断该值
+        if not valueList:
+            return False
+        for i, value in enumerate(valueList, 1):
+            if value == None:
+                continue
+            if not hasattr(self, "GetValue%s" % i):
+                return False
+            curValue = getattr(self, "GetValue%s" % i)()
+            if curValue != value:
+                return False
+        return True
+    
+    def GetValueIndexKey(self):
+        ## 获取Value快速查找索引key,默认使用value1
+        recType = self.GetRecType()
+        if recType not in ShareDefine.Def_GameRecValueKeyDict:
+            return ""
+        valueNumList = ShareDefine.Def_GameRecValueKeyDict[recType]
+        if not valueNumList:
+            valueNumList = [1]
+        keyStr = ""
+        for num in valueNumList:
+            if not hasattr(self, "GetValue%s" % num):
+                return ""
+            if keyStr:
+                keyStr += "_"
+            keyStr += str(getattr(self, "GetValue%s" % num)())
+        return keyStr
+    
+class GameRecIDMgr():
+    ## 类型数据ID管理
+    
+    def __init__(self, recType, recID):
+        self.__recType = recType
+        self.__recID = recID
+        self.__dataList = [] # 数据列表 [GameRecData, ...]
+        self.__valueIndexDict = {} # value索引值对应数据列表 {indexKey:[GameRecData, ...], ...}
+        return
+    
+    def InitRecDataInstance(self, dbData):
+        '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
+        @param dbData: 实例对应绑定的dbData
+        @return: 成功返回实例对象,失败返回None
+        '''
+        dataToJson = False
+        # 如果需要 dataToJson,可根据 RecType 在这里处理
+        if dbData.RecType in []:
+            dataToJson = True
+        recData = GameRecData(dbData, dataToJson)
+        self.__dataList.append(recData)
+        
+        keyStr = recData.GetValueIndexKey()
+        if keyStr:
+            if keyStr not in self.__valueIndexDict:
+                self.__valueIndexDict[keyStr] = []
+            recIndexDataList = self.__valueIndexDict[keyStr]
+            recIndexDataList.append(recData)
+            
+        return recData
+    
+    def GetRecType(self): return self.__recType
+    def GetRecID(self): return self.__recID
+    
+    def SortByTime(self):
+        self.__dataList.sort(key=lambda r: (r.GetTime()), reverse=False)
+        return
+    
+    def AddRecData(self, maxCount=None):
+        '''添加记录
+        @param maxCount: 可传入由配置决定的最大条数,如果为None则进一步取程序默认设定的最大条数,都没配置的话默认不限条数
+        '''
+        
+        fullClear = True
+        recData = None
+        if maxCount == None:
+            maxCount = 0
+        if maxCount and self.GetCount() >= maxCount:
+            if not fullClear:
+                #超过记录记录不了了
+                return recData
+            #self.SortByTime()  # 按时间升序
+            self.DelCount(self.GetCount() - maxCount + 1)
+            
+        dbData = DBStruct.tagDBGameRec()
+        dbData.RecType = self.__recType
+        dbData.RecID = self.__recID
+        dbData.Time = int(time.time())
+        #if valueSetList:
+        #    for num, v in enumerate(valueSetList, 1):
+        #        if not hasattr(dbData, "Value%s" % num):
+        #            continue
+        #        setattr(dbData, "Value%s" % num, v
+        
+        recData = self.InitRecDataInstance(dbData)
+        return recData
+    
+    def GetCount(self): return len(self.__dataList)
+    def At(self, index):
+        recData = None
+        if 0 <= index < len(self.__dataList):
+            recData = self.__dataList[index]
+        elif False:
+            recData = GameRecData()
+        return recData
+    
+    def GetOneRecData(self, isAddNew=False):
+        ## 获取第一条记录,适用于仅需一条的记录类型
+        # @param isAddNew: 没有记录时是否添加一条新记录,一般获取后需要更新数据的可以设置为True,仅判断用的建议设置为False,减少产生多余空数据
+        recData = None
+        if self.__dataList:
+            recData = self.__dataList[0]
+        elif isAddNew:
+            recData = self.AddRecData()
+        return recData
+    
+    def GetRecDataByValues(self, valueList, findone=False):
+        '''获取匹配value值的记录
+        @param valueList: [value1, value2, ...] value为None时不判断该值
+        @param findone: 是否只匹配一条满足的记录
+        @return: recData or [recData, ...] or None
+        '''
+        
+        # 有配置value索引key的,直接快速获取
+        if self.__recType in ShareDefine.Def_GameRecValueKeyDict:
+            keyStr = ""
+            for v in valueList:
+                if keyStr:
+                    keyStr += "_"
+                keyStr += str(v)
+            if keyStr not in self.__valueIndexDict:
+                return
+            recIndexDataList = self.__valueIndexDict[keyStr]
+            if not recIndexDataList:
+                return
+            return recIndexDataList[0] if findone else recIndexDataList
+        
+        # 没有的则遍历匹配
+        matchRecDataList = []
+        for recData in self.__dataList:
+            if not recData.IsMatchValue(valueList):
+                continue
+            if findone:
+                return recData
+            matchRecDataList.append(recData)
+        return matchRecDataList
+    
+    def DelAllData(self):
+        ## 删除该记录ID的所有数据
+        dataCount = self.GetCount()
+        if not dataCount:
+            return 0
+        #GameWorld.DebugLog("删除通用记录某个类型ID所有记录: recType=%s,recID=%s,dataCount=%s" % (self.__recType, self.__recID, dataCount))
+        self.__dataList = []
+        self.__valueIndexDict = {}
+        return dataCount
+    
+    def DelDataByValue(self, valueList):
+        ## 删除该记录ID所有匹配Value值列表的数据记录
+        # @param valueList: [value1, value2, ...] value为None时不判断该值
+        if not valueList:
+            return 0
+        
+        delCount = 0
+        for recData in self.__dataList[::-1]: # 倒序处理删除
+            if recData.IsMatchValue(valueList):
+                self.DelRecData(recData)
+                delCount += 1
+                
+        #if delCount:
+        #    GameWorld.DebugLog("删除通用记录某个类型ID所有匹配Value值的记录: recType=%s,recID=%s,valueList=%s,delCount=%s" 
+        #                       % (self.__recType, self.__recID, valueList, delCount))
+        return delCount
+    
+    def DelRecData(self, recData):
+        ## 删除指定记录
+        if not recData:
+            return 0
+        
+        if recData in self.__dataList:
+            self.__dataList.remove(recData)
+            
+        keyStr = recData.GetValueIndexKey()
+        if keyStr in self.__valueIndexDict:
+            recIndexDataList = self.__valueIndexDict[keyStr]
+            if recData in recIndexDataList:
+                recIndexDataList.remove(recData)
+                
+        return 1
+    
+    def DelCount(self, delCount, reverse=False):
+        ## 删除条数
+        # @param reverse: False-从索引0开始删除,True-从最后一个索引往前删
+        delDataList = self.__dataList[:delCount] if not reverse else self.__dataList[-delCount-1:]
+        for recData in delDataList:
+            self.DelRecData(recData)
+        #GameWorld.DebugLog("删除通用记录条数: recType=%s,recID=%s,delCount=%s,remainCount=%s" 
+        #                   % (self.__recType, self.__recID, delCount, len(self.__dataList)))
+        return
+    
+class GameRecTypeMgr():
+    ## 类型管理
+    
+    def __init__(self, recType):
+        self.__recType = recType
+        self.__recIDDict = {} # recID对应数据列表 {recID:GameRecIDMgr, ...}
+        return
+    
+    def GetRecType(self): return self.__recType
+    
+    def GetRecIDMgr(self, recID):
+        recIDMgr = None
+        if recID in self.__recIDDict:
+            recIDMgr = self.__recIDDict[recID]
+        else:
+            recIDMgr = GameRecIDMgr(self.__recType, recID)
+            self.__recIDDict[recID] = recIDMgr
+        return recIDMgr
+    
+    def GetRecIDList(self): return self.__recIDDict.keys()
+    
+    def GetRecDataByValues(self, valueList, findone=False):
+        ## 获取该类型所有记录匹配value值的记录
+        matchRecDataList = []
+        for recID in self.__recIDDict.keys():
+            recIDMgr = self.GetRecIDMgr(recID)
+            ret = recIDMgr.GetRecDataByValues(valueList, findone)
+            if not ret:
+                continue
+            if findone:
+                return ret
+            
+            if isinstance(ret, list):
+                matchRecDataList += ret
+                
+        return matchRecDataList
+    
+    def DelAllData(self):
+        ## 删除该类型所有记录
+        delCount = 0
+        for recID in self.__recIDDict.keys():
+            delCount += self.DelDataByRecID(recID)
+        return delCount
+    def DelDataByRecID(self, recID):
+        ## 删除该类型某个记录ID的所有记录
+        return self.GetRecIDMgr(recID).DelAllData()
+    def DelDataByValue(self, valueList):
+        ## 删除该类型所有匹配Value值列表的记录
+        delCount = 0
+        for recID in self.__recIDDict.keys():
+            recIDMgr = self.GetRecIDMgr(recID)
+            delCount += recIDMgr.DelDataByValue(valueList)
+        return delCount
+    
+class GameRecMgr():
+    ## 通用记录管理
+    
+    def __init__(self):
+        self.__recTypeDict = {} # {recType:GameRecTypeMgr, ...}
+        return
+    
+    def GetRecTypeMgr(self, recType):
+        recTypeMgr = None
+        if recType in self.__recTypeDict:
+            recTypeMgr = self.__recTypeDict[recType]
+        else:
+            recTypeMgr = GameRecTypeMgr(recType)
+            self.__recTypeDict[recType] = recTypeMgr
+        return recTypeMgr
+    
+    def GetRecTypeIDMgr(self, recType, recID):
+        recTypeMgr = self.GetRecTypeMgr(recType)
+        recTypeIDMgr = recTypeMgr.GetRecIDMgr(recID)
+        if not recTypeIDMgr and False:
+            recTypeIDMgr = GameRecIDMgr(recType, recID)
+        return recTypeIDMgr
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        
+        for recType in self.__recTypeDict.keys():
+            recTypeMgr = self.GetRecTypeMgr(recType)
+            for recID in recTypeMgr.GetRecIDList():
+                recTypeIDMgr = recTypeMgr.GetRecIDMgr(recID)
+                for index in range(recTypeIDMgr.GetCount()):
+                    recData = recTypeIDMgr.At(index)
+                    savaData += recData.GetBuffer()
+                    cnt += 1
+                    
+        GameWorld.Log("Save DBGameRec count :%s len=%s" % (cnt, len(savaData)))
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+    
+    # 从数据库载入数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBGameRec count :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            dbData = DBStruct.tagDBGameRec()
+            dbData.readData(datas, pos, dataslen)
+            recType = dbData.RecType
+            recID = dbData.RecID
+            recTypeIDMgr = self.GetRecTypeIDMgr(recType, recID)
+            recTypeIDMgr.InitRecDataInstance(dbData)
+            
+        for recType in self.__recTypeDict.keys():
+            recTypeMgr = self.GetRecTypeMgr(recType)
+            for recID in recTypeMgr.GetRecIDList():
+                recTypeIDMgr = recTypeMgr.GetRecIDMgr(recID)
+                recTypeIDMgr.SortByTime()
+                
+        return pos
+    
+    
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBPlayerViewCache.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBPlayerViewCache.py
index 4acf923..1b24dc3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBPlayerViewCache.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBPlayerViewCache.py
@@ -18,17 +18,8 @@
 import DBComm
 import DBStruct
 import GameWorld
-import ShareDefine
-import PlayerControl
-import DBDataMgr
 import CommFunc
 import ChConfig
-import GameObj
-
-import random
-import time
-
-Key_UpdViewCacheTick = "UpdViewCacheTick"
 
 class PlayerViewCache():
     
@@ -84,97 +75,36 @@
     
     def __init__(self):
         self.__viewCacheList = [] # [PlayerViewCache, ...]
-        self.__idIndexDict = {} # {playerID:index, ...}
+        self.__viewCacheDict = {} # {playerID:PlayerViewCache, ...}
         self.__needSort = False
         self.__serverIDRangePlayerIDDict = {} # {serverIDRangeTuple:[playerID, ...], ....}
         return
     
-    def InitViewCacheInstance(self, dbData):
+    def __InitViewCacheInstance(self, dbData):
         '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
         @param dbData: 实例对应绑定的dbData
         @return: 成功返回实例对象,失败返回None
         '''
         playerID = dbData.PlayerID
-        self.__refreshIDIndex()
-        if playerID in self.__idIndexDict:
+        if playerID in self.__viewCacheDict:
             return
         viewCache = PlayerViewCache(dbData)
         self.__viewCacheList.append(viewCache)
-        self.__idIndexDict[playerID] = len(self.__viewCacheList) - 1
+        self.__viewCacheDict[playerID] = viewCache
         self.__needSort = True
         return viewCache
     
-    def CheckUpdViewCache(self, playerID):
-        if playerID <= ShareDefine.FackPlayerIDMax:
-            return
-        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
-        if not curPlayer:
-            return
-        lastUpdTick = curPlayer.GetDictByKey(Key_UpdViewCacheTick)
-        tick = GameWorld.GetGameWorld().GetTick()
-        if lastUpdTick and tick - lastUpdTick < 60000:
-            GameWorld.DebugLog("1分钟内只更新一次玩家缓存", playerID)
-            return
-        curPlayer.SetDict(Key_UpdViewCacheTick, tick)
-        return UpdPlayerViewCache(curPlayer)
-    
-    def FindViewCache(self, playerID, isAdd=False):
-        '''查找玩家缓存,如果不存在,则会有额外逻辑,如从redis、db直接找,
-                        跨服玩家从跨服取,可能延迟获得
-        '''
-        curCache = self.GetPlayerViewCache(playerID)
-        if curCache:
-            updCache = self.CheckUpdViewCache(playerID)
-            if updCache:
-                curCache = updCache
-                
-        # 真实玩家
-        elif playerID > ShareDefine.FackPlayerIDMax:
-            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
-            # 本服在线玩家,直接生成新数据
-            if curPlayer:
-                dbData = DBStruct.tagDBPlayerViewCache()
-                dbData.PlayerID = playerID
-                self.InitViewCacheInstance(dbData)
-                UpdPlayerViewCache(curPlayer)
-                
-            # 离线玩家
-            else:
-                pass
-                # 本服玩家,从redis或db读取重新加载读取,换句话说,本服玩家只要获取一定有查看缓存数据
-                # 跨服玩家,去子服拉取数据,理论上也一定有,但是如果需要拉数据,有一定延迟
-                # 逻辑待扩展
-                
-        # 假玩家,默认添加
-        elif ShareDefine.FackPlayerIDStart <= playerID <= ShareDefine.FackPlayerIDMax:
-            serverID = playerID % 100 + 1 # 1 ~ 100 服
-            accID = "fake%s@test@s%s" % (playerID, serverID)
-            fightPower = random.randint(1000000, 100000000) # 先随机,外层有需要的话再自己设置
-            
-            dbData = DBStruct.tagDBPlayerViewCache()
-            dbData.PlayerID = playerID
-            dbData.PlayerName = "%s%s" % (GameWorld.GbkToCode("神秘道友"), playerID)
-            dbData.AccID = accID
-            dbData.LV = random.randint(100, 200)
-            dbData.Job = random.randint(1, 2)
-            dbData.RealmLV = random.randint(5, 15)
-            dbData.FightPower = fightPower % ChConfig.Def_PerPointValue
-            dbData.FightPowerEx = fightPower / ChConfig.Def_PerPointValue
-            dbData.ServerID = serverID
-            dbData.OffTime = int(time.time()) - random.randint(1, 3600 * 24 * 10) # 随机离线 0~10天
-            curCache = self.InitViewCacheInstance(dbData)
-            
-        return curCache
+    def AddPlayerViewCache(self, playerID):
+        dbData = DBStruct.tagDBPlayerViewCache()
+        dbData.PlayerID = playerID
+        return self.__InitViewCacheInstance(dbData)
     
     def GetPlayerViewCache(self, playerID):
         ## 获取玩家查看缓存,仅内存中数据,无额外逻辑
-        self.__refreshIDIndex()
         viewCache = None
-        if playerID in self.__idIndexDict:
-            index = self.__idIndexDict[playerID]
-            if index < len(self.__viewCacheList):
-                viewCache = self.__viewCacheList[index]
-                
+        if playerID in self.__viewCacheDict:
+            viewCache = self.__viewCacheDict[playerID]
+            
         if not viewCache and False:
             viewCache = PlayerViewCache()
             
@@ -200,32 +130,19 @@
             self.__serverIDRangePlayerIDDict[key] = playerIDList
         return self.__serverIDRangePlayerIDDict[key]
     
-    def IsPlayerIn(self, playerID):
-        self.__refreshIDIndex()
-        return playerID in self.__idIndexDict
-    
-    def __refreshIDIndex(self):
-        if not self.__idIndexDict:
-            self.__idIndexDict = {}
-            for index, viewCache in enumerate(self.__viewCacheList):
-                self.__idIndexDict[viewCache.GetPlayerID()] = index
-        return self.__idIndexDict
-    
     def DelPlayerViewCache(self, playerID):
-        self.__refreshIDIndex()
-        index = self.__idIndexDict.pop(playerID, -1)
-        if index >= 0 and index < len(self.__viewCacheList):
-            self.__viewCacheList.pop(index)
+        viewCache = self.__viewCacheDict.pop(playerID, None)
+        if viewCache in self.__viewCacheList:
+            self.__viewCacheList.remove(viewCache)
         for playerIDList in self.__serverIDRangePlayerIDDict.values():
             if playerID in playerIDList:
                 playerIDList.remove(playerID)
-        self.__idIndexDict = {}
         self.__serverIDRangePlayerIDDict = {}
         return
     
     def DelAllCache(self):
         self.__viewCacheList = []
-        self.__idIndexDict = {}
+        self.__viewCacheDict = {}
         self.__needSort = False
         self.__serverIDRangePlayerIDDict = {}
         return
@@ -243,9 +160,7 @@
             return
         self.__needSort = False
         self.__viewCacheList.sort(key=lambda v: (v.GetFightPowerTotal(), v.GetLV()), reverse=True)
-        self.__idIndexDict = {}
         self.__serverIDRangePlayerIDDict = {}
-        self.__refreshIDIndex()
         return
     
     # 保存数据 存数据库和realtimebackup
@@ -269,66 +184,7 @@
         for _ in xrange(cnt):
             dbData = DBStruct.tagDBPlayerViewCache()
             pos += dbData.readData(datas, pos, dataslen)
-            self.InitViewCacheInstance(dbData)
+            self.__InitViewCacheInstance(dbData)
             
         self.Sort()
         return pos
-    
-def OnPlayerLogout(curPlayer):
-    if curPlayer.GetLV() >= 10:
-        UpdPlayerViewCache(curPlayer)
-        
-    return
-
-def UpdPlayerViewCache(curPlayer, isOffline=False):
-    '''更新玩家查看缓存数据,更新时机由外层自己判断,这里只做更新逻辑
-    1. 下线时强制更新一次,上线暂不更新,上线时由各功能如果有需要用到触发更新
-    2. 有需要用到缓存数据时,如果玩家在线,1分钟内多次获取时最多更新一次,没有获取缓存数据则不更新
-    '''
-    if not curPlayer:
-        return
-    
-    playerID = curPlayer.GetPlayerID()
-    curCache = DBDataMgr.GetPlayerViewCacheMgr().GetPlayerViewCache(playerID)
-    if not curCache:
-        return
-    
-    tick = GameWorld.GetGameWorld().GetTick()
-    curPlayer.SetDict(Key_UpdViewCacheTick, tick)
-    GameWorld.DebugLog("更新玩家查看缓存数据! isOffline=%s" % isOffline, playerID)
-    curCache.SetAccID(curPlayer.GetAccID())
-    curCache.SetPlayerName(curPlayer.GetPlayerName())
-    curCache.SetLV(curPlayer.GetLV())
-    curCache.SetJob(curPlayer.GetJob())
-    curCache.SetRealmLV(curPlayer.GetOfficialRank())
-    curCache.SetFace(curPlayer.GetFace())
-    curCache.SetFacePic(curPlayer.GetFacePic())
-    curCache.SetFamilyID(curPlayer.GetFamilyID())
-    curCache.SetFamilyName(curPlayer.GetFamilyName())
-    curCache.SetFamilyEmblemID(PlayerControl.GetFamilyEmblemID(curPlayer))
-    curCache.SetTitleID(PlayerControl.GetTitleID(curPlayer))
-    curCache.SetFightPowerTotal(PlayerControl.GetFightPower(curPlayer))
-    curCache.SetServerID(GameWorld.GetPlayerServerID(curPlayer))
-    if isOffline:
-        curCache.SetOffTime(int(time.time()))
-        
-    plusDict = curCache.GetPlusDict()
-        
-    #战斗属性
-    plusDict.update({
-                     "MinAtk":curPlayer.GetMinAtk(),
-                     "MaxAtk":curPlayer.GetMaxAtk(),
-                     "Def":curPlayer.GetDef(),
-                     "MaxHP":GameObj.GetMaxHP(curPlayer),
-                     "Hit":curPlayer.GetHit(),
-                     "Miss":curPlayer.GetMiss(),
-                     "SuperHitRate":curPlayer.GetSuperHitRate(), # 暴击率
-                     })
-    
-    # 功能数据
-    
-    # 其他
-    
-    return curCache
-
-    
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CreateFamily.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CreateFamily.py
index 4b997da..3937f10 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CreateFamily.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CreateFamily.py
@@ -17,6 +17,7 @@
 
 import GameWorld
 import ShareDefine
+import PlayerViewCache
 import IPY_PlayerDefine
 import PlayerFamily
 import DBDataMgr
@@ -232,7 +233,7 @@
             else:
                 memFightPower = avgValue + memCnt / 2 - m
                 memFightPowerTotal -= memFightPower
-            viewCache = DBDataMgr.GetPlayerViewCacheMgr().FindViewCache(memID, True)
+            viewCache = PlayerViewCache.FindViewCache(memID, True)
             viewCache.SetFightPowerTotal(memFightPower)
             GameWorld.DebugLog("    仙盟成员: memID=%s,memFightPower=%s,fmLV=%s" % (memID, memFightPower, fmLV))
             member.RefreshMemberByID(memID)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py
index e2132aa..5b06d28 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py
@@ -17,7 +17,6 @@
 
 import GameWorld
 import MirrorAttack
-import PlayerViewCacheTube
 import ChConfig
 
 ## GM命令执行入口
@@ -97,8 +96,8 @@
                 return
             
     elif value1 == 5:
-        tick = GameWorld.GetGameWorld().GetTick()
-        PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, forcePackData=True)
+        #tick = GameWorld.GetGameWorld().GetTick()
+        #PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, forcePackData=True)
         GameWorld.DebugAnswer(curPlayer, "已更新最新镜像缓存!")
     elif value1 in ["a", "d", "p"]:
         return True
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
index 61bc000..0128901 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -1406,6 +1406,9 @@
         return mainServerID
     return 0
 
+def GetDBPlayerAccIDByID(playerID):
+    ## 获取玩家表账号ID - 根据玩家ID, 可用于判断是否本服玩家
+    return PyGameData.g_dbPlayerIDMap.get(playerID, "")
 
 #===============================================================================
 # 平台ID = appid
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py
index 55f0c46..7957843 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py
@@ -20,7 +20,6 @@
 import PlayerControl
 import ChPyNetSendPack
 import NetPackCommon
-import PlayerViewCacheTube
 import PlayerActGarbageSorting
 import FBCommon
 import IpyGameDataPY
@@ -111,8 +110,8 @@
         PlayerActGarbageSorting.AddActGarbageTaskProgress(curPlayer, ChConfig.Def_GarbageTask_HelpBattle)
         
         # 没有数据缓存的话,马上同步一次
-        if not haveViewCache:
-            PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, False)
+        #if not haveViewCache:
+        #    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, False)
             
     SyncCheckInState(curPlayer, 1, False)
     
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
index 6a3a195..6a80703 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
@@ -31,7 +31,6 @@
 import ChItem
 import IpyGameDataPY
 import Operate_EquipStone
-import PlayerViewCacheTube
 import Operate_EquipWash
 import FormulaControl
 import ChPyNetSendPack
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
index a51cfd4..ec2a04e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
@@ -228,6 +228,19 @@
     #curPlayer.SendFakePack(innerPackData, len(innerPackData))
     curPlayer.SendFakePack(clientPack.GetBuffer(), clientPack.GetLength())
     
+def SendFackPackOnline(clientPack, parseFunc=None, *args):
+    ## 发送给全服在线玩家
+    # @param parseFunc: 中间处理逻辑,可以做一些修改包数据的逻辑或者过滤某些玩家不发送,返回值为True时发送
+    # @param args: parseFunc方法参数(curPlayer, ...)
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.OnlineCount()):
+        curPlayer = playerManager.OnlineAt(i)
+        if not GameWorld.IsNormalPlayer(curPlayer):
+            continue
+        if parseFunc and not parseFunc(curPlayer, *args):
+            continue
+        SendFakePack(curPlayer, clientPack)
+    return
 
 #-------------------------------------------------------------------------------
 #---Py封包注册信息
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 f41b51b..aec60d7 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -145,7 +145,6 @@
 import PlayerArena
 import PyGameData
 import PlayerCoin
-import PlayerGeTui
 import PlayerCharm
 import PlayerDogz
 import PlayerCoat
@@ -178,6 +177,7 @@
 import IPY_ServerDefine
 import CommFunc
 from PyMongoDB import RecvPackToMapDB
+import PlayerTalk
 
 import datetime
 import time
@@ -208,10 +208,6 @@
     #初始化玩家的时钟个数
     if curPlayer.GetTickTypeCount() == 0:
         curPlayer.SetTickTypeCount(ChConfig.TYPE_Player_Tick_Count)
-    
-    #初始化玩家聊天频道
-    if curPlayer.GetMaxChannelCount() == 0:
-        curPlayer.SetMaxChannelCount(ChConfig.Def_PlayerTalkChannelMaxCount)
         
 #===============================================================================
 #    #初始化玩家鉴定管理器物品最大个数
@@ -643,9 +639,6 @@
     #大师
     PlayerGreatMaster.MasterOnLogin(curPlayer)
     
-    # 推送提醒
-    PlayerGeTui.LoginNotifySetting(curPlayer)
-    
     #通知VIP
     PlayerVip.DoOnLogin(curPlayer, tick)
     
@@ -998,6 +991,7 @@
         PlayerMineArea.OnPlayerLogin(curPlayer)
         PlayerGuaji.OnPlayerLogin(curPlayer)
         PlayerActFamilyGCZ.OnPlayerLogin(curPlayer)
+        PlayerTalk.OnPlayerLogin(curPlayer)
         
         # 上线查询一次充值订单
         curPlayer.SendDBQueryRecharge()
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 cdc027c..761ae6c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -37,6 +37,7 @@
 import OperControlManager
 import PlayerFamily
 import ShareDefine
+import PlayerViewCache
 import PlayerBillboard
 import GameServerRefresh
 import IPY_GameWorld
@@ -56,7 +57,6 @@
 import PlayerWorldAverageLv
 import PlayerActivity
 import FBCommon
-import PlayerViewCacheTube
 import PassiveBuffEffMng
 import PlayerGameEvent
 import EventReport
@@ -87,9 +87,7 @@
 import PlayerActGarbageSorting
 import GY_Query_CrossRealmReg
 import PlayerTongTianLing
-import PlayerCrossRealmPK
 import FunctionNPCCommon
-import DBPlayerViewCache
 import PlayerGoldInvest
 import IPY_PlayerDefine
 import CrossRealmPlayer
@@ -251,7 +249,13 @@
 #  @param mergeMapInfo 该提示所属的跨服活动地图信息, 主要用于不同子服对应所跨的活动地图ID
 #  @return 无返回值
 def WorldNotify(country, msgMark, msgParamList=[], lineID=0, mergeMinOSD=-1, mergeMaxOSD=-1, mergeMapInfo=[]):
-    GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(country, 0, msgMark, __GetNotifyCodeList(msgParamList), lineID)
+    #GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(country, 0, msgMark, __GetNotifyCodeList(msgParamList), lineID)
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.OnlineCount()):
+        curPlayer = playerManager.OnlineAt(i)
+        if not GameWorld.IsNormalPlayer(curPlayer):
+            continue
+        NotifyCode(curPlayer, msgMark, msgParamList)
     return
 
 def GetCrossWorldNotifyInfo(country, msgMark, msgParamList=[]):
@@ -277,7 +281,8 @@
 #  @return 无返回值
 #  @remarks 
 def FamilyNotify(familyID, msgMark, msgParamList=[]):
-    GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(0, familyID, msgMark, __GetNotifyCodeList(msgParamList))
+    #GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(0, familyID, msgMark, __GetNotifyCodeList(msgParamList))
+    PlayerFamily.NotifyAllFamilyMemberMsg(familyID, msgMark, msgParamList)
     return
 
 #---------------------------------------------------------------------
@@ -1488,8 +1493,7 @@
     PlayerBillboard.UpdatePlayerBillboardOnLeaveServer(curPlayer) #排行榜已实时更新,故下线不再同步
     
     #玩家下线通知gameserver记录缓存(放在下线更新排行榜之后,方便Gameserver判断是否需要存入数据库中)
-    PlayerViewCacheTube.OnPlayerLogOut(curPlayer, tick)
-    DBPlayerViewCache.OnPlayerLogout(curPlayer)
+    PlayerViewCache.OnPlayerLogout(curPlayer)
     PlayerFamily.OnPlayerLogout(curPlayer)
     
     #玩家下线/玩家切换地图公用逻辑
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
index 766ae61..9d7d77f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -129,6 +129,7 @@
 import PlayerFuncTeam
 import PlayerMineArea
 import PlayerBillboard
+import PlayerViewCache
 import PlayerMail
 
 import datetime
@@ -168,6 +169,7 @@
     DoLogic_OnDayEx(tick)
     
     PlayerBillboard.OnDay()
+    PlayerViewCache.OnDay()
     return
 
 def DoLogic_OnDayEx(tick):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py
index 6b434b8..eeb08bc 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py
@@ -20,6 +20,7 @@
 import ShareDefine
 import PlayerControl
 import NetPackCommon
+import PlayerViewCache
 import ChPyNetSendPack
 import PlayerFamilyTech
 import PlayerFamilyEmblem
@@ -755,7 +756,7 @@
         reqInfo.ReqTime = reqTime
         if curPlayer:
             reqInfo.IsOnLine = True
-        viewCache = DBDataMgr.GetPlayerViewCacheMgr().FindViewCache(playerID)
+        viewCache = PlayerViewCache.FindViewCache(playerID)
         if viewCache:
             reqInfo.Name = viewCache.GetPlayerName()
             reqInfo.NameLen = len(reqInfo.Name)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGeTui.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGeTui.py
deleted file mode 100644
index 0da4ee1..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGeTui.py
+++ /dev/null
@@ -1,310 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#
-##@package
-#
-# @todo: 个推逻辑
-#
-# @author: Alee
-# @date 2018-5-20 下午02:10:00
-# @version 1.0
-#
-# @note: 
-#
-#---------------------------------------------------------------------
-
-import PlayerControl
-import GameWorld
-import ChConfig
-import ReadChConfig
-import datetime
-import IpyGameDataPY
-import IPY_GameWorld
-import ChPyNetSendPack
-import NetPackCommon
-import PlayerTJG
-import PlayerViewCacheTube
-import urllib
-import PlayerVip
-import json
-#===============================================================================
-# //B2 05 推送提醒设置 tagCMPushNotificationsSetting
-# 
-# struct    tagCMPushNotificationsSetting
-# {
-#    tagHead         Head;
-#    DWORD        OnoffBit;        // 按位约定开关
-#    BYTE        TimeLen;
-#    char        TimeStr[TimeLen];    // 时间字符串  01:02-05:00
-# };
-#===============================================================================
-
-# VIP权限
-Def_Onoff_VIPCount = 5
-(
-Def_Onoff_Time, #免打扰时间开关
-Def_Onoff_Boss, #关注BOSS
-Def_Onoff_Chat, #私聊
-Def_Onoff_TJGDead,  #脱机死亡
-Def_Onoff_TJGTimeLess,  #脱机时间不足1小时
-) = range(Def_Onoff_VIPCount)
-
-#非VIP权限
-Def_GeTui_FMT = -2 # 封魔坛
-
-
-# 推送提醒设置
-def GeTuiSetting(index, pack, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    if not PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_5):
-        #清空前4位 VIP权限
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GeTuiSet, pack.OnoffBit>>Def_Onoff_VIPCount<<Def_Onoff_VIPCount)
-        return
-    
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GeTuiSet, pack.OnoffBit)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_NoGeTuiTime, GetTimeLimit(pack.TimeStr))
-    
-    # 客户端需控制下发送频率
-    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, False)
-    return
-
-
-def GetTimeLimit(timeStr):
-    # 检查格式后转数字
-    timeList = timeStr.split("-")
-    if len(timeList) != 2:
-        return
-    
-    numList = timeList[0].split(":")
-    if len(numList) != 2:
-        return 
-    
-    num1 = GameWorld.ToIntDef(numList[0], 0)
-    num2 = GameWorld.ToIntDef(numList[1], 0)
-    
-    if num1 < 0 or num1 > 24:
-        return 
-    if num2 < 0 or num2 > 60:
-        return 
-    
-    numList2 = timeList[1].split(":")
-    if len(numList2) != 2:
-        return 
-    
-    num3 = GameWorld.ToIntDef(numList2[0], 0)
-    num4 = GameWorld.ToIntDef(numList2[1], 0)
-    
-    if num3 < 0 or num3 > 24:
-        return 
-    if num4 < 0 or num4 > 60:
-        return 
-    
-    return num1*1000000 + num2*10000 + num3*100 + num4
-
-# 便于测试
-def GetGeTuiClientID(curPlayer):
-    #return "13165ffa4e5a8fbf6d0"
-    return curPlayer.GetAccountData().GetGeTuiClientID()
-
-# 检查是否可以个推,geTuiType小于0的代表默认可推,无VIP限制
-def CheckCanGeTui(curPlayer, geTuiType=-1):
-    if not GetGeTuiClientID(curPlayer):
-        return False
-    
-    if not PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_5):
-        if geTuiType < 0:
-            return True
-        return False
-    
-    if geTuiType == Def_GeTui_FMT:
-        # 封魔坛受VIP的关注BOSS开关影响
-        geTuiType = Def_Onoff_Boss
-    
-    # 检查时间和开关
-    if geTuiType >= 0 and curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GeTuiSet)&pow(2, geTuiType) == 0:
-        return False
-    
-    # 没有开启免打扰
-    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GeTuiSet)&pow(2, Def_Onoff_Time) == 0:
-        return True
-    
-    limitTimt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_NoGeTuiTime)
-    
-    curTime = GameWorld.GetCurrentTime()
-    dateStr = str(curTime).split()[0]
-    #时间格式 '%Y-%m-%d %H:%M'
-    try:
-        startTimeStr = '%s %s:%s'%(dateStr, limitTimt/1000000, limitTimt/10000%100)
-        startTime = datetime.datetime.strptime(startTimeStr, "%Y-%m-%d %H:%M")
-        
-        endTimeStr = '%s %s:%s'%(dateStr, limitTimt/100%100, limitTimt%100)
-        endTime = datetime.datetime.strptime(endTimeStr, "%Y-%m-%d %H:%M")
-    except:
-        return False
-    
-    if startTime == endTime:
-        # 时间一致代表不限制
-        return True
-    
-    # 如 13:00-23:00
-    elif startTime < endTime:
-        if startTime <= curTime and curTime <= endTime:
-            return False
-    
-    # 如 23:00 - 8:00
-    else:
-        if endTime < curTime < startTime:
-            return True
-        else:
-            return False
-    
-    return True
-
-#===============================================================================
-# //B2 02 推送提醒设置通知 #tagMCPushNotificationsSetting
-# 
-# struct    tagMCPushNotificationsSetting
-# {
-#    tagHead         Head;
-#    DWORD        OnoffBit;        // 按位约定开关
-#    BYTE        TimeLen;
-#    char        TimeStr[TimeLen];    // 时间字符串  01:02-05:00
-# };
-#===============================================================================
-def LoginNotifySetting(curPlayer):
-
-    sendPack = ChPyNetSendPack.tagMCPushNotificationsSetting()
-    sendPack.OnoffBit = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GeTuiSet)
-    
-    limitTimt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_NoGeTuiTime)
-    timeStr = "%s:%s-%s:%s"%(limitTimt/1000000, limitTimt/10000%100, limitTimt/100%100, limitTimt%100)
-    sendPack.TimeStr = timeStr
-    sendPack.TimeLen = len(timeStr)
-    NetPackCommon.SendFakePack(curPlayer, sendPack)
-    return
-
-
-#===============================================================================
-# import urllib
-# getUrl = "http://127.0.0.1:53000/getui/index.php"
-# curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(0)
-# postInfo = urllib.urlencode({"PlayerName": curPlayer.GetName(), "NotifyMsg":"BOSS---", "RegID":"101d8559091575fb3da", "OSName":"ios"})
-# GameWorld.GetGameWorld().EventReport_EventReport(postInfo, "", "", "", 1, getUrl)
-#===============================================================================
-
-
-# 群推类定时活动由客户端自己处理
-# 服务端群推暂不由游戏服务器推送,可从第三方个推网站推送
-# 游戏服务器只推送具有变化性的内容
-# 支持单推和多人推送
-# appIDDict 混服使用对应不同key {平台ID:[[玩家个推ID, 玩家名],[玩家个推ID2, 玩家名2]。。。]}
-# 如果玩家名存在则必须与个推ID一一对应,若不存在则是多推,若存在则会一一单推
-#                带名字会被组合成 格式如【玩家名】您关注的BOSSxx已复活
-# EventReport_EventReport 向游戏服务器的个推小程序发送 webbottle
-def GeTuiNotify(appIDDict, notifyMsg):
-    if not appIDDict:
-        return
-    #osName = ReadChConfig.GetPyMongoConfig("GeTui", "OSName") 混服无法配置系统
-    geTuiUrl = ReadChConfig.GetPyMongoConfig("GeTui", "GeTuiUrl")
-    
-    playerInfo = json.dumps(appIDDict, ensure_ascii=False)
-    #含中文部分要urlencode
-    postInfo = urllib.urlencode({"PlayerInfo": playerInfo, "NotifyMsg":notifyMsg})
-    
-    GameWorld.GetGameWorld().EventReport_EventReport(postInfo, "", "", "", 1, geTuiUrl)
-    return
-
-
-# 时间不足
-def TJGTimeLess(curPlayer):
-    # 通知脱机挂,只处理一次
-    if curPlayer.GetDictByKey("TJGTimeLess"):
-        return
-    
-    tjgTime = PlayerTJG.GetTJGTime(curPlayer)
-    if tjgTime > 3600:
-        return
-    
-    curPlayer.SetDict("TJGTimeLess", 1)
-    
-    if not CheckCanGeTui(curPlayer, Def_Onoff_TJGTimeLess):
-        return
-    
-    showStr = GameWorld.GbkToCode(IpyGameDataPY.GetFuncCfg("GeTuiTJG", 4))    # 文字信息
-    GeTuiNotify({GameWorld.GetPlayerPlatform(curPlayer) :[[GetGeTuiClientID(curPlayer), curPlayer.GetName()]]}, showStr)
-    return
-
-
-#[玩家名]脱机外挂已开始托管角色挂机,角色当前经验效率:9999亿9999万经验/分,剩余脱机外挂时间:**小时**分钟
-def TJGEfficiency(curPlayer, times, exp):
-    # 通知脱机挂效益,只处理一次
-    if curPlayer.GetDictByKey("TJGEfficiency"):
-        return
-    curPlayer.SetDict("TJGEfficiency", 1)
-    
-    if not CheckCanGeTui(curPlayer):
-        return
-    
-    showStr = IpyGameDataPY.GetFuncCfg("GeTuiTJG")    # 文字信息
-    wanStr = IpyGameDataPY.GetFuncCfg("Coins1", 1) # 万
-    yiStr = IpyGameDataPY.GetFuncCfg("Coins1", 2) # 亿
-    
-    # 此为中式显示法,翻译成英文因考虑显示逻辑不同而变
-    Hundred_Million = 100000000
-    Ten_Thousand = 10000
-    
-    exp = exp/max(times, 1)*60
-    
-    if exp >= Hundred_Million:
-        expStr = "%s%s"%(exp/Hundred_Million, yiStr)
-        if exp/Ten_Thousand%Ten_Thousand != 0:
-            expStr += "%s%s"%(exp/Ten_Thousand%Ten_Thousand, wanStr)
-    elif exp >= Ten_Thousand:
-        if exp < Ten_Thousand*100:
-            expStr = "%.1f%s"%(exp*1.0/Ten_Thousand, wanStr)
-        else:
-            expStr = "%s%s"%(exp/Ten_Thousand, wanStr)
-    else:
-        expStr = exp
-    
-    tjgTime = PlayerTJG.GetTJGTime(curPlayer)
-    
-    GeTuiNotify({GameWorld.GetPlayerPlatform(curPlayer) : [[GetGeTuiClientID(curPlayer), curPlayer.GetName()]]}, 
-                GameWorld.GbkToCode(showStr%(expStr, tjgTime/60/60, tjgTime/60%60)))
-    return
-
-#您被[其他玩家名]杀死,剩余脱机外挂时间:**小时**分钟
-def TJGDead(curPlayer, tagName):
-    if curPlayer.GetGameObjType() != IPY_GameWorld.gotPlayer:
-        return
-    if not PlayerTJG.GetIsTJG(curPlayer):
-        return
-    
-    if not CheckCanGeTui(curPlayer):
-        return
-    
-    showStr = GameWorld.GbkToCode(IpyGameDataPY.GetFuncCfg("GeTuiTJG", 2))    # 文字信息
-    tjgTime = PlayerTJG.GetTJGTime(curPlayer)
-    
-    GeTuiNotify({GameWorld.GetPlayerPlatform(curPlayer) : [[GetGeTuiClientID(curPlayer), curPlayer.GetName()]]}, 
-                showStr%(tagName, tjgTime/60/60, tjgTime/60%60))
-    return
-
-# [玩家名]当前背包已满,赶快上线查收战利品吧
-def FullPack(curPlayer):
-    # 背包满只处理一次,外层已拦截
-    #===========================================================================
-    # if curPlayer.GetDictByKey("GTFullPack"):
-    #    return
-    # curPlayer.SetDict("GTFullPack", 1)
-    #===========================================================================
-    
-    if not CheckCanGeTui(curPlayer):
-        return
-    
-    showStr = GameWorld.GbkToCode(IpyGameDataPY.GetFuncCfg("GeTuiTJG", 3))    # 文字信息
-    GeTuiNotify({GameWorld.GetPlayerPlatform(curPlayer) : [[GetGeTuiClientID(curPlayer), curPlayer.GetName()]]}, showStr)
-    
-    
-    
-    
\ No newline at end of file
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 e9857e7..65509d3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
@@ -34,7 +34,6 @@
 import PlayerAutoCheckOnline
 import PlayerGameWallow
 import ReadChConfig
-import PlayerViewCacheTube
 import PlayerDienstgrad
 import PlayerVip
 import IpyGameDataPY
@@ -1274,9 +1273,6 @@
     
     #副本相关时间处理
     PlayerFB.DoPlayerFBTimeProcess(curPlayer, tick)
-    
-    #玩家数据缓存定时同步
-    PlayerViewCacheTube.ProcessCache(curPlayer, tick)
     
     #脱机计算
     #PlayerTJG.ProcessPlayerTJG(curPlayer, tick)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTJG.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTJG.py
index b205439..bd2e468 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTJG.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTJG.py
@@ -48,7 +48,6 @@
 import math
 import PassiveBuffEffMng
 import PlayerPet
-import PlayerGeTui
 import ChEquip
 import QuestCommon
 import random
@@ -284,8 +283,6 @@
     ChangeGuard(curPlayer, tick)
     times, finalAddExp = CalcPlayerTJG(curPlayer, tick)
     
-    #PlayerGeTui.TJGEfficiency(curPlayer, times, finalAddExp)
-    #PlayerGeTui.TJGTimeLess(curPlayer)
     return
 
 def GetTJGTime(curPlayer): return curPlayer.GetHappyPoint()
@@ -619,7 +616,6 @@
 def CheckPackFull(curPlayer):
     if not ItemCommon.CheckPackHasSpace(curPlayer, IPY_GameWorld.rptItem):
         curPlayer.SetDict(ChConfig.Def_PlayerKey_TJGPackFullAfterEat, 1)
-        #PlayerGeTui.FullPack(curPlayer)
 
 # 可执行吞噬操作
 def CanEatItemsOper(curPlayer):
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 948b30f..51bab1a 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
@@ -1,268 +1,110 @@
 #!/usr/bin/python
 # -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
 #
-##@package
+##@package Player.PlayerTalk
 #
-# @todo: 玩家聊天逻辑 支持语音
-#
-# @author: Alee
-# @date 2018-4-24 下午07:36:28
+# @todo:聊天
+# @author hxp
+# @date 2025-05-23
 # @version 1.0
 #
-# @note: 
+# 详细描述: 聊天
 #
-#---------------------------------------------------------------------
-import IPY_GameWorld
-import GameWorld
-import PlayerControl
+#-------------------------------------------------------------------------------
+#"""Version = 2025-05-23 20:00"""
+#-------------------------------------------------------------------------------
+
 import ChConfig
-import FBLogic
-#import ReadChConfig
+import GameWorld
 import ShareDefine
+import IPY_GameWorld
 import ChPyNetSendPack
 import CrossRealmPlayer
+import PlayerViewCache
 import NetPackCommon
-import EventReport
-import PlayerSuccess
 import IpyGameDataPY
-import ItemCommon
-import ChItem
-import PlayerTJG
-import EventShell
-import PyGameData
-import PlayerLove
+import PlayerControl
+import PlayerFamily
+import DBDataMgr
+
 import math
-#---------------------------------------------------------------------
 
+#需要记录聊天缓存的频道对应限制最大条数
+ChannelCacheMax = {IPY_GameWorld.tcFamily:30,
+                   IPY_GameWorld.tcWorld:100,
+                   }
+    
+def OnPlayerLogin(curPlayer):
+    NotifyTalkCache(curPlayer)
+    return
 
-## 区域频道(封包参数) 
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-#  整个地图的人都可以听到
-def TalkArea(index, tick):
+#// B3 20 聊天 #tagCMTalk
+#
+#struct    tagCMPyTalk
+#{
+#    tagHead        Head;
+#    BYTE        ChannelType;    // 频道
+#    WORD        Len;
+#    char        Content[Len];        //size = Len
+#};
+def OnTalk(index, clientData, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    familyID = curPlayer.GetFamilyID()
+    channelType = clientData.ChannelType
+    content = clientData.Content
     
-    #获得区域频封包
-    sendPack = IPY_GameWorld.IPY_CTalkArea()
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    #通用判断
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, talkType=IPY_GameWorld.tcArea):
-        return
-    
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcArea, tick)
-    
-    
-    #如果在普通地图, 就广播, 如果在副本就单个通知
-    if GameWorld.GetMap().GetMapFBType() == IPY_GameWorld.fbtNull and not GameWorld.IsCrossServer():
-        #广播
-        extras = GetTalkExtraValue(curPlayer)
-        curPlayer.ChatArea(content, 0, extras)
-    else:
-        __DoLogic_FB_TalkArea(curPlayer, content)
-    
-    return True
-
-## 副本中说话
-#  @param curPlayer 当前玩家
-#  @param content 讲话的内容
-#  @return None
-#  @remarks 函数详细说明.
-def __DoLogic_FB_TalkArea(curPlayer, content):
-    playerManager = GameWorld.GetMapCopyPlayerManager()
-    
-    for index in range(0 , playerManager.GetPlayerCount()):
-        #广播玩家
-        tempPlayer = playerManager.GetPlayerByIndex(index)
-        if not tempPlayer.GetPlayerID():
-            continue
+    #GameWorld.DebugLog("OnTalk channelType=%s, %s" % (channelType, GameWorld.CodeToGbk(content)))
+    if channelType == IPY_GameWorld.tcFamily:
+        if not familyID:
+            PlayerControl.NotifyCode(curPlayer, "jiazu_lhs_0")
+            return
         
-        #单个广播说话
-        extras = GetTalkExtraValue(curPlayer)
-        tempPlayer.Sync_ChatArea(curPlayer.GetPlayerID(), content, 0, extras)
+    elif channelType == IPY_GameWorld.tcCountry:
+        if GameWorld.IsCrossServer():
+            return
+        if not CrossRealmPlayer.IsCrossServerOpen():
+            PlayerControl.NotifyCode(curPlayer, "CrossMatching18")
+            return
         
+    if not __CheckTalk(curPlayer, channelType, content, tick):
+        return
+    
+    curPlayer.SetLastChatTick(tick)
+    curPlayer.SetDict(ChConfig.Def_ChannelTalkTick % channelType, tick)
+    
+    if channelType == IPY_GameWorld.tcCountry:
+        #发送到跨服,待扩展
+        return
+    
+    bubbleBox = PlayerControl.GetChatBubbleBox(curPlayer) # 气泡框
+    
+    clientPack = ChPyNetSendPack.tagMCTalk()
+    clientPack.ChannelType = channelType
+    clientPack.PlayerID = playerID
+    clientPack.Name = curPlayer.GetPlayerName()
+    clientPack.NameLen = len(clientPack.Name)
+    clientPack.Content = content
+    clientPack.Len = len(clientPack.Content)
+    clientPack.BubbleBox = bubbleBox
+    clientPack.LV = curPlayer.GetLV()
+    clientPack.Job = curPlayer.GetJob()
+    clientPack.RealmLV = curPlayer.GetOfficialRank()
+    clientPack.Face = curPlayer.GetFace()
+    clientPack.FacePic = curPlayer.GetFacePic()
+    clientPack.ServerID = GameWorld.GetPlayerServerID(curPlayer)
+    
+    if channelType == IPY_GameWorld.tcWorld:
+        NetPackCommon.SendFackPackOnline(clientPack)
+    elif channelType == IPY_GameWorld.tcFamily:
+        PlayerFamily.Broadcast_FamilyPack(familyID, clientPack)
+        
+    DoTalkCache(channelType, playerID, content, bubbleBox, familyID)
     return
 
-## 世界频道(封包参数)
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def TalkWorld(index, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    
-    sendPack = IPY_GameWorld.IPY_CTalkGong()
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    #通用检测
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, checkSameMsg = False, talkType=IPY_GameWorld.tcWorld):
-        return
-            
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcWorld, tick)
-    #发送聊天内容
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatGong(content, 0, extras)
-    #世界频道发言成就
-    #PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_TalkWorld, 1)
-    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_FeastRedPack_TalkWorld, 1)
-    EventShell.EventRespons_Talk(curPlayer, 'talkworld')
-    return
-
-## 国家频道(封包参数)
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def TalkCountry(index, tick):
-    ## 跨服世界频道
-    if GameWorld.IsCrossServer():
-        return
-    
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    
-    if not CrossRealmPlayer.IsCrossServerOpen():
-        PlayerControl.NotifyCode(curPlayer, "CrossMatching18")
-        return
-    
-    sendPack = IPY_GameWorld.IPY_CTalkCountry()
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    #通用检测
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, checkSameMsg = False, talkType=IPY_GameWorld.tcCountry):
-        return
-    
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcCountry, tick)
-    #发送聊天内容
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatCountry(content, 0, extras)
-    return
-
-## 联盟家族频道(封包参数)
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def TalkFamily(index, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    if curPlayer.GetFamilyID() == 0:
-        PlayerControl.NotifyCode(curPlayer, "jiazu_lhs_0 ")
-        return
-    
-    sendPack = IPY_GameWorld.IPY_CTalkBang()
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, talkType=IPY_GameWorld.tcFamily):
-        return
-    
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcFamily, tick)
-    
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatFamily(content, 0, extras)
-    #仙盟频道发言成就
-    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_TalkFamily, 1)
-    EventShell.EventRespons_Talk(curPlayer, 'talkfamily')
-    return
-
-## 队伍频道(封包参数)
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def TalkTeam(index, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    if curPlayer.GetTeam() == None:
-        PlayerControl.NotifyCode(curPlayer, "GeRen_lhs_161795 ")
-        return
-    
-    sendPack = IPY_GameWorld.IPY_CTalkDui()
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, talkType=IPY_GameWorld.tcTeam):
-        return
-    
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcTeam, tick)
-    #说话
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatTeam(content, 0, extras)
-    return
-
-
-## 私聊频道(封包参数)
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def TalkPrivate(index, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    sendPack = IPY_GameWorld.IPY_CTalkMiFix()
-    
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, talkType=IPY_GameWorld.tcPrivate):
-        return
-    
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcPrivate, tick)
-    #说话
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatMiByID(sendPack.GetTalkType(), sendPack.GetPlayerID(), content, 0, extras)
-    return
-
-def TalkPrivateByID(curPlayer, tagPlayerID, content):
-    #私聊 0为默认 1为1对1聊天
-    talkType = 1
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatMiByID(talkType, tagPlayerID, content, 0, extras)
-    return
-
-
-
-## 私聊频道(封包参数)
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def TalkPrivateName(index, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    sendPack = IPY_GameWorld.IPY_CTalkMi()
-    #玩家聊天内容
-    content = sendPack.GetContent()
-    
-    if not __CheckTalk(curPlayer, content, sendPack.GetLen(), tick, talkType=IPY_GameWorld.tcPrivate):
-        return
-    
-    #通用设置
-    SetTalkTime(curPlayer, content, IPY_GameWorld.tcPrivate, tick)
-    #说话
-    extras = GetTalkExtraValue(curPlayer)
-    curPlayer.ChatMiByName(sendPack.GetTalkType(), sendPack.GetTargetName(), content, 0, extras)
-    return
-
-    
-#-3秒重复,;聊天信息太长
-## 聊天通用检查 
-#  @param curPlayer 当前玩家 
-#  @param content 聊天内容 
-#  @param length 聊天长度 
-#  @param tick 当前时间 
-#  @param checkGMForbidenTalk 检查是否禁言 
-#  @param checkSameMsg 是否检查相同信息
-#  @return True or False
-#  @remarks 函数详细说明.
-def __CheckTalk(curPlayer, content, length, tick, checkGMForbidenTalk = True, checkSameMsg = True, talkType=None):
+def __CheckTalk(curPlayer, channelType, content, tick, checkGMForbidenTalk=True):
+    ## 聊天通用检查 
     if checkGMForbidenTalk and GetGMToolForbidTalk(curPlayer):
         #GeRen_chenxin_921745 对不起,您已被GM禁言,发送信息失败
         #PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_921745")
@@ -274,18 +116,18 @@
         return False
     
     #频道各自间隔时间
-    if talkType != None:
+    if channelType != None:
         talkCDDict = IpyGameDataPY.GetFuncEvalCfg("TalkCD", 1, {})
-        if str(talkType) in talkCDDict:
-            cdTicks = talkCDDict[str(talkType)] * 1000
-            lastTalkTick = curPlayer.GetTalkTick(talkType)
+        if str(channelType) in talkCDDict:
+            cdTicks = talkCDDict[str(channelType)] * 1000
+            lastTalkTick = curPlayer.GetDictByKey(ChConfig.Def_ChannelTalkTick % channelType)
             remainTick = cdTicks - (tick - lastTalkTick)
             if remainTick > 0:
-                PlayerControl.NotifyCode(curPlayer, "CanootTalk01", [int(math.ceil(remainTick/1000.0))])
+                PlayerControl.NotifyCode(curPlayer, "CanootTalk01", [int(math.ceil(remainTick / 1000.0))])
                 return False
             
     #聊天信息太长
-    if length > ChConfig.Def_PlayerTalkMaxCount :
+    if len(content) > ChConfig.Def_PlayerTalkMaxCount:
         PlayerControl.NotifyCode(curPlayer, "CanootTalk13")
         return False
     
@@ -296,315 +138,97 @@
     
     return True
 
-
-## 获得玩家是否被禁言 
-#  @param curPlayer 当前玩家
-#  @return 是否禁言
 def GetGMToolForbidTalk(curPlayer):
-    
+    ## 获得玩家是否被禁言 
     #accIDForbid = (curPlayer.GetAccState() & pow(2, ChConfig.Def_PysForbidTalk)) > 0
-    
     return curPlayer.GetGMForbidenTalk()# or accIDForbid
 
-
-## 聊天时间通用设置 
-#  @param curPlayer 当前玩家
-#  @param content 聊天内容
-#  @param type 类型
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def SetTalkTime(curPlayer, content, type, tick):
-    #设置当前时间为玩家开始聊天时间
-    curPlayer.SetLastChatTick(tick)
-    #设置当前聊天内容为玩家本次聊天内容
-    #curPlayer.SetLastChatContent(content)
-    #设置当前频道时间
-    curPlayer.SetTalkTick(type, tick)
-    return
-
-## 信件2B封包
-#  @param index 玩家索引
-#  @param tick 当前时间
-#  @return None
-#  @remarks 函数详细说明.
-def GBLetter(index, tick):
-    #===========================================================================
-    # curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    # sendPack = IPY_GameWorld.IPY_CGBLetter()
-    # 
-    # if tick - curPlayer.GetTickByType(ChConfig.TYPE_Player_Tick_GBLetter) <= ChConfig.TYPE_Player_Tick_Time[ChConfig.TYPE_Player_Tick_GBLetter]:
-    #    #发信1秒间隔
-    #    return
-    # 
-    # curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_GBLetter, tick)
-    # 
-    # #信件标题和内容
-    # titleStr = sendPack.GetTitle()
-    # contentStr = sendPack.GetContent()
-    # 
-    # #发给GM
-    # curPlayer.Interface_SendGMLetter(titleStr, contentStr)
-    #===========================================================================
-    return
-    
-## 记录玩家聊天内容
-#  @param messageStr 聊天类型
-#  @param curPlayer 聊天的玩家
-#  @param tagPlayer None
-#  @param content 聊天内容
-#  @param addinfo 额外信息
-#  @return None
-#  @remarks 函数详细说明.
-def __LogInDBPlayerTalk(messageStr , curPlayer , tagPlayer , content, addinfo=""):
-    # 由客户端向后台发送
-    return
-    #===========================================================================
-    # tagName = "" if not tagPlayer else tagPlayer.GetName()
-    # #EventReport.WriteEvent_chat_log(curPlayer, content, messageStr, tagName, addinfo)
-    # gameWorld = GameWorld.GetGameWorld()
-    # #开关未开启
-    # if not gameWorld.GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_PurTalk):
-    #    return
-    # 
-    # #将聊天内容存入数据库
-    # gameWorld.DataServer_TalkTrace('%s'%(messageStr), curPlayer, tagPlayer, content)
-    # return
-    #===========================================================================
-
-
-## 获取聊天内容附加值
-#  @param objTalk: 聊天对象
-#  @return: 聊天内容附加值
-def GetTalkExtraValue(objTalk):
-    vipLv = objTalk.GetVIPLv()  # 玩家vip等级
-    GMLevel = objTalk.GetGMLevel()
-    job = objTalk.GetJob()
-    playerID = objTalk.GetID()
-    
-    extraValueStr = ""
-    # vip等级
-    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_VipLv)%vipLv
-    # GM
-    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_GM)% (GMLevel > 0)
-    # job
-    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_JOB)% job
-    # 气泡框
-    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_BubbleBox) % PlayerControl.GetChatBubbleBox(objTalk)
-    # 服务器组ID
-    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_ServerGroupID) % PlayerControl.GetPlayerServerGroupID(objTalk)
-    # 等级
-    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_LV) % objTalk.GetLV()
-    # 伴侣信息
-    coupleName = PlayerControl.GetCoupleName(objTalk)
-    coupleJob = PlayerControl.GetCoupleJob(objTalk)
-    bridePriceMaxID = PlayerControl.GetBridePriceMaxID(objTalk)
-    face = objTalk.GetFace()
-    facePic = objTalk.GetFacePic()
-    extraValueStr = "%s|%s|%s|%s|%s|%s" % (extraValueStr, coupleName, coupleJob, bridePriceMaxID, face, facePic)
-    return extraValueStr
-
-
-## 附加信息的长度匹配
-#  @param extraValueInfo: 附加信息的长度
-#  @return: 
-def GetTalkExtraValueStar(extraValueType):
-    extraValueInfo = ShareDefine.Def_TalkExtraValue_LenDict.get(extraValueType)
-    extraValueLen = extraValueInfo[1] - extraValueInfo[0]
-    
-    return "%0" + str(extraValueLen) + "d"
-
-
-#// A2 17 喇叭聊天 #tagCMPYSpeaker
-#
-#struct    tagCMPYSpeaker
-#{
-#    tagHead        Head;
-#    BYTE        SpeakerType;        //1-本服;2-跨服
-#    BYTE        IsUseGold;        //是否使用钻石
-#    BYTE        ItemIndex;        //使用物品说话时, 物品Index
-#    BYTE        TextLen;        //字符长度
-#    char        Text[TextLen];        //size = TextLen
-#};
-def OnUsePYSpeaker(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    playerID = curPlayer.GetPlayerID()
-    SpeakerType = clientData.SpeakerType
-    IsUseGold = clientData.IsUseGold
-    ItemIndex = clientData.ItemIndex
-    TextLen = clientData.TextLen
-    Text = clientData.Text
-    
-    #GameWorld.Log("玩家喇叭聊天: SpeakerType=%s,IsUseGold=%s,ItemIndex=%s" 
-    #              % (SpeakerType, IsUseGold, ItemIndex), playerID)
-    if not __CheckTalk(curPlayer, Text, TextLen, tick):
+def DoTalkCache(channelType, playerID, content, bubbleBox, familyID=0):
+    # 聊天缓存
+    if channelType not in ChannelCacheMax:
         return
+    cacheMaxDict = IpyGameDataPY.GetFuncEvalCfg("TalkCache", 1, {})
+    maxCount = min(ChannelCacheMax[channelType], cacheMaxDict.get(channelType, 0))
     
-
-    if IsUseGold:
-        bugleItemID = IpyGameDataPY.GetFuncCfg('BugleItem', SpeakerType)
-        if not bugleItemID:
-            GameWorld.ErrLog("功能配置表没有配置对应喇叭类型物品消耗!SpeakerType=%s,请检查BugleItem!" % SpeakerType)
-            return
-        costMoney = ItemCommon.GetAutoBuyItemNeedGold({bugleItemID:1})
-        if not costMoney:
-            return
-        moneyType = IPY_GameWorld.TYPE_Price_Gold_Money
-        infoDict = {"SpeakerType":SpeakerType, ChConfig.Def_Cost_Reason_SonKey:bugleItemID}
-        if not PlayerControl.PayMoney(curPlayer, moneyType, costMoney, ChConfig.Def_Cost_UseSpeaker, infoDict, 1):
-            return
-    
-    # 检查使用喇叭道具
-    elif not ChItem.DoSpeaker_UseItem(curPlayer, ItemIndex, SpeakerType):
-        GameWorld.Log("    喇叭道具不可用!", playerID)
-        return
-    
-    #通知世界服务器,使用小喇叭
-    extraValue = 0
-    extras = GetTalkExtraValue(curPlayer)
-    msgList = str([SpeakerType, Text, extraValue, extras])
-    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(playerID, 0, 0, 'PYSpeaker', msgList, len(msgList))
-
-    return
-
-
-
-#// A2 16 自定义玩家聊天 #tagCMPyTalk
-#
-#struct    tagCMPyTalk
-#{
-#    tagHead        Head;
-#    BYTE        TalkType;        // 自定义聊天类型
-#    WORD        Len;
-#    char        Content[Len];        //size = Len
-#};
-## 自定义玩家聊天
-#  @param index
-#  @param clientData
-#  @param tick
-#  @return
-def OnPyTalk(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    
-    #GameWorld.DebugLog("OnPyTalk, Name:%s" % curPlayer.GetPlayerName())
-    
-    talkType = clientData.TalkType
-    contentLen = clientData.Len
-    content = clientData.Content
-    
-    if talkType not in ShareDefine.TalkTypeList:
-        GameWorld.ErrLog("OnPyTalk talkType(%s) is not define!" % talkType, curPlayer.GetPlayerID())
-        return
-    
-    #通用判断
-    if not __CheckTalk(curPlayer, content, contentLen, tick):
-        return
-    
-    #说话
-    extraValue = 0
-    extras = GetTalkExtraValue(curPlayer)
-    
-    isChatOK = False
-    if talkType == ShareDefine.Def_TalkType_FBFaction:
-        isChatOK = __ChatFBFaction(curPlayer, talkType, content, extraValue, extras)
+    # 仙盟聊天存FamilyAction
+    if channelType == IPY_GameWorld.tcFamily:
+        familyActonMgr = DBDataMgr.GetFamilyActionMgr().GetFamilyAction(familyID, ShareDefine.Def_ActionType_TalkCache)
+        actionData = familyActonMgr.AddAction(maxCount)
+        actionData.SetValue1(playerID)
+        actionData.SetValue2(bubbleBox)
+        actionData.GetUserDict().update({"content":content})
         
-    if not isChatOK:
-        return
-    
-    #设置当前时间为玩家开始聊天时间
-    curPlayer.SetLastChatTick(tick)
-    #设置当前聊天内容为玩家本次聊天内容
-    curPlayer.SetLastChatContent(content)
-    
-    return True
+    else:
+        recTypeIDMgr = DBDataMgr.GetGameRecMgr().GetRecTypeIDMgr(ShareDefine.Def_GameRecType_TalkCache, channelType)
+        recData = recTypeIDMgr.AddRecData(maxCount)
+        recData.SetValue1(playerID)
+        recData.SetValue2(bubbleBox)
+        recData.GetUserDict().update({"content":content})
+        
+    return
 
-## py自定义聊天推送包
-def __GetPyTalkPack(curPlayer, talkType, content, extraValue, extras):
-    pyTalk = ChPyNetSendPack.tagMCPyTalk()
-    pyTalk.Clear()
-    pyTalk.TalkType = talkType
-    pyTalk.Name = curPlayer.GetPlayerName()
-    pyTalk.NameLen = len(pyTalk.Name)
-    pyTalk.PlayerID = curPlayer.GetPlayerID()
-    pyTalk.Len = len(content)
-    pyTalk.Content = content
-    pyTalk.ExtraValue = extraValue
-    pyTalk.Extras = extras
-    return pyTalk
-
-## 副本阵营聊天
-def __ChatFBFaction(curPlayer, talkType, content, extraValue, extras):
-    curFaction = curPlayer.GetFaction()
-    if not curFaction:
-        return False
+def NotifyTalkCache(curPlayer):
+    ##上线通知聊天缓存
     
-    pyTalkPack = __GetPyTalkPack(curPlayer, talkType, content, extraValue, extras)
-    
-    playerManager = GameWorld.GetMapCopyPlayerManager()
-    for index in range(playerManager.GetPlayerCount()):
-        player = playerManager.GetPlayerByIndex(index)
-        if not player:
+    for channelType in ChannelCacheMax.keys():
+        cacheList = []
+        if channelType == IPY_GameWorld.tcFamily:
+            familyID = curPlayer.GetFamilyID()
+            if not familyID:
+                continue
+            familyActonMgr = DBDataMgr.GetFamilyActionMgr().GetFamilyAction(familyID, ShareDefine.Def_ActionType_TalkCache)
+            for index in range(familyActonMgr.Count()):
+                actionData = familyActonMgr.At(index)
+                talkTime = actionData.GetTime()
+                playerID = actionData.GetValue1()
+                bubbleBox = actionData.GetValue2()
+                content = actionData.GetUserDict().get("content", "")
+                if not content:
+                    content
+                cacheList.append([talkTime, playerID, bubbleBox, content])
+        else:
+            recTypeIDMgr = DBDataMgr.GetGameRecMgr().GetRecTypeIDMgr(ShareDefine.Def_GameRecType_TalkCache, channelType)
+            for index in range(recTypeIDMgr.GetCount()):
+                recData = recTypeIDMgr.At(index)
+                talkTime = recData.GetTime()
+                playerID = recData.GetValue1()
+                bubbleBox = recData.GetValue2()
+                content = recData.GetUserDict().get("content", "")
+                if not content:
+                    content
+                cacheList.append([talkTime, playerID, bubbleBox, content])
+                
+        if not cacheList:
             continue
         
-        if player.GetFaction() != curFaction:
+        packCacheList = []
+        for talkTime, playerID, bubbleBox, content in cacheList:
+            viewCache = PlayerViewCache.FindViewCache(playerID)
+            if not viewCache:
+                continue
+            talkCache = ChPyNetSendPack.tagMCTalkCacheInfo()
+            talkCache.PlayerID = playerID
+            talkCache.Name = viewCache.GetPlayerName()
+            talkCache.NameLen = len(talkCache.Name)
+            talkCache.Content = content
+            talkCache.Len = len(talkCache.Content)
+            talkCache.BubbleBox = bubbleBox
+            talkCache.LV = viewCache.GetLV()
+            talkCache.Job = viewCache.GetJob()
+            talkCache.RealmLV = viewCache.GetRealmLV()
+            talkCache.Face = viewCache.GetFace()
+            talkCache.FacePic = viewCache.GetFacePic()
+            talkCache.ServerID = viewCache.GetServerID()
+            talkCache.TalkTime = talkTime
+            packCacheList.append(talkCache)
+            
+        if not packCacheList:
             continue
         
-        if PlayerTJG.GetIsTJG(player):
-            continue
+        clientPack = ChPyNetSendPack.tagMCTalkCacheList()
+        clientPack.ChannelType = channelType
+        clientPack.InfoList = packCacheList
+        clientPack.Count = len(clientPack.InfoList)
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
         
-        NetPackCommon.SendFakePack(player, pyTalkPack)
-        
-    return True
-
-
-#===============================================================================
-# //A2 26 语音聊天 #tagCMVoiceChat
-# 
-# struct    tagCMVoiceChat
-# {
-#    tagHead        Head;
-#    BYTE        ChannelType;     //  5 区域 --- 查看封包tagCGVoiceChat 1 世界 2 仙盟 3 私聊(好友) 4 队伍
-#    BYTE        TargetNameLen;
-#    char        TargetName[TargetNameLen];        //size = TargetNameLen
-#    DWORD        TargetID;        // 默认发玩家ID,没有ID才发名称
-#    WORD        Len;
-#    BYTE        Content[Len];        //size = Len
-# };
-#===============================================================================
-def OnVoiceChat(index, clientPack, tick):
-#    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-#    if GetGMToolForbidTalk(curPlayer):
-#        return
-#    if clientPack.ChannelType != ShareDefine.Def_ChannelChat_Area:
-#        return
-#    sendPack = ChPyNetSendPack.tagGCVoiceChat()
-#    sendPack.Clear()
-#    sendPack.ChannelType = clientPack.ChannelType
-#    sendPack.SrcName = curPlayer.GetName()
-#    sendPack.SrcNameLen = len(curPlayer.GetName())
-#    sendPack.PlayerID = curPlayer.GetID()
-#    sendPack.Len = clientPack.Len
-#    sendPack.Content = clientPack.Content
-#    sendPack.Extras = GetTalkExtraValue(curPlayer)
-#    sendPack.ExtraValue = len(sendPack.Extras)
-#    
-#    # 区域频道
-#    
-#    #如果在普通地图, 就广播, 如果在副本就单个通知
-#    if GameWorld.GetMap().GetMapFBType() == IPY_GameWorld.fbtNull:
-#        curPlayer.BroadCastAll(sendPack.GetBuffer(), len(sendPack.GetBuffer()))
-#    else:
-#        playerManager = GameWorld.GetMapCopyPlayerManager()
-#        
-#        for index in range(0 , playerManager.GetPlayerCount()):
-#            #广播玩家
-#            tempPlayer = playerManager.GetPlayerByIndex(index)
-#            if not tempPlayer.GetPlayerID():
-#                continue
-#            
-#            if PlayerTJG.GetIsTJG(tempPlayer):
-#                continue
-#                
-#            NetPackCommon.SendFakePack(tempPlayer, sendPack)
     return
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
new file mode 100644
index 0000000..cd5d600
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
@@ -0,0 +1,298 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerViewCache
+#
+# @todo:玩家缓存
+# @author hxp
+# @date 2025-5-22
+# @version 1.0
+#
+# 详细描述: 玩家缓存
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-5-22 下午6:37:10"""
+#-------------------------------------------------------------------------------
+
+import ChConfig
+import GameWorld
+import PyMongoMain
+import PlayerControl
+import NetPackCommon
+import ChPyNetSendPack
+import IpyGameDataPY
+import ShareDefine
+import DBDataMgr
+import GameObj
+
+import random
+import time
+
+Key_UpdViewCacheTick = "UpdViewCacheTick"
+
+def OnDay():
+    DelOutofTimeViewCacheData()
+    return
+
+def OnPlayerLogout(curPlayer):
+    if curPlayer.GetLV() < 10:
+        return
+    
+    curCache = UpdPlayerViewCache(curPlayer)
+    if curCache and not IsSaveDBViewCache(curCache):
+        DBDataMgr.GetPlayerViewCacheMgr().DelPlayerViewCache(curPlayer.GetPlayerID())
+        
+    return
+
+def DelOutofTimeViewCacheData():
+    ## 删除过期的查看缓存数据
+    
+    playerManager = GameWorld.GetPlayerManager()
+    viewCacheMgr = DBDataMgr.GetPlayerViewCacheMgr()
+    for index in range(viewCacheMgr.GetCount())[::-1]: # 有删除需倒序遍历
+        viewCache = viewCacheMgr.At(index)
+        playerID = viewCache.GetPlayerID()
+        curPlayer = playerManager.FindPlayerByID(playerID)
+        if curPlayer:
+            continue
+        if IsSaveDBViewCache(viewCache):
+            continue
+        viewCacheMgr.DelPlayerViewCache(playerID)
+        
+    return
+
+def IsSaveDBViewCache(viewCache):
+    ## 缓存数据是否入库
+    if not viewCache:
+        return False
+    
+    playerID = viewCache.GetPlayerID()
+    
+    #某个功能中不能删除的
+    #...
+    
+    
+    #排行版上的默认保留
+    billboardMgr = DBDataMgr.GetBillboardMgr()
+    for bType in ShareDefine.BillboardTypeAllList:
+        if bType in ShareDefine.FamilyBillboardList:
+            continue
+        groupList = billboardMgr.GetBillboardGroupList(bType)
+        for billboardType, groupValue1, groupValue2 in groupList:
+            billboardObj = billboardMgr.GetBillboard(billboardType, groupValue1, groupValue2)
+            if billboardObj.FindByID(playerID):
+                return True
+            
+    # 以上是相关功能需要用到的数据,必定不能删除的
+    
+    # 以下是保留近期活跃玩家,等级限制
+    playerLV = viewCache.GetLV()
+    if playerLV >= IpyGameDataPY.GetFuncCfg("PlayerViewCache", 1):
+        maxDays = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 2)
+        if not maxDays:
+            maxDays = 7 # 默认7天
+        MaxTime = maxDays * 3600 * 24
+        curTime = int(time.time())
+        passTime = curTime - viewCache.GetOffTime()
+        if passTime < MaxTime:
+            return True
+        
+    return False
+
+def FindViewCache(playerID, isAdd=False):
+    '''查找玩家缓存,如果不存在,则会有额外逻辑,如从redis、db直接找,
+            本服玩家理论上一定有查看缓存,因为如果不存在会直接从db读,除非该玩家数据被删除
+            跨服玩家理论上也一定有缓存,只是通过跨服或从子服查询,延迟获得
+            【注】外层调用依然要判断是否有数据
+    '''
+    
+    viewCacheMgr = DBDataMgr.GetPlayerViewCacheMgr()
+    curCache = viewCacheMgr.GetPlayerViewCache(playerID)
+    if curCache:
+        updCache = __CheckUpdViewCache(playerID)
+        if updCache:
+            curCache = updCache
+            
+    # 真实玩家
+    elif playerID > ShareDefine.FackPlayerIDMax:
+        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        # 本服在线玩家,直接生成新数据
+        if curPlayer:
+            curCache = viewCacheMgr.AddPlayerViewCache(playerID)
+            UpdPlayerViewCache(curPlayer)
+            
+        # 本服离线玩家
+        elif GameWorld.GetDBPlayerAccIDByID(playerID):
+            # 本服玩家,从redis或db读取重新加载读取,换句话说,本服玩家只要获取一定有查看缓存数据
+            curCache = UpdPlayerViewCacheByDB(playerID)
+            
+        # 跨服玩家
+        else:
+            pass
+            # 跨服玩家,去子服拉取数据,理论上也一定有,但是如果需要拉数据,有一定延迟
+            # 逻辑待扩展
+            
+    # 假玩家,默认添加
+    elif ShareDefine.FackPlayerIDStart <= playerID <= ShareDefine.FackPlayerIDMax:
+        serverID = playerID % 100 + 1 # 1 ~ 100 服
+        accID = "fake%s@test@s%s" % (playerID, serverID)
+        fightPower = random.randint(1000000, 100000000) # 先随机,外层有需要的话再自己设置
+        
+        curCache = viewCacheMgr.AddPlayerViewCache(playerID)
+        curCache.SetPlayerName("%s%s" % (GameWorld.GbkToCode("神秘道友"), playerID))
+        curCache.SetAccID(accID)
+        curCache.SetLV(random.randint(100, 200))
+        curCache.SetJob(random.randint(1, 2))
+        curCache.SetRealmLV(random.randint(5, 15))
+        curCache.SetFightPowerTotal(fightPower)
+        curCache.SetServerID(serverID)
+        curCache.SetOffTime(int(time.time()) - random.randint(1, 3600 * 24 * 10)) # 随机离线 0~10天
+        
+    return curCache
+
+def __CheckUpdViewCache(playerID):
+    if playerID <= ShareDefine.FackPlayerIDMax:
+        return
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    lastUpdTick = curPlayer.GetDictByKey(Key_UpdViewCacheTick)
+    tick = GameWorld.GetGameWorld().GetTick()
+    if lastUpdTick and tick - lastUpdTick < 60000:
+        GameWorld.DebugLog("1分钟内只更新一次玩家缓存", playerID)
+        return
+    curPlayer.SetDict(Key_UpdViewCacheTick, tick)
+    return UpdPlayerViewCache(curPlayer)
+
+def UpdPlayerViewCache(curPlayer, isOffline=False):
+    '''更新玩家查看缓存数据,更新时机由外层自己判断,这里只做更新逻辑
+    1. 下线时强制更新一次,上线暂不更新,上线时由各功能如果有需要用到触发更新
+    2. 有需要用到缓存数据时,如果玩家在线,1分钟内多次获取时最多更新一次,没有获取缓存数据则不更新
+    '''
+    if not curPlayer:
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    curCache = DBDataMgr.GetPlayerViewCacheMgr().GetPlayerViewCache(playerID)
+    if not curCache:
+        return
+    
+    tick = GameWorld.GetGameWorld().GetTick()
+    curPlayer.SetDict(Key_UpdViewCacheTick, tick)
+    GameWorld.DebugLog("更新玩家查看缓存数据! isOffline=%s" % isOffline, playerID)
+    curCache.SetAccID(curPlayer.GetAccID())
+    curCache.SetPlayerName(curPlayer.GetPlayerName())
+    curCache.SetLV(curPlayer.GetLV())
+    curCache.SetJob(curPlayer.GetJob())
+    curCache.SetRealmLV(curPlayer.GetOfficialRank())
+    curCache.SetFace(curPlayer.GetFace())
+    curCache.SetFacePic(curPlayer.GetFacePic())
+    curCache.SetFamilyID(curPlayer.GetFamilyID())
+    curCache.SetFamilyName(curPlayer.GetFamilyName())
+    curCache.SetFamilyEmblemID(PlayerControl.GetFamilyEmblemID(curPlayer))
+    curCache.SetTitleID(PlayerControl.GetTitleID(curPlayer))
+    curCache.SetFightPowerTotal(PlayerControl.GetFightPower(curPlayer))
+    curCache.SetServerID(GameWorld.GetPlayerServerID(curPlayer))
+    if isOffline:
+        curCache.SetOffTime(int(time.time()))
+        
+    plusDict = curCache.GetPlusDict()
+        
+    #战斗属性
+    plusDict.update({
+                     "MinAtk":curPlayer.GetMinAtk(),
+                     "MaxAtk":curPlayer.GetMaxAtk(),
+                     "Def":curPlayer.GetDef(),
+                     "MaxHP":GameObj.GetMaxHP(curPlayer),
+                     "Hit":curPlayer.GetHit(),
+                     "Miss":curPlayer.GetMiss(),
+                     "SuperHitRate":curPlayer.GetSuperHitRate(), # 暴击率
+                     })
+    
+    # 功能数据
+    
+    # 其他
+    
+    return curCache
+
+def UpdPlayerViewCacheByDB(playerID):
+    '''更新玩家查看缓存数据,直接从db数据更新,仅更新dbPlayer表有的属性,
+    '''
+    GameWorld.DebugLog("UpdPlayerViewCacheByDB", playerID)
+    curCache = None
+    dbPlayer = PyMongoMain.GetUserCtrlDB().findDBPlayer(playerID)
+    if not dbPlayer:
+        GameWorld.DebugLog("1111111111111111", playerID)
+        return curCache
+    viewCacheMgr = DBDataMgr.GetPlayerViewCacheMgr()
+    curCache = viewCacheMgr.GetPlayerViewCache(playerID)
+    if not curCache:
+        curCache = viewCacheMgr.AddPlayerViewCache(playerID)
+    familyID = dbPlayer.FamilyID
+    GameWorld.DebugLog("db查找直接更新玩家查看缓存数据!", playerID)
+    curCache.SetAccID(dbPlayer.AccID)
+    curCache.SetPlayerName(dbPlayer.PlayerName)
+    curCache.SetLV(dbPlayer.LV)
+    curCache.SetJob(dbPlayer.Job)
+    curCache.SetRealmLV(dbPlayer.OfficialRank)
+    curCache.SetFace(dbPlayer.Face)
+    curCache.SetFacePic(dbPlayer.FacePic)
+    curCache.SetFamilyID(familyID)
+    family = DBDataMgr.GetFamilyMgr().FindFamily(familyID)
+    curCache.SetFamilyName(family.GetName() if family else "")
+    curCache.SetFamilyEmblemID(family.GetEmblemID() if family else 0)
+    #curCache.SetTitleID(PlayerControl.GetTitleID(curPlayer))
+    curCache.SetFightPowerTotal(dbPlayer.FightPowerEx * ChConfig.Def_PerPointValue + dbPlayer.FightPower)
+    curCache.SetServerID(GameWorld.GetAccIDServerID(dbPlayer.AccID))
+    curCache.SetOffTime(GameWorld.ChangeTimeStrToNum(dbPlayer.LogoffTime) if dbPlayer.LogoffTime else 0)
+    return curCache
+
+#//A2 12 查看玩家详细信息#tagCMViewPlayerInfo
+#struct tagCMViewPlayerInfo
+#{
+#    tagHead        Head;
+#    DWORD        PlayerID;
+#    BYTE        EquipClassLV;    //大于0为查看指定境界阶装备信息,  0为查看默认信息
+#};
+def OnCMViewPlayerInfo(index, clientPack, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    
+    findPlayerID = clientPack.PlayerID
+    #equipClassLV = clientPack.EquipClassLV
+    
+    clientPack = GetPack_ViewCache(findPlayerID)
+    if clientPack:
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+        return
+    if GameWorld.GetDBPlayerAccIDByID(findPlayerID):
+        PlayerControl.NotifyCode(curPlayer, "ViewPlayer_OffLine")
+        return
+    
+    # 跨服玩家发送跨服查询,待扩展...
+    
+    return
+
+def GetPack_ViewCache(playerID):
+    ## 获取同步封包 - 玩家查看缓存
+    curCache = FindViewCache(playerID)
+    if not curCache:
+        return
+    clientPack = ChPyNetSendPack.tagSCQueryPlayerCacheResult()
+    clientPack.PlayerID = curCache.GetPlayerID()
+    clientPack.PlayerName = curCache.GetPlayerName()
+    clientPack.LV = curCache.GetLV()
+    clientPack.Job = curCache.GetJob()
+    clientPack.RealmLV = curCache.GetRealmLV()
+    clientPack.Face = curCache.GetFace()
+    clientPack.FacePic = curCache.GetFacePic()
+    clientPack.TitleID = curCache.GetTitleID()
+    clientPack.ServerID = curCache.GetServerID()
+    clientPack.FightPower = curCache.GetFightPower()
+    clientPack.FightPowerEx = curCache.GetFightPowerEx()
+    clientPack.FamilyID = curCache.GetFamilyID()
+    clientPack.FamilyName = curCache.GetFamilyName()
+    clientPack.FamilyEmblemID = curCache.GetFamilyEmblemID()
+    clientPack.PlusData = curCache.GetPlusData()
+    clientPack.PlusDataSize = len(clientPack.PlusData)
+    return clientPack
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
deleted file mode 100644
index 7a9b4ad..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
+++ /dev/null
@@ -1,493 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#
-#
-##@package PlayerViewCacheTube.py
-#
-# @todo:玩家数据缓存 地图服务器处理模块
-#
-# @author xmnathan
-# @date 2010-01-01 21:30
-# @version 1.0
-# @note:
-#------------------------------------------------------------------------------ 
-#"""Version = 2017-11-27 22:30"""
-#------------------------------------------------------------------------------ 
-import ChConfig
-import GameWorld
-import ShareDefine
-import NetPackCommon
-import PlayerControl
-import IPY_GameWorld
-import ChPyNetSendPack
-import DBStruct
-import ChMapToGamePyPack
-import PlayerMagicWeapon
-import Operate_EquipStone
-import Operate_EquipWash
-import PlayerAttrFruit
-import ItemControler
-import IpyGameDataPY
-import PlayerHorse
-import ChEquip
-import ItemCommon
-import PyGameData
-import PlayerTJG
-import SkillShell
-import GameObj
-
-import base64
-import time
-import json
-
-TempDBPlayer = DBStruct.tagDBPlayer()
-
-Def_Process_Tick = "ProcessPlayerCache"
-
-def OnPlayerLogOut(curPlayer, tick):
-    ##玩家下线同步
-    UpdateGameServerPlayerCache(curPlayer, tick, True)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_EquipViewCacheState, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PackDataSyncState, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PackDataSyncFightPower, 0)
-    return
-
-def ProcessCache(curPlayer, tick):
-    ##玩家在线定时同步
-    lastTick = curPlayer.GetDictByKey(Def_Process_Tick)
-    if not lastTick:
-        curPlayer.SetDict(Def_Process_Tick, tick)
-        return
-    if tick - lastTick < 5 * 60 * 1000: # 同步玩家缓存间隔
-        return
-    UpdateGameServerPlayerCache(curPlayer, tick, False)
-    return
-
-def GetDBPlayerByPackData(packData):
-    ## 根据 curPlayer.GetPackData() 打包返回的数据获取DBPlayer数据
-    TempDBPlayer.clear()
-    if packData:
-        TempDBPlayer.readData(base64.b64decode(packData))
-    return TempDBPlayer
-
-def GetSyncPlayerPackData(curPlayer, force=False):
-    playerID = curPlayer.GetPlayerID()
-    fightPower = curPlayer.GetFightPower()
-    
-    if not force:
-        syncState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncState)
-        if not syncState:
-            GameWorld.DebugLog("不需要同步打包数据", playerID)
-            return ""
-        # 值判断求余部分即可
-        syncFightPower = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncFightPower)
-        if syncFightPower == fightPower:
-            GameWorld.DebugLog("战力不变,不需要同步打包数据! syncFightPower=%s" % syncFightPower, playerID)
-            return ""
-        
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PackDataSyncFightPower, fightPower)
-    packData = curPlayer.GetPackData()
-    #GameWorld.DebugLog("packData=%s %s %s" % (type(packData), len(packData), packData), playerID)
-    return packData
-
-def UpdPackDataSyncState(curPlayer, msgData):
-    ## 更新打包数据同步状态,这里只更新状态即可,具体同步由定时同步处理
-    syncState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncState)
-    updSyncState = syncState
-    if msgData.get("PackData"):
-        updSyncState = GameWorld.SetBitValue(updSyncState, 0, 1)
-    if msgData.get("PackDataCross"):
-        updSyncState = GameWorld.SetBitValue(updSyncState, 1, 1)
-    if msgData.get("ViewCacheCross"):
-        updSyncState = GameWorld.SetBitValue(updSyncState, 2, 1)
-    if syncState == updSyncState:
-        return
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PackDataSyncState, updSyncState)
-    GameWorld.DebugLog("更新打包数据同步状态: msgData=%s,syncState=%s,updSyncState=%s" 
-                       % (msgData, syncState, updSyncState), curPlayer.GetPlayerID())
-    return
-
-def SetPackDataSyncState(curPlayer): UpdPackDataSyncState(curPlayer, {"PackData":1})
-def SetPackDataCrossSyncState(curPlayer): UpdPackDataSyncState(curPlayer, {"PackDataCross":1})
-def SetViewCacheCrossSyncState(curPlayer): UpdPackDataSyncState(curPlayer, {"ViewCacheCross":1})
-
-def NormalSyncPackData(curPlayer):
-    '''常规同步打包数据,仅作为补充同步用,不强制同步
-    一般由需要打包数据的功能发起检查自动同步用,做战力验证,战力变更时主动同步一次
-    防止短时间内强化了战力,导致镜像数据差异太大,影响镜像战斗结果
-    '''
-    
-    syncFightPower = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncFightPower)
-    if PlayerControl.GetFightPower(curPlayer) == syncFightPower:
-        GameWorld.DebugLog("战力与打包数据相同,不同步!", curPlayer.GetPlayerID())
-        return
-    GameWorld.DebugLog("战力与打包数据不同,立即同步!", curPlayer.GetPlayerID())
-    
-    syncState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncState)
-    if not syncState:
-        SetPackDataSyncState(curPlayer)
-        SetPackDataCrossSyncState(curPlayer)
-        
-    tick = GameWorld.GetGameWorld().GetTick()
-    UpdateGameServerPlayerCache(curPlayer, tick)
-    return
-
-##更新玩家当前详细信息到GameServer
-#  @param curPlayer, tick
-#  @return None
-def UpdateGameServerPlayerCache(curPlayer, tick, IsLogouting=False, forcePackData=False, packMsg=None, isOnlyViewCache=False):
-    if PlayerTJG.GetIsTJG(curPlayer):
-        # 脱机不处理
-        return
-    curPlayer.SetDict(Def_Process_Tick, tick)
-    PackDataSyncState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncState)
-    isAllEquip = False
-    # 需要同步跨服缓存 且 还没同步装备的
-    if PackDataSyncState&pow(2, 2) and curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_EquipViewCacheState) != 2:
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_EquipViewCacheState, 2)
-        isAllEquip = True
-        GameWorld.DebugLog("本次登录首次同步跨服缓存,全装备同步", curPlayer.GetPlayerID())
-        
-    if forcePackData:
-        SetPackDataSyncState(curPlayer)
-        SetPackDataCrossSyncState(curPlayer)
-        PackDataSyncState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PackDataSyncState)
-        
-    #获取当前玩家缓存数据
-    PropData, PlusData = GetPlayerPropPlusCache(curPlayer)
-    itemDataDict = __GetPlayerItemDataCache(curPlayer, isAllEquip)
-    
-    #同步发送到GameServer
-    sendPack = ChMapToGamePyPack.tagMGUpdatePlayerCache()
-    sendPack.PlayerID = curPlayer.GetPlayerID()
-    sendPack.PlayerLV = curPlayer.GetLV()
-    sendPack.IsLogouting = IsLogouting #通知本次同步是否下线前保存
-    sendPack.OffTime = int(time.time())    # 最后一次发送即当做离线时间
-    sendPack.PropData = PropData
-    sendPack.PropDataSize = len(sendPack.PropData)
-    sendPack.PlusData = PlusData
-    sendPack.PlusDataSize = len(sendPack.PlusData)
-    for classLV, itemData in itemDataDict.items():
-        setattr(sendPack, "ItemData%s" % classLV, itemData)
-        setattr(sendPack, "ItemDataSize%s" % classLV, len(itemData))
-    # 打包数据相关
-    sendPack.PackDataSyncState = PackDataSyncState
-    sendPack.PackData = "" if isOnlyViewCache else GetSyncPlayerPackData(curPlayer, forcePackData)
-    sendPack.PackDataLen = len(sendPack.PackData)
-    sendPack.PackMsg = str(packMsg) if packMsg else "{}"
-    sendPack.PackMsgLen = len(sendPack.PackMsg)
-    GameWorld.DebugLog("同步缓存: logout=%s,forcePackData=%s,isOnlyViewCache=%s,PackDataSyncState=%s,isAllEquip=%s,classList=%s" 
-                       % (IsLogouting, forcePackData, isOnlyViewCache, PackDataSyncState, isAllEquip, itemDataDict.keys()), curPlayer.GetPlayerID())
-    NetPackCommon.SendPyPackToGameServer(sendPack)
-    return
-
-def __GetPlayerItemDataCache(curPlayer, isAllEquip=False):
-    ## 装备及装备位养成缓存,由于装备位比较多,所以按阶同步,重登第一次同步所有阶
-    if not isAllEquip and not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_EquipViewCacheState):
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_EquipViewCacheState, 1)
-        isAllEquip = True
-        
-    if isAllEquip:
-        needSyncClassLVList = xrange(1, IpyGameDataPY.GetFuncCfg('EquipMaxClasslv') + 1)
-    else:
-        playerID = curPlayer.GetPlayerID()
-        needSyncClassLVList = PyGameData.g_equipChangeClassLVInfo.pop(playerID, [])
-        
-    itemDataDict = {}
-    for classLV in needSyncClassLVList:
-        itemDataDict[classLV] = __GetPlayerEquipClassDataCache(curPlayer, classLV)
-        
-    return itemDataDict
-
-def __GetPlayerEquipClassDataCache(curPlayer, classLV):
-    ## 获取境界阶装备缓存数据
-    ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition('EquipPlaceIndexMap', {'ClassLV':classLV}, True)
-    if not ipyDataList:
-        return "{}"
-    
-    packType = IPY_GameWorld.rptEquip
-    equipPack = curPlayer.GetItemManager().GetPack(packType)
-    classItemDataDict = {}
-    for ipyData in ipyDataList:
-        index = ipyData.GetGridIndex()
-        
-        curEquip = equipPack.GetAt(index)
-        if not curEquip or curEquip.IsEmpty():
-            continue
-        
-        itemDict = {}
-        itemDict["ItemID"] = curEquip.GetItemTypeID()
-        userData = curEquip.GetUserData()
-        if userData and userData != "{}":
-            itemDict["UserData"] = userData
-            
-        classItemDataDict[index] = itemDict
-        classLV = ItemCommon.GetItemClassLV(curEquip)
-        if not classLV:
-            continue
-        
-        #部位升星数据
-        equipStar = ChEquip.GetEquipPartStarByRank(curPlayer, index, curEquip)
-        if equipStar:
-            itemDict["Star"] = equipStar
-            
-        #部位强化数据
-        equipPartPlusLV = ChEquip.GetEquipPartPlusLV(curPlayer, packType, index)
-        equipPartPlusEvolveLV = ChEquip.GetEquipPartPlusEvolveLV(curPlayer, packType, index)
-        if equipPartPlusLV:
-            itemDict["PlusLV"] = equipPartPlusLV
-        if equipPartPlusEvolveLV:
-            itemDict["EvolveLV"] = equipPartPlusEvolveLV
-            
-        #部位宝石数据
-        stoneIDList = Operate_EquipStone.GetEquipIndexStoneIDList(curPlayer, index)
-        if stoneIDList and stoneIDList.count(0) != len(stoneIDList):
-            itemDict["Stone"] = stoneIDList
-            
-        #部位洗练数据
-        washLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_EquipWashLV % index)
-        valueList = []
-        for attrNum in xrange(1, Operate_EquipWash.Def_EquipWashMaxAttrCount + 1):
-            value = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_EquipWashValue % (index, attrNum))
-            valueList.append(value)
-        if valueList and valueList.count(0) != len(valueList):
-            itemDict["Wash"] = {"LV":washLV, "Value":valueList}
-             
-    return json.dumps(classItemDataDict, ensure_ascii=False).replace(" ", "")
-
-def GetPlayerPropPlusCache(curPlayer):
-    #玩家属性缓存
-    curPlayerPropDict = {}
-    curPlayerPropDict["AccID"] = curPlayer.GetAccID()
-    curPlayerPropDict["LV"] = curPlayer.GetLV()
-    curPlayerPropDict["RealmLV"] = curPlayer.GetOfficialRank()
-    curPlayerPropDict["Job"] = curPlayer.GetJob()
-    curPlayerPropDict["VIPLV"] = curPlayer.GetVIPLv()
-    curPlayerPropDict["Name"] = curPlayer.GetPlayerName()
-    curPlayerPropDict["Face"] = curPlayer.GetFace()
-    curPlayerPropDict["FacePic"] = curPlayer.GetFacePic()
-    curPlayerPropDict["FamilyID"] = curPlayer.GetFamilyID()
-    curPlayerPropDict["FamilyName"] = curPlayer.GetFamilyName()
-    curPlayerPropDict["FamilyEmblemID"] = PlayerControl.GetFamilyEmblemID(curPlayer)
-    curPlayerPropDict["TitleID"] = PlayerControl.GetTitleID(curPlayer)
-    curPlayerPropDict["CoupleName"] = PlayerControl.GetCoupleName(curPlayer)
-    curPlayerPropDict["FightPower"] = PlayerControl.GetFightPower(curPlayer)
-    curPlayerPropDict["AppID"] = GameWorld.GetPlayerPlatform(curPlayer)
-    curPlayerPropDict["EquipShowSwitch"] = curPlayer.GetEquipShowSwitch()
-    curPlayerPropDict["EquipShowID"] = __GetEquipShowIDList(curPlayer)
-    curPlayerPropDict["ServerGroupID"] = PlayerControl.GetPlayerServerGroupID(curPlayer)
-    curPlayerPropDict["LingGenPoint"] = [PlayerControl.GetMetal(curPlayer), PlayerControl.GetWood(curPlayer), PlayerControl.GetWater(curPlayer), 
-                                         PlayerControl.GetFire(curPlayer), PlayerControl.GetEarth(curPlayer)]
-    
-    #战斗属性
-    curPlayerPropDict["MinAtk"] = curPlayer.GetMinAtk()
-    curPlayerPropDict["MaxAtk"] = curPlayer.GetMaxAtk()
-    curPlayerPropDict["Def"] = curPlayer.GetDef()
-    curPlayerPropDict["MaxHP"] = GameObj.GetMaxHP(curPlayer)
-    curPlayerPropDict["Hit"] = curPlayer.GetHit()
-    curPlayerPropDict["Miss"] = curPlayer.GetMiss()
-    curPlayerPropDict["SkillAtkRate"] = curPlayer.GetSkillAtkRate() # 技能攻击比例加成
-    curPlayerPropDict["SkillAtkRateReduce"] = PlayerControl.GetSkillAtkRateReduce(curPlayer) # 技能攻击比例减少
-    curPlayerPropDict["LuckyHitRate"] = curPlayer.GetLuckyHitRate() # 会心一击几率
-    curPlayerPropDict["LuckyHitVal"] = curPlayer.GetLuckyHitVal() # 会心一击伤害固定值
-    curPlayerPropDict["LuckyHitRateReduce"] = PlayerControl.GetLuckyHitRateReduce(curPlayer) # 会心一击概率抗性
-    curPlayerPropDict["LuckyHitReduce"] = PlayerControl.GetLuckyHitReduce(curPlayer) # 会心一击伤害减免固定值
-    curPlayerPropDict["SuperHitRate"] = curPlayer.GetSuperHitRate() # 暴击概率
-    curPlayerPropDict["SuperHit"] = curPlayer.GetSuperHit() # 暴击伤害固定值
-    curPlayerPropDict["SuperHitRateReduce"] = PlayerControl.GetSuperHitRateReduce(curPlayer) # 暴击概率抗性
-    curPlayerPropDict["SuperHitReduce"] = PlayerControl.GetSuperHitReduce(curPlayer) # 暴击伤害抗性固定值
-    curPlayerPropDict["IceAtk"] = curPlayer.GetIceAtk() # 真实伤害            固定值
-    curPlayerPropDict["IceDef"] = curPlayer.GetIceDef() # 真实伤害防御        固定值
-    curPlayerPropDict["IgnoreDefRate"] = curPlayer.GetIgnoreDefRate() # 无视防御几率
-    curPlayerPropDict["IgnoreDefRateReduce"] = PlayerControl.GetIgnoreDefRateReduce(curPlayer) # 无视防御概率抗性
-    curPlayerPropDict["IgnoreDefReducePer"] = PlayerControl.GetIgnoreDefReducePer(curPlayer) # 无视防御伤害减免
-    curPlayerPropDict["DamagePVE"] = PlayerControl.GetDamagePVE(curPlayer) # 伤害输出计算固定值PVE
-    curPlayerPropDict["DamagePerPVP"] = PlayerControl.GetDamagePerPVP(curPlayer) # 伤害输出计算百分比PVP
-    curPlayerPropDict["DamagePerPVPReduce"] = PlayerControl.GetDamagePerPVPReduce(curPlayer) # 伤害输出计算百分比PVP减少
-    curPlayerPropDict["DamagePVP"] = PlayerControl.GetDamagePVP(curPlayer) # PVP固定伤害
-    curPlayerPropDict["DamagePVPReduce"] = PlayerControl.GetDamagePVPReduce(curPlayer) # PVP固定减伤
-    curPlayerPropDict["FinalHurt"] = PlayerControl.GetFinalHurt(curPlayer) # 最终固定伤害增加
-    curPlayerPropDict["FinalHurtReduce"] = PlayerControl.GetFinalHurtReduce(curPlayer) # 最终固定伤害减少
-    curPlayerPropDict["FinalHurtPer"] = PlayerControl.GetFinalHurtPer(curPlayer) # 最终伤害百分比
-    curPlayerPropDict["FinalHurtReducePer"] = PlayerControl.GetFinalHurtReducePer(curPlayer) # 最终伤害减少百分比
-    curPlayerPropDict["OnlyFinalHurt"] = PlayerControl.GetOnlyFinalHurt(curPlayer) # 额外输出伤害
-    curPlayerPropDict["DamChanceDef"] = PlayerControl.GetDamChanceDef(curPlayer) # 20%的概率抵御伤害比率
-    curPlayerPropDict["NPCHurtAddPer"] = PlayerControl.GetNPCHurtAddPer(curPlayer) # 对怪物伤害加成
-    curPlayerPropDict["AtkBackHPPer"] = PlayerControl.GetAtkBackHPPer(curPlayer) # 攻击回复血量固定值
-    curPlayerPropDict["PVPAtkBackHP"] = PlayerControl.GetPVPAtkBackHP(curPlayer) # PVP攻击回血
-    curPlayerPropDict["FaintRate"] = PlayerControl.GetFaintRate(curPlayer) # 触发击晕
-    curPlayerPropDict["FaintDefRate"] = PlayerControl.GetFaintDefRate(curPlayer) # 击晕抵抗
-    
-    #-----------
-    #扩展属性缓存
-    curPlayerPlusDict = {}
-    
-    #各模块战力
-    fightPowerDict = {}
-    for mfpType in ShareDefine.ModuleFightPowerTypeList:
-        fightPower = PlayerControl.GetMFPFightPower(curPlayer, mfpType)
-        if fightPower:
-            fightPowerDict["%s" % mfpType] = fightPower
-    curPlayerPlusDict["FightPowerDict"] = fightPowerDict
-    
-    #装备汇总信息
-    curPlayerPlusDict["EquipOrangeCount"] = ChEquip.GetEquipOrangeCount(curPlayer)
-    curPlayerPlusDict["TotalEquipStar"] = ChEquip.GetTotalEquipStars(curPlayer)
-    curPlayerPlusDict["TotalPlusLV"] = ChEquip.GetTotalPlusLV(curPlayer)
-    curPlayerPlusDict["TotalPlusEvolveLV"] = ChEquip.GetTotalPlusEvolveLV(curPlayer)
-    curPlayerPlusDict["TotalStoneLV"] = Operate_EquipStone.GetTotalStoneLV(curPlayer)
-    curPlayerPlusDict["TotalEquipWashLV"] = Operate_EquipWash.GetTotalEquipWashLV(curPlayer)
-    #主动技能总等级
-    curPlayerPlusDict["TotalSkillLV"] = SkillShell.GetAllSkillLV(curPlayer, ChConfig.Def_SkillFuncType_FbSkill)
-    #灵宠数据
-    curPlayerPlusDict["Pet"] = __GetPetInfo(curPlayer)
-    
-    #坐骑数据
-    curPlayerPlusDict["Horse"] = __GetHorseInfo(curPlayer)
-    
-    #神器数据
-    curPlayerPlusDict["GodWeapon"] = __GetGodWeaponInfo(curPlayer)
-    
-    #符印数据
-    curPlayerPlusDict["Rune"] = __GetRuneInfo(curPlayer)
-    
-    #法宝数据
-    curPlayerPlusDict["MagicWeapon"] = __GetMagicWeaponInfo(curPlayer)
-    
-    #魂石、丹药使用个数
-    curPlayerPlusDict["Fruit"] = PlayerAttrFruit.GetAttrFruitEatCntDict(curPlayer)
-    
-    PropData = json.dumps(curPlayerPropDict, ensure_ascii=False).replace(" ", "")
-    PlusData = json.dumps(curPlayerPlusDict, ensure_ascii=False).replace(" ", "")
-    return PropData, PlusData
-
-def __GetEquipShowIDList(curPlayer):
-    ## 获取外观装备ID列表
-    equipShowIDList = []
-    indexList = range(10) + PlayerControl.GetFaceEquipIndexList(curPlayer) # 暂写死前10个物品 + 展示的境界装备部位
-    equipPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptEquip)
-    for index in indexList:
-        curEquip = equipPack.GetAt(index)
-        if not curEquip or curEquip.IsEmpty():
-            continue
-        equipShowIDList.append(curEquip.GetItemTypeID())
-    return equipShowIDList
-
-## 灵宠信息
-def __GetPetInfo(curPlayer):
-    petInfo = {}
-    petClassLVList = []
-    equipPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptPet)
-    for index in xrange(equipPack.GetCount()):
-        packItem = equipPack.GetAt(index)
-        if not packItem or packItem.IsEmpty():
-            continue
-        petNPCID = packItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
-        classLV = packItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
-        petClassLVList.append({"id":petNPCID, 'lv':classLV})
-        
-    petInfo["PetLV"] = petClassLVList
-    petInfo["AtkSpeed"] = PlayerControl.GetAtkSpeed(curPlayer)
-    return petInfo
-
-## 坐骑信息
-def __GetHorseInfo(curPlayer):
-    skinEndTimeInfo = {}
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for index in xrange(ipyDataMgr.GetHorseSkinPlusCount()):
-        skinPlusIpyData = ipyDataMgr.GetHorseSkinPlusByIndex(index)
-        skinID = skinPlusIpyData.GetID()
-        if not skinPlusIpyData.GetSkinValidTime():
-            continue
-        skinEndTimeInfo[skinID] = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HorserSkinEndTime % skinID)
-    horseInfo = {"LV":curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HorserLV),
-                 "EatItemCount":curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HorserEatItemCount),
-                 "SkinPlusStateList":PlayerHorse.GetHorseSkinPlusStateList(curPlayer),
-                 "SkinEndTimeInfo":skinEndTimeInfo,
-                 }
-    return horseInfo
-
-## 神器信息
-def __GetGodWeaponInfo(curPlayer):
-    godWeaponDict = {}
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    maxType = ipyDataMgr.GetGodWeaponByIndex(ipyDataMgr.GetGodWeaponCount() - 1).GetType()
-    for gwType in xrange(1, maxType + 1):
-        gwLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GodWeaponLV % gwType)
-        if gwLV:
-            godWeaponDict[gwType] = gwLV
-    return godWeaponDict
-
-## 符印信息
-def __GetRuneInfo(curPlayer):
-    #runeDict = {}
-    maxLV = 0
-    runeHoleCnt = IpyGameDataPY.GetFuncCfg("RuneUnlock", 4)
-    for holeNum in xrange(1, runeHoleCnt + 1):
-        runeData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % holeNum, 0)
-        if not runeData:
-            continue
-        #runeItemID = ItemControler.GetRuneItemID(runeData)
-        runeItemPlusLV = ItemControler.GetRuneItemPlusLV(runeData)
-        #runeDict[holeNum] = [runeItemID, runeItemPlusLV]
-        maxLV += runeItemPlusLV
-    return maxLV
-
-## 法宝信息
-def __GetMagicWeaponInfo(curPlayer):
-    mwDict = {}
-    ipyDataMgr = IpyGameDataPY.IPY_Data()
-    for i in xrange(ipyDataMgr.GetTreasureCount()):
-        treasureIpyData = ipyDataMgr.GetTreasureByIndex(i)
-        magicWeaponID = treasureIpyData.GetID()
-        treasureType = treasureIpyData.GetTreasureType()
-        if PlayerMagicWeapon.GetIsActiveMagicWeapon(curPlayer, magicWeaponID):
-            mwDict[treasureType] = mwDict.get(treasureType, 0) + 1
-            
-    return mwDict
-
-#//A2 12 查看玩家详细信息#tagCMViewPlayerInfo
-#struct tagCMViewPlayerInfo
-#{
-#    tagHead        Head;
-#    DWORD        PlayerID;
-#    BYTE        EquipClassLV;    //大于0为查看指定境界阶装备信息,  0为查看默认信息
-#};
-def OnCMViewPlayerInfo(index, clientPack, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    
-    findPlayerID = clientPack.PlayerID
-    equipClassLV = clientPack.EquipClassLV
-    findPlayer = GameWorld.GetPlayerManager().FindPlayerByID(findPlayerID)
-    if findPlayer:
-        if equipClassLV:
-            sendPack = ChPyNetSendPack.tagSCPlayerEquipCacheResult()
-            sendPack.PlayerID = findPlayerID
-            sendPack.EquipClassLV = equipClassLV
-            sendPack.ItemData = __GetPlayerEquipClassDataCache(findPlayer, equipClassLV)
-            sendPack.ItemDataSize = len(sendPack.ItemData)
-            NetPackCommon.SendFakePack(curPlayer, sendPack)
-            return
-        
-        #本地图玩家直接返回
-        PropData, PlusData = GetPlayerPropPlusCache(findPlayer)
-        sendPack = ChPyNetSendPack.tagSCQueryPlayerCacheResult()
-        sendPack.PlayerID = findPlayerID
-        sendPack.PropData = PropData
-        sendPack.PropDataSize = len(sendPack.PropData)
-        sendPack.ItemData = ""
-        sendPack.ItemDataSize = len(sendPack.ItemData)
-        sendPack.PlusData = PlusData
-        sendPack.PlusDataSize = len(sendPack.PlusData)
-        #GameWorld.DebugLog('ViewCache### OnCMViewPlayerInfo len: %s , sendPack: %s' % (sendPack.GetLength(), sendPack.OutputString()))
-        NetPackCommon.SendFakePack(curPlayer, sendPack)
-        return
-    #发送到GameServer去查询
-    sendPack = ChMapToGamePyPack.tagMGQueryPlayerCache()
-    sendPack.PlayerID = curPlayer.GetPlayerID()
-    sendPack.FindPlayerID = findPlayerID
-    sendPack.EquipClassLV = equipClassLV
-    
-    NetPackCommon.SendPyPackToGameServer(sendPack)  
-    return
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_PlayerMirror.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_PlayerMirror.py
index 591d97a..000d610 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_PlayerMirror.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_PlayerMirror.py
@@ -17,7 +17,6 @@
 
 import GameWorld
 import MirrorAttack
-import PlayerViewCacheTube
 import PyGameData
 #---------------------------------------------------------------------
 
@@ -62,36 +61,36 @@
         return
     msgType = funResult[0]
     msgData = funResult[1]
-    
-    if msgType == "PackDataSyncState":
-        PlayerViewCacheTube.UpdPackDataSyncState(curPlayer, msgData)
-        if msgData.get("PackDataCross"): # 如果跨服需要的,立即同步一次
-            PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick)
-    elif msgType == "PullPlayerPackData":
-        msgInfo = msgData
-        __DoPullPlayerPackData(curPlayer, msgInfo, tick)
-        
-    elif msgType == "PullPlayerViewCache":
-        msgInfo = msgData
-        __DoPullPlayerViewCache(curPlayer, msgInfo, tick)
-        
+#    
+#    if msgType == "PackDataSyncState":
+#        PlayerViewCacheTube.UpdPackDataSyncState(curPlayer, msgData)
+#        if msgData.get("PackDataCross"): # 如果跨服需要的,立即同步一次
+#            PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick)
+#    elif msgType == "PullPlayerPackData":
+#        msgInfo = msgData
+#        __DoPullPlayerPackData(curPlayer, msgInfo, tick)
+#        
+#    elif msgType == "PullPlayerViewCache":
+#        msgInfo = msgData
+#        __DoPullPlayerViewCache(curPlayer, msgInfo, tick)
+#        
     return
 
 def __DoPullPlayerPackData(curPlayer, msgInfo, tick):
     pullFrom = msgInfo.get("pullFrom")
     # 0 或 非本服代表跨服需要
-    if pullFrom == 0 or (pullFrom > 0 and pullFrom != GameWorld.GetServerGroupID()):
-        PlayerViewCacheTube.SetPackDataCrossSyncState(curPlayer)
-    else:
-        PlayerViewCacheTube.SetPackDataSyncState(curPlayer)
-    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, forcePackData=True, packMsg=msgInfo)
+#    if pullFrom == 0 or (pullFrom > 0 and pullFrom != GameWorld.GetServerGroupID()):
+#        PlayerViewCacheTube.SetPackDataCrossSyncState(curPlayer)
+#    else:
+#        PlayerViewCacheTube.SetPackDataSyncState(curPlayer)
+#    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, forcePackData=True, packMsg=msgInfo)
     return
 
 def __DoPullPlayerViewCache(curPlayer, msgInfo, tick):
     viewFrom = msgInfo.get("viewFrom")
     # 0 或 非本服代表跨服需要
-    if viewFrom == 0 or (viewFrom > 0 and viewFrom != GameWorld.GetServerGroupID()):
-        PlayerViewCacheTube.SetViewCacheCrossSyncState(curPlayer)
-    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, packMsg=msgInfo, isOnlyViewCache=True)
+#    if viewFrom == 0 or (viewFrom > 0 and viewFrom != GameWorld.GetServerGroupID()):
+#        PlayerViewCacheTube.SetViewCacheCrossSyncState(curPlayer)
+#    PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, packMsg=msgInfo, isOnlyViewCache=True)
     return
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index 8eed522..84f5472 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -26,6 +26,8 @@
 
 g_pyGameDataManager = None
 
+g_dbPlayerIDMap = {} # 本服DBPlayer玩家表ID映射关系 {playerID:accID, ...}
+
 g_mapIDTxtInfo = {} # MapID.txt 加载的信息
 g_realmDiffPlayerDict = {} # 境界难度玩家信息 {realm:[playerID, ...], ...}
 g_realmDiffNPCRefresh = {} # {(lineID, realm):{refreshID:tagNPCRefresh, ...}}
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/CollectionDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/CollectionDefine.py
index 886a20c..30ab5fd 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/CollectionDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/CollectionDefine.py
@@ -5,6 +5,7 @@
 #-------------------------------------------------------------------------------
 #
 #卡牌服务器表
+UCN_DBGameRec="tagDBGameRec"
 UCN_DBFamilyAction="tagDBFamilyAction"
 UCN_DBFamilyMem="tagDBFamilyMem"
 UCN_DBFamily="tagDBFamily"
@@ -18,7 +19,6 @@
 
 #MMO旧表
 UCN_DBPlayerPackData="tagDBPlayerPackData"
-UCN_DBGameRec="tagDBGameRec"
 UCN_DBPyFuncTeam="tagDBPyFuncTeam"
 UCN_DBPyFuncTeamMem="tagDBPyFuncTeamMem"
 UCN_DBPlayerRecData="tagDBPlayerRecData"
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/DataServerPlayerData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/DataServerPlayerData.py
index 75fc0a3..0252ce3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/DataServerPlayerData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/Collections/DataServerPlayerData.py
@@ -28697,3 +28697,221 @@
             self.Name = Str[:33]
             
 
+
+# 通用记录表新 #tagDBGameRec
+class tagDBGameRec(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('RecType', ctypes.c_ushort),
+        ('RecID', ctypes.c_ulong),
+        ('Time', ctypes.c_double),
+        ('Value1', ctypes.c_ulong),
+        ('Value2', ctypes.c_ulong),
+        ('Value3', ctypes.c_ulong),
+        ('Value4', ctypes.c_ulong),
+        ('Value5', ctypes.c_ulong),
+        ('Value6', ctypes.c_ulong),
+        ('Value7', ctypes.c_ulong),
+        ('Value8', ctypes.c_ulong),
+        ('UserDataLen', ctypes.c_ushort),
+        ('UserData', ctypes.c_char_p),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+    def clear(self):
+        self.RecType = 0
+        self.RecID = 0
+        self.Time = 0.0
+        self.Value1 = 0
+        self.Value2 = 0
+        self.Value3 = 0
+        self.Value4 = 0
+        self.Value5 = 0
+        self.Value6 = 0
+        self.Value7 = 0
+        self.Value8 = 0
+        self.UserDataLen = 0
+        self.UserData = ''
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            msg = error.formatMsg('error', error.ERROR_NO_148, '(pos = %s) > (length = %s)'%(pos, length))
+            mylog.error(msg)
+            return -1
+        if len(buf) < pos + self.getLength():
+            msg = error.formatMsg('error', error.ERROR_NO_149, 'len = %s while %s expected!'%(len(buf) - pos, self.getLength()))
+            mylog.error(msg)
+        self.clear()
+        self.RecType, pos = CommFunc.ReadWORD(buf, pos)
+        self.RecID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Time, pos = CommFunc.ReadDouble(buf, pos)
+        self.Value1, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value2, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value3, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value4, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value5, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value6, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value7, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value8, pos = CommFunc.ReadDWORD(buf, pos)
+        self.UserDataLen, pos = CommFunc.ReadWORD(buf, pos)
+        tmp, pos = CommFunc.ReadString(buf, pos, self.UserDataLen)
+        self.UserData = ctypes.c_char_p(tmp)
+        return self.getLength()
+
+    def getBuffer(self):
+        buf = ''
+        buf = CommFunc.WriteWORD(buf, self.RecType)
+        buf = CommFunc.WriteDWORD(buf, self.RecID)
+        buf = CommFunc.WriteDouble(buf, self.Time)
+        buf = CommFunc.WriteDWORD(buf, self.Value1)
+        buf = CommFunc.WriteDWORD(buf, self.Value2)
+        buf = CommFunc.WriteDWORD(buf, self.Value3)
+        buf = CommFunc.WriteDWORD(buf, self.Value4)
+        buf = CommFunc.WriteDWORD(buf, self.Value5)
+        buf = CommFunc.WriteDWORD(buf, self.Value6)
+        buf = CommFunc.WriteDWORD(buf, self.Value7)
+        buf = CommFunc.WriteDWORD(buf, self.Value8)
+        buf = CommFunc.WriteWORD(buf, self.UserDataLen)
+        buf = CommFunc.WriteString(buf, self.UserDataLen, self.UserData)
+        return buf
+
+    def getLength(self):
+        length = 0
+        length += sizeof(ctypes.c_ushort)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_double)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ushort)
+        length += self.UserDataLen
+        return length
+
+    def getRecord(self):
+        '''组织存储记录'''
+        rec = {}
+        rec[u'RecType'] = self.RecType
+        rec[u'RecID'] = self.RecID
+        rec[u'Time'] = self.Time
+        rec[u'Value1'] = self.Value1
+        rec[u'Value2'] = self.Value2
+        rec[u'Value3'] = self.Value3
+        rec[u'Value4'] = self.Value4
+        rec[u'Value5'] = self.Value5
+        rec[u'Value6'] = self.Value6
+        rec[u'Value7'] = self.Value7
+        rec[u'Value8'] = self.Value8
+        rec[u'UserDataLen'] = self.UserDataLen
+        rec[u'UserData'] = fix_incomingText(self.UserData)
+        return rec
+
+    def readRecord(self, rec):
+        '''由于MongoDB读出来是unicode,所有字符串需要进行转换'''
+        self.RecType = rec.get(u'RecType', 0)
+        self.RecID = rec.get(u'RecID', 0)
+        self.Time = rec.get(u'Time', 0)
+        self.Value1 = rec.get(u'Value1', 0)
+        self.Value2 = rec.get(u'Value2', 0)
+        self.Value3 = rec.get(u'Value3', 0)
+        self.Value4 = rec.get(u'Value4', 0)
+        self.Value5 = rec.get(u'Value5', 0)
+        self.Value6 = rec.get(u'Value6', 0)
+        self.Value7 = rec.get(u'Value7', 0)
+        self.Value8 = rec.get(u'Value8', 0)
+        self.UserDataLen = rec.get(u'UserDataLen', 0)
+        self.UserData = fix_outgoingText(rec.get(u'UserData', u''))
+
+#Can not implement adoLoadStr method:No key defined!
+#Can not implement adoInsertStr method:No key defined!
+#Can not implement adoUpdateStr method:No key defined!
+#Can not implement adoUpdateStr method:No key defined!
+#Can not implement adoCheckUpdateStr method:No key defined!
+#Can not implement adoCheckUpdateExStr method:No key defined!
+
+    def getAdoRecords(self, resultCollection):
+        '''查询结果打包成二进制流'''
+        result = ''
+        result = CommFunc.WriteDWORD(result, resultCollection.count())
+        for rec in resultCollection:
+            self.readRecord(rec)
+            result += self.getBuffer()
+        return result
+
+#Can not implement adoQueryIndexStr method:No key defined!
+
+    def adoQueryCustom(self, collection, queryDict):
+        '''自定义查询'''
+        resultCollection = collection.find(queryDict)
+
+        return self.getAdoRecords(resultCollection)
+
+
+    def adoQueryAll(self, collection):
+        '''查询所有''' 
+        resultCollection = collection.find()
+         
+        return self.getAdoRecords(resultCollection)
+
+#Can not implement adoDeleteByIndexStr method:No key defined!
+    def outputString(self):
+        output = '''// 通用记录表新 #tagDBGameRec:
+            RecType = %s,
+            RecID = %s,
+            Time = %s,
+            Value1 = %s,
+            Value2 = %s,
+            Value3 = %s,
+            Value4 = %s,
+            Value5 = %s,
+            Value6 = %s,
+            Value7 = %s,
+            Value8 = %s,
+            UserDataLen = %s,
+            UserData = %s,
+            ADOResult = %s,
+            '''%(
+                self.RecType,
+                self.RecID,
+                self.Time,
+                self.Value1,
+                self.Value2,
+                self.Value3,
+                self.Value4,
+                self.Value5,
+                self.Value6,
+                self.Value7,
+                self.Value8,
+                self.UserDataLen,
+                self.UserData,
+                self.ADOResult,
+            )
+        return output
+
+    def dumpString(self):
+        output = '''%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s\t%1s'''%(
+                self.RecType,
+                self.RecID,
+                self.Time,
+                self.Value1,
+                self.Value2,
+                self.Value3,
+                self.Value4,
+                self.Value5,
+                self.Value6,
+                self.Value7,
+                self.Value8,
+                self.UserDataLen,
+                self.UserData,
+            )
+        return output
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/LogicProcess/UserCtrlDB.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/LogicProcess/UserCtrlDB.py
index 95d7abf..a500a86 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/LogicProcess/UserCtrlDB.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/LogicProcess/UserCtrlDB.py
@@ -400,10 +400,27 @@
             PyGameData.g_UserCtrlDBFirstInit = True
             self.__PlayerBackupSave()
             CheckGameVersion()
-
-            #后续也要增加公共数据保存如家族等,考虑保存失败可以直接关闭地图
-
+            self.loadDBPlayerIDMap()
+            
         return
+    
+    def loadDBPlayerIDMap(self):
+        ## 加载本服玩家映射关系
+        col = self.db[UCN_DBPlayer]
+        resultSet = col.find({}, {"PlayerID":1, "AccID":1, "_id":0})
+        if resultSet and resultSet.count():
+            for resultDict in resultSet:
+                PyGameData.g_dbPlayerIDMap[resultDict["PlayerID"]] = resultDict["AccID"]
+        GameWorld.Log("启动服务器加载DBPlayer玩家账号ID对应关系! %s, %s" % (len(PyGameData.g_dbPlayerIDMap), PyGameData.g_dbPlayerIDMap))
+        return
+    
+    def findDBPlayer(self, playerID):
+        col = self.db[UCN_DBPlayer]
+        dbPlayer = DataServerPlayerData.tagDBPlayer()
+        dbPlayer.IsDeleted = 0
+        if not dbPlayer.adoLoadCEx(col, {"PlayerID":playerID}):
+            return
+        return dbPlayer
     
     def requestLogicProcess(self, pack):
         db = self.db
@@ -1662,7 +1679,7 @@
 
             mylog.debug('RevoverBillProcess success...%s'%orderID)
         except:
-            mylog.error("RevoverBillProcess error %s"%orderID)
+            mylog.error("RevoverBillProcess error %s"%traceback.format_exc())
     
     def SavePlayerMapServerData(self, db, saveData):
         playerRec = DataServerPlayerData.tagDBPlayer()
@@ -2413,6 +2430,9 @@
             return 0, disDataBaseError, createPlayer.AccID, '' 
 
         mylog.debug('insert role ok!accid = %s, PlayerName = %s'%(createPlayer.AccID, createPlayer.PlayerName))
+        PyGameData.g_dbPlayerIDMap[newPlayerID] = createPlayer.AccID
+        mylog.debug('PyGameData.g_dbPlayerIDMap = %s, %s'%(len(PyGameData.g_dbPlayerIDMap), PyGameData.g_dbPlayerIDMap))
+        
         #构造其他角色初始数据
         itemData = ''
         itemData = CommFunc.WriteDWORD(itemData, 0)
@@ -3409,6 +3429,11 @@
         data += DBFamilyAction.adoQueryAll(collection)
         mylog.info("tagDBFamilyAction ok")
         
+        collection = db[UCN_DBGameRec]
+        DBGameRec = DataServerPlayerData.tagDBGameRec()
+        data += DBGameRec.adoQueryAll(collection)
+        mylog.info("tagDBGameRec ok")
+        
         mylog.info('readGameWorldData len:%s' % len(data))
         return data
     
@@ -3430,6 +3455,7 @@
             gameDataReadPos = self.savegameServerWorldData(saveData, gameDataReadPos, UCN_DBFamily, DataServerPlayerData.tagDBFamily, db)
             gameDataReadPos = self.savegameServerWorldData(saveData, gameDataReadPos, UCN_DBFamilyMem, DataServerPlayerData.tagDBFamilyMem, db)
             gameDataReadPos = self.savegameServerWorldData(saveData, gameDataReadPos, UCN_DBFamilyAction, DataServerPlayerData.tagDBFamilyAction, db)
+            gameDataReadPos = self.savegameServerWorldData(saveData, gameDataReadPos, UCN_DBGameRec, DataServerPlayerData.tagDBGameRec, db)
             
             mylog.info('saveGameWorldData ok!')
             
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index fe1fb61..a2e5419 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -946,6 +946,9 @@
 
 BillboardTypeAllList = BillboardTypeList + CrossBillboardTypeList
 
+#仙盟榜单类型
+FamilyBillboardList = [Def_BT_BossTrialSubmitFamily, Def_BT_BossTrialSubmitFamilyBak, Def_CBT_FamilyGCZScore, Def_CBT_FamilyGCZRoundHurt]
+
 #职业对应战力排行榜类型
 JobFightPowerBillboardDict = {
                               PlayerJob_Warrior:Def_BT_FightPower_Warrior,
@@ -958,9 +961,6 @@
                              Def_BT_LV, Def_BT_FightPower_Horse, Def_BT_FightPower_Pet, Def_BT_TrialTower, Def_BT_OffLineEfficient,
                              Def_BT_SkyTower, Def_BT_CharmTotal, Def_BT_CharmWeek, Def_BT_CharmDay
                              ]
-
-#仙盟榜单类型
-FamilyBillboardList = [Def_BT_BossTrialSubmitFamily, Def_BT_BossTrialSubmitFamilyBak]
 
 ##---比率---
 #百分率
@@ -1381,35 +1381,6 @@
     5006:6,
     }
 
-#聊天信息附加值
-(
-Def_TalkExtraValue_Bit_VipLv,  # vip等级
-Def_TalkExtraValue_Bit_GM,            #GM
-Def_TalkExtraValue_Bit_JOB, #job
-Def_TalkExtraValue_Bit_BubbleBox, #气泡框
-Def_TalkExtraValue_Bit_ServerGroupID, #服务器组ID
-Def_TalkExtraValue_Bit_LV, #等级
-) = range(0, 6)
-
-#聊天信息附加值中某信息数据所占位置
-#{聊天信息附加值类型:[起始位置(从左往右), 结束位置(不包含)]}
-Def_TalkExtraValue_LenDict = {
-     Def_TalkExtraValue_Bit_VipLv:[0, 2],  # vip等级
-     Def_TalkExtraValue_Bit_GM:[2, 3],  # GM
-     Def_TalkExtraValue_Bit_JOB:[3, 4],  # job
-     Def_TalkExtraValue_Bit_BubbleBox:[4, 6],  # 气泡框
-     Def_TalkExtraValue_Bit_ServerGroupID:[6, 13],  # 服务器组ID
-     Def_TalkExtraValue_Bit_LV:[13, 17],  # 等级
-     }
-
-# 聊天频道 暂用语音
-(Def_ChannelChat_World,     # 世界
-Def_ChannelChat_Family,     # 仙盟
-Def_ChannelChat_Private,    # 私聊含好友
-Def_ChannelChat_Team,       # 队伍
-Def_ChannelChat_Area,    # 区域(当前地图或副本线)
-) = range(1, 6)
-
 #背包类型
 (
 rptTempSwap,        # 临时交换背包 28
@@ -1469,7 +1440,8 @@
                        Def_GameRecType_FamilyGCZJoinFamily, # 仙盟攻城战参与仙盟信息, zoneID 303
                        Def_GameRecType_FamilyGCZJoinMember, # 仙盟攻城战参与成员信息, zoneID 304
                        Def_GameRecType_FamilyGCZCityWall, # 仙盟攻城战城池信息, zoneID 305
-                       ) = range(300, 1 + 305)
+                       Def_GameRecType_TalkCache, # 聊天缓存,频道 306
+                       ) = range(300, 1 + 306)
 #通用信息记录新 - 字典key配置,如果有配置,则可额外按对应记录Value值存储字典,方便快速取值,可配置Value编号 1~8,配空默认 Value1
 Def_GameRecValueKeyDict = {
                            Def_GameRecType_Xiangong:[1],
@@ -1580,7 +1552,20 @@
                       Def_ActionType_FamilyCTGAssist,    #仙盟充值协助活动 14
                       Def_ActionType_FamilyEmblem,    #仙盟时效徽章信息 15
                       Def_ActionType_Zhenbaoge,    #珍宝阁 16
-                      ) = range(0, 17)
+                      Def_ActionType_TalkCache,    #聊天缓存 17,最大条数配置决定
+                      ) = range(0, 18)
+                      
+#家族某行为类型保存的条数
+ActionTypeSaveCnt = {
+                     Def_ActionType_FamilyPray:10 ,    #家族祈福
+                     Def_ActionType_FamilyArrest:7,     #家族悬赏
+                     Def_ActionType_FamilyMember:1,       #记录家族成员信息
+                     Def_ActionType_LeaderImpeachTime:1,  # 族长下线了多久
+                     Def_ActionType_FamilyBossFB:1,  # 记录家族boss副本信息
+                     Def_ActionType_FamilyStore:30,       #仓库操作记录
+                     Def_ActionType_OfficerModelEquip:10,  # 记录家族有职位的成员模型装备信息(盟主+副盟主*2+战斗队长*5)
+                     Def_ActionType_FamilyEvent:50,  # 记录家族事件
+                     }
 
 # 家族行为事件类型定义; Def_ActionType_FamilyEvent; 存与事件记录Value1
 # 通用:time-时间;name-玩家;value1-事件类型

--
Gitblit v1.8.0