From bc5f3f1c88d225109fa39a85b209ef13f5fb52a9 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 06 二月 2026 21:28:13 +0800
Subject: [PATCH] 66 【公会】基础主体-服务端(跨服公会所有基本功能支持、跨服砍价支持;修改查看目标公会、查看目标玩家方式;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMgr.py         |   73 +++-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CreateFamily.py        |   78 ++--
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py             |  151 ++++++--
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                     |    9 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                     |   64 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                 |  180 +++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py                        |    9 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py          |   40 +-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Family.py              |   48 +-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py          |   57 ++-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py                   |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamilyEmblem.py       |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMsg.py         |   17 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                             |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py   |   18 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                 |   37 +-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py                       |   45 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBPlayerViewCache.py |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayer.py              |   72 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py            |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py       |    4 
 21 files changed, 709 insertions(+), 212 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index 796029f..d28862d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -166,9 +166,9 @@
 PacketSubCMD_6=0x12
 PacketCallFunc_6=OnFamilyMoneyDonate
 
-PacketCMD_7=
-PacketSubCMD_7=
-PacketCallFunc_7=
+PacketCMD_7=A6
+PacketSubCMD_7=19
+PacketCallFunc_7=OnViewTagFamily
 
 PacketCMD_8=0xA6
 PacketSubCMD_8=0x20
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 143ce97..040afff 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -2165,7 +2165,7 @@
                   ("Cmd", c_ubyte),
                   ("SubCmd", c_ubyte),
                   ("PlayerID", c_int),    
-                  ("EquipClassLV", c_ubyte),    #大于0为查看指定境界阶装备信息,  0为查看默认信息
+                  ("ServerID", c_int),    #玩家服务器ID,发0默认本服玩家
                   ]
 
     def __init__(self):
@@ -2183,7 +2183,7 @@
         self.Cmd = 0xA2
         self.SubCmd = 0x12
         self.PlayerID = 0
-        self.EquipClassLV = 0
+        self.ServerID = 0
         return
 
     def GetLength(self):
@@ -2197,13 +2197,13 @@
                                 Cmd:%s,
                                 SubCmd:%s,
                                 PlayerID:%d,
-                                EquipClassLV:%d
+                                ServerID:%d
                                 '''\
                                 %(
                                 self.Cmd,
                                 self.SubCmd,
                                 self.PlayerID,
-                                self.EquipClassLV
+                                self.ServerID
                                 )
         return DumpString
 
@@ -7565,6 +7565,62 @@
 
 
 #------------------------------------------------------
+# A6 19 查看目标公会 #tagCSViewTagFamily
+
+class  tagCSViewTagFamily(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("FamilyID", c_int),    
+                  ("ServerID", c_int),    #公会服务器ID,发0默认本服公会
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xA6
+        self.SubCmd = 0x19
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xA6
+        self.SubCmd = 0x19
+        self.FamilyID = 0
+        self.ServerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCSViewTagFamily)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// A6 19 查看目标公会 //tagCSViewTagFamily:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                FamilyID:%d,
+                                ServerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.FamilyID,
+                                self.ServerID
+                                )
+        return DumpString
+
+
+m_NAtagCSViewTagFamily=tagCSViewTagFamily()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSViewTagFamily.Cmd,m_NAtagCSViewTagFamily.SubCmd))] = m_NAtagCSViewTagFamily
+
+
+#------------------------------------------------------
 # A6 16 珍宝阁操作 #tagCMZhenbaogeOP
 
 class  tagCMZhenbaogeOP(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 1068d12..b99a038 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -11133,6 +11133,7 @@
     FamilyCount = 0    #(BYTE FamilyCount)
     FamilyList = list()    #(vector<tagMCFamilyView> FamilyList)//本页家族信息列表
     Rank = 0    #(DWORD Rank)//玩家公会所在名次,0-没有公会或没有在榜上;>0-对应排名
+    DataServerID = 0    #(DWORD DataServerID)//数据所在服务器ID
     data = None
 
     def __init__(self):
@@ -11155,6 +11156,7 @@
             _pos = temFamilyList.ReadData(_lpData, _pos)
             self.FamilyList.append(temFamilyList)
         self.Rank,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.DataServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         return _pos
 
     def Clear(self):
@@ -11170,6 +11172,7 @@
         self.FamilyCount = 0
         self.FamilyList = list()
         self.Rank = 0
+        self.DataServerID = 0
         return
 
     def GetLength(self):
@@ -11183,6 +11186,7 @@
         length += 1
         for i in range(self.FamilyCount):
             length += self.FamilyList[i].GetLength()
+        length += 4
         length += 4
 
         return length
@@ -11199,6 +11203,7 @@
         for i in range(self.FamilyCount):
             data = CommFunc.WriteString(data, self.FamilyList[i].GetLength(), self.FamilyList[i].GetBuffer())
         data = CommFunc.WriteDWORD(data, self.Rank)
+        data = CommFunc.WriteDWORD(data, self.DataServerID)
         return data
 
     def OutputString(self):
@@ -11211,7 +11216,8 @@
                                 TotalPage:%d,
                                 FamilyCount:%d,
                                 FamilyList:%s,
-                                Rank:%d
+                                Rank:%d,
+                                DataServerID:%d
                                 '''\
                                 %(
                                 self.Head.OutputString(),
@@ -11222,7 +11228,8 @@
                                 self.TotalPage,
                                 self.FamilyCount,
                                 "...",
-                                self.Rank
+                                self.Rank,
+                                self.DataServerID
                                 )
         return DumpString
 
@@ -11693,6 +11700,175 @@
 
 
 #------------------------------------------------------
+# A5 19 查看目标公会信息 #tagSCTagFamilyInfo
+
+class  tagSCTagFamilyInfo(Structure):
+    Head = tagHead()
+    FamilyID = 0    #(DWORD FamilyID)//家族ID
+    FamilyNameLen = 0    #(BYTE FamilyNameLen)
+    FamilyName = ""    #(String FamilyName)//size = FamilyNameLen
+    LeaderID = 0    #(DWORD LeaderID)//族长ID
+    LeaderNameLen = 0    #(BYTE LeaderNameLen)
+    LeaderName = ""    #(String LeaderName)//size = LeaderNameLen
+    LeaderServerID = 0    #(DWORD LeaderServerID)//会长区服ID
+    FamilyLV = 0    #(BYTE FamilyLV)//家族等级
+    ServerID = 0    #(DWORD ServerID)//区服ID
+    EmblemID = 0    #(DWORD EmblemID)//徽章ID
+    EmblemWord = ""    #(char EmblemWord[3])//徽章文字
+    FightPower = 0    #(DWORD FightPower)//总战力,求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)//总战力,整除亿部分
+    BroadcastLen = 0    #(WORD BroadcastLen)//公告
+    Broadcast = ""    #(String Broadcast)//size = BroadcastLen
+    MemberCount = 0    #(BYTE MemberCount)//成员人数
+    DataServerID = 0    #(DWORD DataServerID)//数据所在服务器ID
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xA5
+        self.Head.SubCmd = 0x19
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FamilyNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.FamilyName,_pos = CommFunc.ReadString(_lpData, _pos,self.FamilyNameLen)
+        self.LeaderID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LeaderNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LeaderName,_pos = CommFunc.ReadString(_lpData, _pos,self.LeaderNameLen)
+        self.LeaderServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FamilyLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.EmblemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.EmblemWord,_pos = CommFunc.ReadString(_lpData, _pos,3)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.BroadcastLen,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Broadcast,_pos = CommFunc.ReadString(_lpData, _pos,self.BroadcastLen)
+        self.MemberCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.DataServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xA5
+        self.Head.SubCmd = 0x19
+        self.FamilyID = 0
+        self.FamilyNameLen = 0
+        self.FamilyName = ""
+        self.LeaderID = 0
+        self.LeaderNameLen = 0
+        self.LeaderName = ""
+        self.LeaderServerID = 0
+        self.FamilyLV = 0
+        self.ServerID = 0
+        self.EmblemID = 0
+        self.EmblemWord = ""
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        self.BroadcastLen = 0
+        self.Broadcast = ""
+        self.MemberCount = 0
+        self.DataServerID = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 4
+        length += 1
+        length += len(self.FamilyName)
+        length += 4
+        length += 1
+        length += len(self.LeaderName)
+        length += 4
+        length += 1
+        length += 4
+        length += 4
+        length += 3
+        length += 4
+        length += 4
+        length += 2
+        length += len(self.Broadcast)
+        length += 1
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteDWORD(data, self.FamilyID)
+        data = CommFunc.WriteBYTE(data, self.FamilyNameLen)
+        data = CommFunc.WriteString(data, self.FamilyNameLen, self.FamilyName)
+        data = CommFunc.WriteDWORD(data, self.LeaderID)
+        data = CommFunc.WriteBYTE(data, self.LeaderNameLen)
+        data = CommFunc.WriteString(data, self.LeaderNameLen, self.LeaderName)
+        data = CommFunc.WriteDWORD(data, self.LeaderServerID)
+        data = CommFunc.WriteBYTE(data, self.FamilyLV)
+        data = CommFunc.WriteDWORD(data, self.ServerID)
+        data = CommFunc.WriteDWORD(data, self.EmblemID)
+        data = CommFunc.WriteString(data, 3, self.EmblemWord)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        data = CommFunc.WriteWORD(data, self.BroadcastLen)
+        data = CommFunc.WriteString(data, self.BroadcastLen, self.Broadcast)
+        data = CommFunc.WriteBYTE(data, self.MemberCount)
+        data = CommFunc.WriteDWORD(data, self.DataServerID)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                FamilyID:%d,
+                                FamilyNameLen:%d,
+                                FamilyName:%s,
+                                LeaderID:%d,
+                                LeaderNameLen:%d,
+                                LeaderName:%s,
+                                LeaderServerID:%d,
+                                FamilyLV:%d,
+                                ServerID:%d,
+                                EmblemID:%d,
+                                EmblemWord:%s,
+                                FightPower:%d,
+                                FightPowerEx:%d,
+                                BroadcastLen:%d,
+                                Broadcast:%s,
+                                MemberCount:%d,
+                                DataServerID:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.FamilyID,
+                                self.FamilyNameLen,
+                                self.FamilyName,
+                                self.LeaderID,
+                                self.LeaderNameLen,
+                                self.LeaderName,
+                                self.LeaderServerID,
+                                self.FamilyLV,
+                                self.ServerID,
+                                self.EmblemID,
+                                self.EmblemWord,
+                                self.FightPower,
+                                self.FightPowerEx,
+                                self.BroadcastLen,
+                                self.Broadcast,
+                                self.MemberCount,
+                                self.DataServerID
+                                )
+        return DumpString
+
+
+m_NAtagSCTagFamilyInfo=tagSCTagFamilyInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCTagFamilyInfo.Head.Cmd,m_NAtagSCTagFamilyInfo.Head.SubCmd))] = m_NAtagSCTagFamilyInfo
+
+
+#------------------------------------------------------
 # A6 05 VIP礼包购买记录 #tagMCVIPAwardMsg
 
 class  tagMCVIPAwardMsg(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py
index 78aa02d..26f5408 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py
@@ -69,7 +69,14 @@
     if space:
         hex_str = ' '.join(hex_str[i:i+2] for i in range(0, len(hex_str), 2))
     return hex_str
-            
+
+def GetPackHead(clientPack):
+    if hasattr(clientPack, "Head"):
+        headStr = "%02x%02x" % (clientPack.Head.Cmd, clientPack.Head.SubCmd)
+    else:
+        headStr = "%02x%02x" % (clientPack.Cmd, clientPack.SubCmd)
+    return headStr.upper()
+
 #获取异常信息#(try:...except:..GetExceptionInfo())
 ## 
 #  @param 参数
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 81d7080..de1ac31 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
@@ -263,6 +263,8 @@
         self.SetFacePic(viewCache.GetFacePic())
         self.SetTitleID(viewCache.GetTitleID())
         self.SetServerID(viewCache.GetServerID())
+        if not self.GetOffTime(): # 有离线时间数据了,以成员自己的为准
+            self.SetOffTime(viewCache.GetOffTime())
         fpChange = False
         fightPowerTotal = viewCache.GetFightPowerTotal()
         if self.GetFightPowerTotal() != fightPowerTotal:
@@ -343,6 +345,9 @@
             return
         self.__memberDict[playerID] = member
         self.__memberList.append(member)
+        viewCache = PlayerViewCache.FindViewCache(playerID)
+        member.SetOffTime(viewCache.GetOffTime() if viewCache else int(time.time()))
+        self.__familyMgr.OnAddMember(self, playerID)
         return member
     
     def GetMemberIDList(self): return self.__memberDict.keys()
@@ -360,7 +365,6 @@
             if not member and False:
                 member = FamilyMem()
         self.RefrshFightPowerTotal()
-        self.__familyMgr.OnAddMember(self, playerID)
         return member
     
     def DeleteMember(self, playerID):
@@ -520,6 +524,8 @@
                 if fixName not in self.__familyNameDict:
                     familyName = fixName
                     break
+            family.SetName(familyName)
+            family.SetExtra1(0) # 重置改名CD
         self.__familyNameDict[familyName] = family
         
         if family not in self.__familyList:
@@ -834,10 +840,18 @@
         self.__crossZoneCfgDict = updCrossZoneCfgDict
         self.__zoneFamilyMgrDict = {}
         self.__familyIDZoneIDDict = {}
+        
+        # 重新初始化本服管理的分区
         zoneDict = self.__crossZoneCfgDict[crossServerID]
+        GameWorld.Log("本跨服重置公会互通分区! crossServerID=%s,zoneDict=%s" % (crossServerID, zoneDict))
+        for zoneID in zoneDict.keys():
+            self.GetZoneFamilyMgr(zoneID)
+        GameWorld.Log("GetZoneIDListThisServer=%s" % self.GetZoneIDListThisServer())
+        
+        # 重新将本服公会数据分配到所属分区
         for family in self.__familyIDDict.values():
             familyID = family.GetID()
-            zoneID = familyZoneDict.get(familyID, 0) # 理论上不可能再为0
+            zoneID = familyZoneDict.get(familyID, 0) # 理论上不可能再为0,因为有0时 noZoneServerIDList 验证不会通过
             zoneMgr = self.GetZoneFamilyMgr(zoneID)
             zoneMgr.AddFamilyToZone(family)
             
@@ -877,7 +891,7 @@
                     break
         return zoneID
     
-    def GetZoneIDListThisServer(self): return self.__zoneFamilyMgrDict.keys() # 在本服数据中已存在的分区
+    def GetZoneIDListThisServer(self): return self.__zoneFamilyMgrDict.keys() # 本服管理的分区
     
     def GetFamilyZoneID(self, familyID): return self.__familyIDZoneIDDict.get(familyID, -1) # -1-未找到所属分区;>=0-所属分区
     
@@ -1035,7 +1049,7 @@
             self.__setFamilyToDefaultZone() # 游戏服本服的数据无论有没有跨服了都同意设置到默认分区
         return pos
     
-def LoadZoneCfg(self):
+def LoadZoneCfg():
     crossZoneCfgDict = {}
     appID = GameWorld.GetAppID()
     ipyDataMgr = IpyGameDataPY.IPY_Data()
@@ -1049,6 +1063,7 @@
             crossZoneCfgDict[crossServerID] = {}
         zoneDict = crossZoneCfgDict[crossServerID]
         zoneDict[zoneID] = [] + ipyData.GetServerIDList()
+    GameWorld.Log("跨服公会分区配置加载: appID=%s,%s" % (appID, crossZoneCfgDict))
     return crossZoneCfgDict
 
 def CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
@@ -1058,7 +1073,7 @@
         GameWorld.Log("跨服公会互通分区配置不变不处理")
         return
     
-    # 验证配置,是否有交叉、拆分,并邮件通知运维,待扩展,先开发功能
+    # 验证配置,是否有交叉、拆分,并邮件通知运维,待扩展,功能完整性优先
     #GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", "noZoneServerIDList=%s" % noZoneServerIDList)
     
     return True
@@ -1073,11 +1088,13 @@
         if not crossZoneCfgDict or not DBDataMgr.GetFamilyMgr().UpdCrossZoneCfgDict(crossZoneCfgDict):
             return
         Sync_CenterToCross_FamilyCrossCfg()
-        
+        Sync_CrossToServer_FamilyInfo()
     return
 
 def Sync_CenterToCross_FamilyInfo(serverType, serverID):
     ## 跨服中心同步给跨服服务器
+    
+    # 【注】只同步给跨服服务器,各跨服验证通过后,游戏服才会通过所属跨服取得最终的分区信息
     if serverType == ShareDefine.serverType_Cross:
         Sync_CenterToCross_FamilyCrossCfg(serverID)
     return
@@ -1115,6 +1132,7 @@
     ## 跨服服务器同步互通公会信息给游戏服
     # @param toServerID: 有指定游戏服连上时只发给该服,没有的话一般是分区配置变更时由跨服主动同步所有相关游戏服
     
+    GameWorld.DebugLog("Sync_CrossToServer_FamilyInfo toServerID=%s,syncZoneID=%s,syncFamilyIDList=%s" % (toServerID, syncZoneID, syncFamilyIDList))
     familyMgr = DBDataMgr.GetFamilyMgr()
     crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict() # 配置的互通
     if not crossZoneCfgDict:
@@ -1123,6 +1141,7 @@
     if crossServerID not in crossZoneCfgDict:
         return
     zoneCfgDict = crossZoneCfgDict[crossServerID]
+    GameWorld.DebugLog("    crossServerID=%s,zoneCfgDict=%s" % (crossServerID, zoneCfgDict))
     
     for zoneID in familyMgr.GetZoneIDListThisServer():
         if syncZoneID and syncZoneID != zoneID:
@@ -1134,6 +1153,7 @@
         if toServerID:
             if not GameWorld.CheckServerIDInList(toServerID, cfgServerIDList):
                 # 非指定目标服务器所属分区不同步
+                #GameWorld.DebugLog("    非指定目标服务器所属分区不同步 toServerID=%s" % (toServerID))
                 continue
             toServerIDList = [toServerID]
         else:
@@ -1260,6 +1280,7 @@
     syncData = familyMgr.GetSaveData(cntDict)
     familyIDList = familyMgr.GetFamilyIDList()
     
+    GameWorld.Log("dataslen=%s" % len(syncData))
     CrossMsg.SendToCrossServer(ShareDefine.S2C_FamilyData, {"syncData":syncData, "familyIDList":familyIDList, "cntDict":cntDict}, [crossServerID])
     return
 
@@ -1270,11 +1291,9 @@
     GameWorld.Log("收到游戏服同步的互通公会数据! fromServerID=%s,cntDict=%s,familyIDList=%s" % (fromServerID, cntDict, familyIDList))
     
     unpackRet = __unpackFamilyData(syncData, familyIDList, cntDict)
-    if not unpackRet:
-        errorMsg = "unknown"
-    else:
-        errorMsg = unpackRet[0]
-    if errorMsg:
+    isOK = unpackRet[0]
+    if not isOK:
+        errorMsg = unpackRet[1]
         GameWorld.SendGameErrorEx("S2C_FamilyDataError", "互通公会数据同步失败! fromServerID=%s,errorMsg=%s" % (fromServerID, errorMsg))
         CrossMsg.SendToClientServer(ShareDefine.C2S_FamilyDataRet, {"isOK":False}, [fromServerID])
         return
@@ -1287,7 +1306,6 @@
     
     syncFamilyIDList = []
     for dbData in familyDataList:
-        dbData = DBStruct.tagDBFamily()
         familyID = dbData.ID
         familyMgr.DelFamily(familyID, False) # 每次都强制先删除,支持重复同步
         zoneMgr.AddFamilyToZone(familyMgr.InitFamilyInstance(dbData))
@@ -1327,6 +1345,7 @@
     
     errorMsg = ""
     datas, pos, dataslen = syncData, 0, len(syncData)
+    GameWorld.Log("__unpackFamilyData: dataslen=%s" % dataslen)
     
     zoneIDDict = {}
     familyMgr = DBDataMgr.GetFamilyMgr()
@@ -1342,25 +1361,25 @@
         familyID = dbData.ID
         if familyID not in familyIDList:
             errorMsg = "同步的数据公会ID不匹配! familyID=%s not in %s" % (familyID, familyIDList)
-            return errorMsg
+            return False, errorMsg
         
         familyServerID = dbData.ServerID
         zoneID = familyMgr.GetZoneIDInThisServer(familyServerID)
         if zoneID <= 0:
             errorMsg = "同步的公会数据不属于本跨服! familyID=%s,familyServerID=%s,zoneID=%s" % (familyID, familyServerID, zoneID)
-            return errorMsg
+            return False, errorMsg
         zoneIDDict[zoneID] = familyServerID
         
     if len(zoneIDDict) != 1:
         errorMsg = "同步的公会数据分区异常可能存在多个分区! zoneIDDict=%s" % zoneIDDict
-        return errorMsg
+        return False, errorMsg
     zoneID = zoneIDDict.keys()[0]
     
     uppackFamilyCnt = len(familyDataList)
     familyDataCnt = cntDict.get("familyDataCnt", 0)
     if uppackFamilyCnt != familyDataCnt:
         errorMsg = "同步的公会个数不匹配! uppackFamilyCnt=%s != %s" % (uppackFamilyCnt, familyDataCnt)
-        return errorMsg
+        return False, errorMsg
     
     # 成员
     memberDataList = []
@@ -1375,7 +1394,7 @@
     membreDataCnt = cntDict.get("membreDataCnt", 0)
     if uppackMemberCnt != membreDataCnt:
         errorMsg = "同步的成员个数不匹配! uppackMemberCnt=%s != %s" % (uppackMemberCnt, membreDataCnt)
-        return errorMsg
+        return False, errorMsg
     
     # 行为
     actionDataList = []
@@ -1390,9 +1409,9 @@
     actionDataCnt = cntDict.get("actionDataCnt", 0)
     if uppackMemberCnt != membreDataCnt:
         errorMsg = "同步的行为个数不匹配! uppackActionCnt=%s != %s" % (uppackActionCnt, actionDataCnt)
-        return errorMsg
+        return False, errorMsg
     
-    return errorMsg, zoneID, familyDataList, memberDataList, actionDataList
+    return True, zoneID, familyDataList, memberDataList, actionDataList
 
 def C2S_FamilyDataRet(dataMsg, fromServerID):
     isOK = dataMsg["isOK"]
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 7e80e38..66e4296 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
@@ -21,6 +21,7 @@
 import ShareDefine
 import CommFunc
 import ChConfig
+import time
 
 class PlayerViewCache():
     
@@ -97,6 +98,8 @@
         if playerID in self.__viewCacheDict:
             return
         viewCache = PlayerViewCache(dbData)
+        if not viewCache.GetOffTime(): # 无值时默认离线时间为当前,适用于机器人、假人、重启加载数据时修正异常在线状态
+            viewCache.SetOffTime(int(time.time()))
         self.__viewCacheList.append(viewCache)
         self.__viewCacheDict[playerID] = viewCache
         self.__needSort = True
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 087b9c0..834e6c7 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
@@ -27,20 +27,27 @@
 def GetGMServerIDList(curPlayer):
     ## 获取命令额外发送到其他服务器,如跨服
     crossServerID = DBDataMgr.GetFamilyMgr().GetCurCrossServerID()
-    #GameWorld.DebugAnswer(curPlayer, "GetGMServerIDList: %s" % crossServerID)
+    GameWorld.DebugAnswer(curPlayer, "本服公会互通跨服ID:%s" % crossServerID)
     if crossServerID:
         return [crossServerID]
     return []
 
 def OnExecCross(crossPlayer, gmList):
     ## 跨服执行命令
-    GameWorld.DebugLog("OnExecCross %s" % gmList, crossPlayer.GetPlayerID())
+    playerID = crossPlayer.GetPlayerID()
+    familyMgr = DBDataMgr.GetFamilyMgr()
+    familyID = familyMgr.GetPlayerFamilyID(playerID)
+    zoneID = familyMgr.GetFamilyZoneID(familyID)
+    GameWorld.DebugAnswer(crossPlayer, "跨服公会ID:%s,zoneID=%s" % (familyID, zoneID))
+    OnExec(crossPlayer, gmList)
     return
 
 def OnExec(curPlayer, gmList):
     ## 游戏服执行命令
     
     if not gmList:
+        if GameWorld.IsCrossServer():
+            return
         GameWorld.DebugAnswer(curPlayer, "创建假人公会: CreatFamily 个数 [总战力 ServerID 等级 成员数  是否审核 官职限制]")
         GameWorld.DebugAnswer(curPlayer, "删除假人公会: CreatFamily 0")
         GameWorld.DebugAnswer(curPlayer, "输出公会列表: CreatFamily pl [条数 从第x名]")
@@ -51,46 +58,45 @@
     
     crossPlayer = CrossPlayer.GetCrossPlayerMgr().FindCrossPlayer(curPlayer.GetPlayerID())
     if not crossPlayer:
-        #GameWorld.DebugAnswer(curPlayer, "找不到crossPlayer")
         return
     
     value1 = gmList[0]
     if value1 == "pl":
-        __printFamilyList(curPlayer, gmList)
+        __printFamilyList(crossPlayer, gmList)
         return
     
     if value1 == "pf":
-        __printFamilyInfo(curPlayer, gmList)
+        __printFamilyInfo(crossPlayer, gmList)
         return
     
     if value1 == "sq":
-        __addFackRequestJoin(curPlayer, gmList)
+        __addFackRequestJoin(crossPlayer, gmList)
         return
     
     if value1 == "m":
-        __addFackMember(curPlayer, gmList, crossPlayer)
+        __addFackMember(crossPlayer, gmList)
         return
     
     creatCount = value1
     if creatCount <= 0:
-        __delFackFamily(curPlayer)
+        __delFackFamily(crossPlayer)
         return
-    __createFackFamily(curPlayer, gmList)
+    __createFackFamily(crossPlayer, gmList)
     return
 
-def __addFackMember(curPlayer, gmList, crossPlayer):
+def __addFackMember(crossPlayer, gmList):
     memCnt = gmList[1] if len(gmList) > 1 else 1
-    familyID = gmList[2] if len(gmList) > 2 else curPlayer.GetFamilyID()
+    familyID = gmList[2] if len(gmList) > 2 else crossPlayer.GetFamilyID()
     
     familyMgr = DBDataMgr.GetFamilyMgr()
     curFamily = familyMgr.FindFamily(familyID)
     if not curFamily:
-        GameWorld.DebugAnswer(curPlayer, "没有该公会: %s" % familyID)
+        GameWorld.DebugAnswer(crossPlayer, "没有该公会: %s" % familyID)
         return
     
     MemberMax = PlayerFamily.GetFamilySetting(curFamily.GetLV(), "MemberMax")
     if curFamily.GetCount() >= MemberMax:
-        GameWorld.DebugAnswer(curPlayer, "成员已满: %s" % MemberMax)
+        GameWorld.DebugAnswer(crossPlayer, "成员已满: %s" % MemberMax)
         return
     memCnt = min(memCnt, MemberMax - curFamily.GetCount())
     
@@ -120,17 +126,17 @@
         
     curZoneMgr.Sort()
     PlayerFamily.Sync_FamilyInfo(crossPlayer)
-    GameWorld.DebugAnswer(curPlayer, "增加成员数:%s, 总成员:%s" % (addCnt, curFamily.GetCount()))
+    GameWorld.DebugAnswer(crossPlayer, "增加成员数:%s, 总成员:%s" % (addCnt, curFamily.GetCount()))
     return
 
-def __addFackRequestJoin(curPlayer, gmList):
+def __addFackRequestJoin(crossPlayer, gmList):
     reqCnt = gmList[1] if len(gmList) > 1 else 1
-    familyID = gmList[2] if len(gmList) > 2 else curPlayer.GetFamilyID()
+    familyID = gmList[2] if len(gmList) > 2 else crossPlayer.GetFamilyID()
     
     familyMgr = DBDataMgr.GetFamilyMgr()
     family = familyMgr.FindFamily(familyID)
     if not family:
-        GameWorld.DebugAnswer(curPlayer, "没有该公会: %s" % familyID)
+        GameWorld.DebugAnswer(crossPlayer, "没有该公会: %s" % familyID)
         return
     
     reqCnt = min(reqCnt, 100)
@@ -149,10 +155,10 @@
             break
     # 广播给有招人权限的
     PlayerFamily.SendFamilyReqJoinInfo(familyID)
-    GameWorld.DebugAnswer(curPlayer, "增加申请数:%s, 总申请:%s" % (addCnt, len(family.GetReqJoinPlayerInfo())))
+    GameWorld.DebugAnswer(crossPlayer, "增加申请数:%s, 总申请:%s" % (addCnt, len(family.GetReqJoinPlayerInfo())))
     return
 
-def __printFamilyList(curPlayer, gmList):
+def __printFamilyList(crossPlayer, gmList):
     printCnt = gmList[1] if len(gmList) > 1 else 20
     fromIndex = gmList[2] if len(gmList) > 2 else 0
     
@@ -163,7 +169,7 @@
         zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
         zoneMgr.Sort()
         familyCnt = zoneMgr.GetCount()
-        GameWorld.DebugAnswer(curPlayer, "----- 【分区%s】公会总数: %s -----" % (zoneID, familyCnt))
+        GameWorld.DebugAnswer(crossPlayer, "----- 【分区%s】公会总数: %s -----" % (zoneID, familyCnt))
         for index in range(fromIndex, fromIndex + printCnt):
             if index >= familyCnt:
                 break
@@ -173,38 +179,38 @@
             text = "%s,ID:%s,LV:%s,战:%s,成:%s,审:%s,官:%s" % (rank, family.GetID(), family.GetLV(), family.GetFightPowerTotal(), family.GetCount(), family.GetJoinReview(), family.GetJoinLVMin())
             printAnswerCnt += 1
             if printAnswerCnt <= 100:
-                GameWorld.DebugAnswer(curPlayer, text)
+                GameWorld.DebugAnswer(crossPlayer, text)
             else:
                 GameWorld.DebugLog(text)
             
     return
 
-def __printFamilyInfo(curPlayer, gmList):
-    familyID = gmList[1] if len(gmList) > 1 else curPlayer.GetFamilyID()
+def __printFamilyInfo(crossPlayer, gmList):
+    familyID = gmList[1] if len(gmList) > 1 else crossPlayer.GetFamilyID()
     
     familyMgr = DBDataMgr.GetFamilyMgr()
     family = familyMgr.FindFamily(familyID)
     if not family:
-        GameWorld.DebugAnswer(curPlayer, "公会不存在: %s" % familyID)
+        GameWorld.DebugAnswer(crossPlayer, "公会不存在: %s" % familyID)
         return
     
     zoneID = familyMgr.GetFamilyZoneID(familyID)
-    GameWorld.DebugAnswer(curPlayer, "----- 【%s】 -----" % (GameWorld.CodeToGbk(family.GetName())))
-    GameWorld.DebugAnswer(curPlayer, "公会ID:%s, ServerID:%s, 分区:%s" % (familyID, family.GetServerID(), zoneID))
-    GameWorld.DebugAnswer(curPlayer, "LV:%s, Exp:%s" % (family.GetLV(), family.GetExp()))
-    GameWorld.DebugAnswer(curPlayer, "审核:%s, 官职条件:%s, 申请数:%s" % (family.GetJoinReview(), family.GetJoinLVMin(), len(family.GetReqJoinPlayerInfo())))
-    GameWorld.DebugAnswer(curPlayer, "战旗:%s, 旗号【%s】" % (family.GetEmblemID(), GameWorld.CodeToGbk(family.GetEmblemWord())))
-    GameWorld.DebugAnswer(curPlayer, "总战力:%s, 人数:%s" % (family.GetFightPowerTotal(), family.GetCount()))
-    GameWorld.DebugAnswer(curPlayer, "盟主ID:%s" % (family.GetLeaderID()))
+    GameWorld.DebugAnswer(crossPlayer, "----- 【%s】 -----" % (GameWorld.CodeToGbk(family.GetName())))
+    GameWorld.DebugAnswer(crossPlayer, "公会ID:%s, ServerID:%s, 分区:%s" % (familyID, family.GetServerID(), zoneID))
+    GameWorld.DebugAnswer(crossPlayer, "LV:%s, Exp:%s" % (family.GetLV(), family.GetExp()))
+    GameWorld.DebugAnswer(crossPlayer, "审核:%s, 官职条件:%s, 申请数:%s" % (family.GetJoinReview(), family.GetJoinLVMin(), len(family.GetReqJoinPlayerInfo())))
+    GameWorld.DebugAnswer(crossPlayer, "战旗:%s, 旗号【%s】" % (family.GetEmblemID(), GameWorld.CodeToGbk(family.GetEmblemWord())))
+    GameWorld.DebugAnswer(crossPlayer, "总战力:%s, 人数:%s" % (family.GetFightPowerTotal(), family.GetCount()))
+    GameWorld.DebugAnswer(crossPlayer, "盟主ID:%s" % (family.GetLeaderID()))
     for index in range(family.GetCount()):
         member = family.GetAt(index)
         playerID = member.GetPlayerID()
         fightPower = member.GetFightPowerTotal()
-        GameWorld.DebugAnswer(curPlayer, "%s,ID:%s,职位:%s,战力:%s" % (index, playerID, member.GetFmLV(), fightPower))
+        GameWorld.DebugAnswer(crossPlayer, "%s,ID:%s,职位:%s,战力:%s" % (index, playerID, member.GetFmLV(), fightPower))
         
     return
 
-def __delFackFamily(curPlayer):
+def __delFackFamily(crossPlayer):
     
     delCnt = 0
     familyMgr = DBDataMgr.GetFamilyMgr()
@@ -215,10 +221,10 @@
         familyMgr.DelFamily(familyID)
         
     remainCnt = len(familyMgr.GetFamilyIDList())
-    GameWorld.DebugAnswer(curPlayer, "删除假公会数: %s,剩余:%s" % (delCnt, remainCnt))
+    GameWorld.DebugAnswer(crossPlayer, "删除假公会数: %s,剩余:%s" % (delCnt, remainCnt))
     return
 
-def __createFackFamily(curPlayer, gmList):
+def __createFackFamily(crossPlayer, gmList):
     ## 个数 [总战力 ServerID 等级 成员数]
     
     creatCount = gmList[0] if len(gmList) > 0 else 1 # 默认1个
@@ -307,5 +313,5 @@
         createOKCnt += 1
         familyFightPower += 10000
         
-    GameWorld.DebugAnswer(curPlayer, "成功创建假公会: %s,总:%s" % (creatCount, len(familyMgr.GetFamilyIDList())))
+    GameWorld.DebugAnswer(crossPlayer, "成功创建假公会: %s,总:%s" % (creatCount, len(familyMgr.GetFamilyIDList())))
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Family.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Family.py
index 6ddd0c0..8fd4477 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Family.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Family.py
@@ -23,25 +23,33 @@
 import PlayerFamily
 import CrossPlayer
 import DBDataMgr
+import DBFamily
 import time
 
 def GetGMServerIDList(curPlayer):
     ## 获取命令额外发送到其他服务器,如跨服
     crossServerID = DBDataMgr.GetFamilyMgr().GetCurCrossServerID()
-    GameWorld.DebugAnswer(curPlayer, "GetGMServerIDList: %s" % crossServerID)
+    GameWorld.DebugAnswer(curPlayer, "本服公会互通跨服ID:%s" % crossServerID)
     if crossServerID:
         return [crossServerID]
     return []
 
-def OnExecCross(crossPlayer, msgList):
+def OnExecCross(crossPlayer, gmList):
     ## 跨服执行命令
-    GameWorld.DebugLog("OnExecCross %s" % msgList, crossPlayer.GetPlayerID())
+    playerID = crossPlayer.GetPlayerID()
+    familyMgr = DBDataMgr.GetFamilyMgr()
+    familyID = familyMgr.GetPlayerFamilyID(playerID)
+    zoneID = familyMgr.GetFamilyZoneID(familyID)
+    GameWorld.DebugAnswer(crossPlayer, "跨服公会ID:%s,zoneID=%s" % (familyID, zoneID))
+    OnExec(crossPlayer, gmList)
     return
 
 def OnExec(curPlayer, msgList):
     ## 游戏服执行命令
     
     if not msgList:
+        if GameWorld.IsCrossServer():
+            return
         GameWorld.DebugAnswer(curPlayer, "设置等级: Family lv 等级 经验")
         GameWorld.DebugAnswer(curPlayer, "设置徽章: Family e 徽章ID [剩余时间秒]")
         GameWorld.DebugAnswer(curPlayer, "设置贡献: Family c 今日贡献 累计贡献 [成员ID]")
@@ -56,9 +64,11 @@
     if not crossPlayer:
         return
     
+    isMainServer = GameWorld.IsMainServer()
     value = msgList[0]
-    
     if value == "l":
+        if not isMainServer:
+            return
         leaveCnt = msgList[1] if len(msgList) > 1 else 0
         kickedCnt = msgList[2] if len(msgList) > 2 else 0
         lastVoluntarily = msgList[3] if len(msgList) > 3 else 0
@@ -68,63 +78,67 @@
         GameWorld.DebugAnswer(curPlayer, "设置离开: Info=%s,%s" % (leaveInfo, GameWorld.ChangeTimeNumToStr(leaveTime)))
         return
     
-    familyID = curPlayer.GetFamilyID()
+    if isMainServer and DBFamily.IsFamilyCross():
+        GameWorld.DebugAnswer(curPlayer, "公会已跨服由跨服执行命令")
+        return
+    
+    familyID = crossPlayer.GetFamilyID()
     familyMgr = DBDataMgr.GetFamilyMgr()
     curFamily = familyMgr.FindFamily(familyID) if familyID else None
     if not curFamily:
-        GameWorld.DebugAnswer(curPlayer, "玩家未加入仙盟!")
+        GameWorld.DebugAnswer(crossPlayer, "玩家未加入仙盟!")
         return
     
     if value == "lv":
         lv = msgList[1] if len(msgList) > 1 else 1
         exp = msgList[2] if len(msgList) > 2 else 0
         if not IpyGameDataPY.GetIpyGameData("Family", lv):
-            GameWorld.DebugAnswer(curPlayer, "仙盟等级不存在: %s" % (lv))
+            GameWorld.DebugAnswer(crossPlayer, "仙盟等级不存在: %s" % (lv))
             return
         curFamily.SetLV(lv)
         curFamily.SetExp(exp)
-        GameWorld.DebugAnswer(curPlayer, "设置仙盟等级:%s, exp=%s" % (lv, exp))
+        GameWorld.DebugAnswer(crossPlayer, "设置仙盟等级:%s, exp=%s" % (lv, exp))
         
     elif value == "e":
         emblemID = msgList[1] if len(msgList) > 1 else 0
         setExpireTimes = msgList[2] if len(msgList) > 2 else None
         emblemActionObj = PlayerFamilyEmblem.AddFamilyEmblem(curFamily.GetID(), emblemID, setExpireTimes)
         if not emblemActionObj:
-            GameWorld.DebugAnswer(curPlayer, "该徽章ID无法添加")
+            GameWorld.DebugAnswer(crossPlayer, "该徽章ID无法添加")
             return
         endTime = PlayerFamilyEmblem.GetActionEmblemEndTime(emblemActionObj)
-        GameWorld.DebugAnswer(curPlayer, "添加徽章(%s)到期:%s" % (emblemID, GameWorld.ChangeTimeNumToStr(endTime)))
+        GameWorld.DebugAnswer(crossPlayer, "添加徽章(%s)到期:%s" % (emblemID, GameWorld.ChangeTimeNumToStr(endTime)))
         return
     
     elif value == "m":
-        CreateFamily.OnExec(curPlayer, msgList)
+        CreateFamily.OnExec(crossPlayer, msgList)
         return
     
     elif value == "n":
         PlayerFamily.SetRenameTime(curFamily, 0)
-        GameWorld.DebugAnswer(curPlayer, "重置改名CD")
+        GameWorld.DebugAnswer(crossPlayer, "重置改名CD")
         
     elif value == "c":
         contribDay = msgList[1] if len(msgList) > 1 else 0
         contribTotal = msgList[2] if len(msgList) > 2 else 0
-        memID = msgList[3] if len(msgList) > 3 else curPlayer.GetPlayerID()
+        memID = msgList[3] if len(msgList) > 3 else crossPlayer.GetPlayerID()
         member = curFamily.FindMember(memID)
         if not member:
-            GameWorld.DebugAnswer(curPlayer, "不存在该成员ID:%s" % memID)
+            GameWorld.DebugAnswer(crossPlayer, "不存在该成员ID:%s" % memID)
             return
         member.SetContribDay(contribDay)
         member.SetContribTotal(contribTotal)
-        GameWorld.DebugAnswer(curPlayer, "设置贡献:%s/%s, ID:%s" % (contribDay, contribTotal, memID))
+        GameWorld.DebugAnswer(crossPlayer, "设置贡献:%s/%s, ID:%s" % (contribDay, contribTotal, memID))
         
     elif value == "ml":
         memID = msgList[1] if len(msgList) > 1 else 0
         logoutMinutes = msgList[2] if len(msgList) > 2 else 0
         member = curFamily.FindMember(memID)
         if not member:
-            GameWorld.DebugAnswer(curPlayer, "不存在该成员ID:%s" % memID)
+            GameWorld.DebugAnswer(crossPlayer, "不存在该成员ID:%s" % memID)
             return
         member.SetOffTime(int(time.time()) - logoutMinutes * 60)
-        GameWorld.DebugAnswer(curPlayer, "成员ID:%s,离线时间:%s" % (memID, GameWorld.ChangeTimeNumToStr(member.GetOffTime())))
+        GameWorld.DebugAnswer(crossPlayer, "成员ID:%s,离线时间:%s" % (memID, GameWorld.ChangeTimeNumToStr(member.GetOffTime())))
         
     PlayerFamily.Sync_FamilyInfo(crossPlayer)
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
index 37590a0..1fb8f02 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -1371,6 +1371,22 @@
     ## 是否跨服中心服务器
     return GetServerType() == ShareDefine.serverType_CrossCenter
 
+def CheckCrossCenterUniquenessErr():
+    ## 检查跨服中心唯一性
+    # @return: 是否异常
+    if not IsCrossCenter():
+        return
+    serverCnt = 0
+    serverDict = ReadChConfig.GetServerConfigDict()
+    for serverInfo in serverDict.values():
+        serverType = serverInfo[ShareDefine.serverCfgIndex_ServerType]
+        if serverType == ShareDefine.serverType_CrossCenter:
+            serverCnt += 1
+            if serverCnt > 1:
+                SendGameErrorEx("CrossCenterUniquenessErr", "跨服中心只允许配置一台", isRaiseErr=True)
+                return
+    return
+
 def IsMainServer():
     ## 是否游戏服
     return GetServerType() == ShareDefine.serverType_Main
@@ -1407,7 +1423,7 @@
     #    MainServerDict = {} # 所属主服ID {子服ID:主服ID, ...}
     #    groupName = GetServerGroupName()
     #    serverDict = ReadChConfig.GetServerConfigDict()
-    #    for serverInfo in serverDict:
+    #    for serverInfo in serverDict.values():
     #        groupName = serverInfo[ShareDefine.serverCfgIndex_GroupName]
     #        serverMapID = serverInfo[ShareDefine.serverCfgIndex_MapID]
     #        serverType = serverInfo[ShareDefine.serverCfgIndex_ServerType]
@@ -2445,15 +2461,32 @@
 
 
 def DebugAnswer(curPlayer, text):
-    '''转码后再发DebugAnswer'''
+    '''转码后再发DebugAnswer
+    @param curPlayer: 跨服服务器时支持直接传入 crossPlayer
+    '''
     #===========================================================================
     # if not GetGameWorld().GetDebugLevel():
     #    return
     #===========================================================================
-    
-    DebugLog(text, curPlayer.GetPlayerID())
+    playerID = curPlayer.GetPlayerID()
+    if IsCrossServer():
+        crossPlayer = curPlayer
+        mainServerID = crossPlayer.GetMainServerID()
+        if not mainServerID:
+            return
+        import CrossMsg
+        CrossMsg.SendToClientServer(ShareDefine.C2S_GMDebugAnswer, {"text":text}, [mainServerID], playerID)
+        return
+    DebugLog(text, playerID)
     text = text.decode(ShareDefine.Def_Game_Character_Encoding).encode(GetCharacterEncoding())
     curPlayer.DebugAnswer(text)
+    return
+
+def C2S_GMDebugAnswer(dataMsg, playerID):
+    text = dataMsg["text"]
+    curPlayer = GetPlayerManager().FindPlayerByID(playerID)
+    if curPlayer:
+        DebugAnswer(curPlayer, text)
     return
 
 def RaiseException(errorMsg, playerID=0):
@@ -2465,10 +2498,10 @@
         SendGameError("MapServerRaiseException", errorMsg)
     return
 
-def SendGameErrorEx(errType, msgInfo="", playerID=0):
+def SendGameErrorEx(errType, msgInfo="", playerID=0, isRaiseErr=False):
     ErrLog("SendGameErrorEx: %s -> %s" % (errType, msgInfo), playerID)
     SendGameError(errType, msgInfo)
-    if GetGameWorld().GetDebugLevel():
+    if isRaiseErr or GetGameWorld().GetDebugLevel():
         raise Exception("%s -> %s" % (errType, msgInfo))
     return
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMgr.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMgr.py
index bd46703..6d22f2b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMgr.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMgr.py
@@ -76,6 +76,16 @@
     def SetConnState(self, connState): self._connState = connState
     def GetHeartCurTime(self): return self._heartCurTime # 上次收到该服心跳时的本服时间戳
     def SetHeartCurTime(self, curTime): self._heartCurTime = curTime
+    def IsServerOpen(self):
+        ## 是否正常开放中
+        
+        # 验证连接状态
+        if self._connState != ShareDefine.ssConn_Normal:
+            return False
+        
+        # 验证维护状态
+        
+        return True
     
 class SSServerMgr():
     ## 其他服务器管理器,所有服务器通用
@@ -103,14 +113,16 @@
     def DoHeartbeat(self, curTime):
         ## 心跳广播给其他服
         
+        if not GameWorld.IsCrossServer():
+            # 目前仅跨服服务器需要处理心跳广播 ,其他暂时不用
+            return
+        
         # 时间回调时也立刻同步心跳
         if self._heartTime and curTime >= self._heartTime and curTime - self._heartTime < HeartBreat:
+            #GameWorld.DebugLog("不广播心跳! self._heartTime=%s,curTime=%s,diff=%s" % (self._heartTime, curTime, curTime - self._heartTime))
             return
         self._heartTime = curTime
-        
-        if not GameWorld.IsCrossServer():
-            # 目前仅跨服服务器需要处理心跳,其他暂时不用
-            return
+        #GameWorld.DebugLog("广播心跳! self._heartTime=%s,%s" % (self._heartTime, GameWorld.ChangeTimeNumToStr(self._heartTime)))
         
         pack = ChServerToServerPyPack.tagSSHeart()
         pack.ServerID = GameWorld.GetGameWorld().GetServerID()
@@ -127,32 +139,42 @@
         curTime = int(time.time())
         
         ssServer = self.GetSSServer(serverID)
+        ssServer.SetServerType(serverType)
+        ssServer.SetHeartCurTime(curTime)
         
         befConnState = ssServer.GetConnState()
         
-        ssServer.SetServerType(serverType)
-        ssServer.SetConnState(ShareDefine.ssConn_Normal)
-        ssServer.SetHeartCurTime(curTime)
+        # 目标是跨服中心,更新跨服时间
+        if serverType == ShareDefine.serverType_CrossCenter:
+            if not self._crossCenterID:
+                self._crossCenterID = serverID
+                
+            updCrossTime = serverTime
+            curCrossTime = self.GetCrossTime()
+            self.SetCrossTime(updCrossTime, curTime)
+            diffSeconds = updCrossTime - curCrossTime # 误差秒
+            #GameWorld.DebugLog("curCrossTime=%s" % GameWorld.ChangeTimeNumToStr(curCrossTime))
+            #GameWorld.DebugLog("updCrossTime=%s" % GameWorld.ChangeTimeNumToStr(updCrossTime))
+            #GameWorld.DebugLog("与跨服时间误差=%s" % diffSeconds)
+            if abs(diffSeconds) >= 30:
+                GameWorld.Log("本服的跨服时间与跨服实际时间误差过大同步前端! diffSeconds=%s" % diffSeconds)
+                GameWorld.Log("curCrossTime=%s" % GameWorld.ChangeTimeNumToStr(curCrossTime))
+                GameWorld.Log("updCrossTime=%s" % GameWorld.ChangeTimeNumToStr(updCrossTime))
+                ChPlayer.Sync_PyServerDataTimeToClient()
+                
+        if befConnState == ShareDefine.ssConn_Normal:
+            #GameWorld.Log("收到目标跨服服务器心跳,正常连接中: crossServerID=%s,crossServerTime=%s" % (serverID, GameWorld.ChangeTimeNumToStr(serverTime)))
+            return
         
+        ssServer.SetConnState(ShareDefine.ssConn_Normal)
         isReconn = True if befConnState == ShareDefine.ssConn_Disconnected else False
         
         # 跨服服务器
-        if serverType == ShareDefine.serverType_CrossCenter:
-            GameWorld.Log("连上跨服中心服务器: crossServerID=%s,isReconn=%s,crossServerTime=%s" % (serverID, isReconn, GameWorld.ChangeTimeNumToStr(serverTime)))
-            if not self._crossCenterID:
-                self._crossCenterID = serverID
-            if serverID not in self._crossServerIDList:
-                self._crossServerIDList.append(serverID)
-                
-            lastCrossTime = self.GetCrossTime()
-            self.SetCrossTime(serverTime, curTime)
-            
-            # 时间回调或误差过大立即同步给前端
-            if serverTime < lastCrossTime or (serverTime - lastCrossTime) >= 30:
-                ChPlayer.Sync_PyServerDataTimeToClient()
-                
-        elif serverType == ShareDefine.serverType_Cross:
-            GameWorld.Log("连上跨服服务器: crossServerID=%s,isReconn=%s" % (serverID, isReconn))
+        if serverType in [ShareDefine.serverType_CrossCenter, ShareDefine.serverType_Cross]:
+            if serverType == ShareDefine.serverType_CrossCenter:
+                GameWorld.Log("连上跨服中心服务器: crossServerID=%s,isReconn=%s,crossServerTime=%s" % (serverID, isReconn, GameWorld.ChangeTimeNumToStr(serverTime)))
+            elif serverType == ShareDefine.serverType_Cross:
+                GameWorld.Log("连上常规跨服服务器: crossServerID=%s,isReconn=%s" % (serverID, isReconn))
             if serverID not in self._crossServerIDList:
                 self._crossServerIDList.append(serverID)
                 
@@ -167,6 +189,7 @@
         ## 获取跨服服务器时间 - 以跨服中心服务器为准,如果没有默认取本服时间
         curTime = int(time.time())
         if not self._crossTime:
+            #GameWorld.DebugLog("没有跨服时间,直接返回本服时间")
             return curTime
         self._crossTime += max(0, curTime - self._crossTimeCurTime)
         self._crossTimeCurTime = curTime
@@ -178,7 +201,8 @@
         self._crossTimeCurTime = curTime if curTime else int(time.time())
         return serverTime
     
-    def GetCrossServerIDList(self): return self._crossServerIDList
+    def GetCrossCenterID(self): return self._crossCenterID # 跨服中心服务器ID
+    def GetCrossServerIDList(self): return self._crossServerIDList # 所有运行中的跨服服务器ID,包含跨服中心
     
     def CheckSSServerDisconnected(self, curTime):
         ## 检查其他服是否断开连接
@@ -203,6 +227,7 @@
                 # 本服时间回调了暂不处理
                 continue
             if curTime - lastHeartTime <= DisconnectedTime:
+                #GameWorld.Log("检查断开时为正常连接中: serverID=%s,serverType=%s,pass=%s" % (ssServer.GetServerID(), ssServer.GetServerType(), curTime - lastHeartTime))
                 continue
             ssServer.SetConnState(ShareDefine.ssConn_Disconnected)
             
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMsg.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMsg.py
index 8d16fc5..ed555bd 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMsg.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/CrossMsg.py
@@ -22,6 +22,7 @@
 import NetPackCommon
 import ChServerToServerPyPack
 from GM import GMShell
+import PlayerViewCache
 import PlayerFamily
 import CrossPlayer
 import TurnAttack
@@ -39,6 +40,8 @@
     #if not dataMsg:
     #    return
     logData = "" if msgType in ShareDefine.NoLogDataSSMsgTypes else dataMsg
+    if msgType == ShareDefine.S2C_FamilyPyPack:
+        logData = "%s%s" % (dataMsg["funcName"], logData)
     GameWorld.Log("SendToCrossServer => %s, %s, %s" % (msgType, serverIDList, logData), playerID)
     SendToServer(msgType, dataMsg, serverIDList, ShareDefine.dirType_Cross, playerID, isLog=False)
     return
@@ -53,6 +56,8 @@
     #if not dataMsg:
     #    return
     logData = "" if msgType in ShareDefine.NoLogDataSSMsgTypes else dataMsg
+    if msgType == ShareDefine.C2S_SendFakePack:
+        logData = "%s%s" % (dataMsg["packHead"], logData)
     GameWorld.Log("SendToClientServer => %s, %s, %s" % (msgType, serverIDList, logData), playerID)
     SendToServer(msgType, dataMsg, serverIDList, ShareDefine.dirType_Main, playerID, isLog=False) # 默认发给主服即可
     return
@@ -144,6 +149,10 @@
         dataMsg = cPickle.loads(recvMsg)
         
         logData = "" if msgType in ShareDefine.NoLogDataSSMsgTypes else str(dataMsg)
+        if msgType == ShareDefine.C2S_SendFakePack:
+            logData = "%s%s" % (dataMsg["packHead"], logData)
+        elif msgType == ShareDefine.S2C_FamilyPyPack:
+            logData = "%s%s" % (dataMsg["funcName"], logData)
         GameWorld.Log("OnSSRecvMsg => %s, fromServerID=%s, %s,time=%s" % (msgType, fromServerID, logData, time.time()), playerID)
         
         # 所有类型服务器均可能收到的信息
@@ -151,6 +160,10 @@
             TurnAttack.S2B_BattleRequest(dataMsg, fromServerID, msgType)      
         elif msgType == ShareDefine.B2S_BattleResult: # 战斗结果
             TurnAttack.B2S_BattleResult(dataMsg, fromServerID, msgType)
+        elif msgType == ShareDefine.S2S_ViewTagFamily: # 查看目标公会
+            PlayerFamily.S2S_ViewTagFamily(dataMsg, fromServerID, playerID)
+        elif msgType == ShareDefine.S2S_ViewTagPlayer: # 查看目标玩家
+            PlayerViewCache.S2S_ViewTagPlayer(dataMsg, fromServerID, playerID)
             
         else:
             curServerType = GameWorld.GetServerType()
@@ -184,7 +197,7 @@
                 elif msgType == ShareDefine.C2S_FamilyPyPackRet:
                     PlayerFamily.C2S_FamilyPyPackRet(dataMsg, playerID)
                 elif msgType == ShareDefine.C2S_NotifyCode:
-                    CrossPlayer.C2S_NotifyCode(dataMsg, playerID)
+                    CrossPlayer.C2S_NotifyCode(dataMsg)
                 elif msgType == ShareDefine.C2S_SendFakePack:
                     CrossPlayer.C2S_SendFakePack(dataMsg)
                 elif msgType == ShareDefine.C2S_CostPlayerResources:
@@ -195,6 +208,8 @@
                     CrossPlayer.C2S_SetPlayerNomalDict(dataMsg, playerID)
                 elif msgType == ShareDefine.C2S_SendPlayerMail:
                     PlayerMail.C2S_SendPlayerMail(dataMsg, playerID)
+                elif msgType == ShareDefine.C2S_GMDebugAnswer:
+                    GameWorld.C2S_GMDebugAnswer(dataMsg, playerID)
                     
     except:
         GameWorld.RaiseException("服务器接收信息处理报错 \r\n%s" % str(traceback.format_exc()))
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
index e366e5e..08e4dfb 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
@@ -92,6 +92,9 @@
     PlayerViewCache.LoadRobot()
     PyGameData.g_initGameTime = int(time.time()) # 放到加载数据之后
     
+    # 检查跨服中心唯一性
+    GameWorld.CheckCrossCenterUniquenessErr()
+    
     if DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyTransDataTime):
         DBDataMgr.GetEventTrigMgr().SetValue(ShareDefine.Def_FamilyTransDataTime, 0)
         GameWorld.Log("启动服务器时重置跨服公会传输数据状态!")
@@ -464,15 +467,18 @@
         serverEventValue = centerEventValue
         DBDataMgr.GetEventTrigMgr().SetValue(ShareDefine.Def_CrossCenterEvent, centerEventValue)
         
-    if centerServerID:
-        GameWorld.Log("处理跨服中心事件值! serverEventValue=%s,centerEventValue=%s,centerServerID=%s" % (serverEventValue, centerEventValue, centerServerID))
-        
     if serverEventValue == centerEventValue:
-        GameWorld.DebugLog("跨服中心事件值不变! serverEventValue=%s,centerEventValue=%s,centerServerID=%s" % (serverEventValue, centerEventValue, centerServerID))
+        if centerServerID:
+            GameWorld.Log("本服与跨服中心事件值相同不处理! serverEventValue=%s,centerEventValue=%s,centerServerID=%s" % (serverEventValue, centerEventValue, centerServerID))
         return
     
-    serverEventTime = GameWorld.ChangeStrToDatetime("%s:%02d:%02d" % serverEventValue, ChConfig.TYPE_Time_Format_YmdHMS)
-    centerEventTime = GameWorld.ChangeStrToDatetime("%s:%02d:%02d" % centerEventValue, ChConfig.TYPE_Time_Format_YmdHMS)
+    if centerServerID:
+        GameWorld.Log("本服与跨服中心事件值变化! serverEventValue=%s,centerEventValue=%s,centerServerID=%s" % (serverEventValue, centerEventValue, centerServerID))
+    else:
+        GameWorld.Log("跨服中心服务器事件值变化! serverEventValue=%s,centerEventValue=%s" % (serverEventValue, centerEventValue))
+        
+    serverEventTime = GameWorld.ChangeStrToDatetime("%s" % serverEventValue, ChConfig.TYPE_Time_Format_YmdH)
+    centerEventTime = GameWorld.ChangeStrToDatetime("%s" % centerEventValue, ChConfig.TYPE_Time_Format_YmdH)
     
     serverHour = serverEventTime.hour
     serverDay = serverEventTime.day
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
index 2150f31..6953918 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
@@ -377,7 +377,8 @@
 def RecCrossServerNetPack(netPackBuffer):
     
     try:
-
+        GameWorld.GetGameWorld().SetCurGameWorldIndex(0) # 需要设置,不然获取不到 GetMap 等虚拟分线相关接口
+        
         #没有PY封包头
         if len(netPackBuffer) <= 1:
             return
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 2deb268..a51bd7d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -870,29 +870,34 @@
     return
 
 def S2C_OnlineState(dataMsg, fromServerID, playerID):
-    ## 收到游戏服玩家在线状态同步
+    '''收到游戏服玩家在线状态同步
+    跨服收到在线状态同步时都视为在跨服上线,需要处理跨服在线/上线的逻辑
+    不然在跨服维护游戏服不维护的情况下,等跨服重开后,游戏服重新同步在线玩家,此时如果跨服不处理登录逻辑,会少同步封包
+    如公会,跨服维护之后登录的玩家会取不到公会数据,等跨服重开后,需视为登录重新同步
+    与跨服重连一样的道理,都是重新同步所有信息
+    '''
     isOnline = dataMsg["isOnline"]
-    isLoginout = dataMsg["isLoginout"]
+    #isLoginout = dataMsg["isLoginout"] # 如果个别跨服功能有需要对真实上下线做特殊处理的可使用该参数判断
     baseInfo = dataMsg["baseInfo"]
     
     crossPlayer = UpdCrossPlayerFromMainServer(fromServerID, playerID, baseInfo, isOnline)
     
     # 其他跨服功能处理,暂时仅上下线时处理
     curServerID = GameWorld.GetGameWorld().GetServerID()
-    if isLoginout:
-        # 公会
-        if "crossFamilyServerID" in dataMsg:
-            crossFamilyServerID = dataMsg["crossFamilyServerID"]
-            if curServerID == crossFamilyServerID:
-                if isOnline:
-                    PlayerFamily.OnCrossPlayerLogin(crossPlayer)
-                else:
-                    PlayerFamily.OnCrossPlayerLogout(crossPlayer)
-                    
-        # 最后处理缓存,先放在更新中处理删除,有问题再放后面
-        #if not isOnline:
-        #    PlayerViewCache.OnCrossPlayerLogout(crossPlayer)
-        #    CrossPlayer.GetCrossPlayerMgr().DeletePlayer(playerID)
+    #if isLoginout:
+    # 公会
+    if "crossFamilyServerID" in dataMsg:
+        crossFamilyServerID = dataMsg["crossFamilyServerID"]
+        if curServerID == crossFamilyServerID:
+            if isOnline:
+                PlayerFamily.OnCrossPlayerLogin(crossPlayer)
+            else:
+                PlayerFamily.OnCrossPlayerLogout(crossPlayer)
+                
+    # 最后处理缓存,先放在更新中处理删除,有问题再放后面
+    #if not isOnline:
+    #    PlayerViewCache.OnCrossPlayerLogout(crossPlayer)
+    #    CrossPlayer.GetCrossPlayerMgr().DeletePlayer(playerID)
             
     # 最后同步处理跨服登录成功
     #if isLoginout and isOnline:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayer.py
index e683567..4440d86 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayer.py
@@ -26,6 +26,7 @@
 import IPY_GameObj
 import CrossMsg
 import ChConfig
+import CommFunc
 
 class CrossPlayerObj():
     ## 跨服在线玩家实例,不入库,由游戏服玩家登录同步,当做以前GameServer的Player处理,跨服及游戏服本服通用,方便统一逻辑
@@ -54,7 +55,7 @@
         self.SetServerID(curCache.GetServerID())
         self.SetMainServerID(fromServerID)
         self.SetRealmLV(curCache.GetRealmLV())
-        # familyID 由公会模块管理
+        self.SetFamilyID(curCache.GetFamilyID())
         return
     
     def GetPlayer(self): return self.__curPlayer
@@ -177,9 +178,9 @@
     if not crossServerPlayerDict:
         return
     
-    packBuff, packLen = clientPack.GetBuffer(), clientPack.GetLength()
+    packBuff, packLen, packHead = clientPack.GetBuffer(), clientPack.GetLength(), CommFunc.GetPackHead(clientPack)
     for mainServerID, playerIDList in crossServerPlayerDict.items():
-        dataMsg = {"playerIDList":playerIDList, "packBuff":packBuff, "packLen":packLen}
+        dataMsg = {"playerIDList":playerIDList, "packBuff":packBuff, "packLen":packLen, "packHead":packHead}
         playerID = playerIDList[0]
         CrossMsg.SendToClientServer(ShareDefine.C2S_SendFakePack, dataMsg, [mainServerID], playerID)
         
@@ -202,8 +203,17 @@
     
     playerID = crossPlayer.GetPlayerID()
     packBuff, packLen = clientPack.GetBuffer(), clientPack.GetLength()
-    dataMsg = {"playerIDList":[playerID], "packBuff":packBuff, "packLen":packLen}
+    dataMsg = {"playerIDList":[playerID], "packBuff":packBuff, "packLen":packLen, "packHead":CommFunc.GetPackHead(clientPack)}
     CrossMsg.SendToClientServer(ShareDefine.C2S_SendFakePack, dataMsg, [mainServerID], playerID)
+    return
+
+def SendFakePackByID(playerID, clientPack, fromServerID=0):
+    if not clientPack:
+        return
+    packBuff, packLen = clientPack.GetBuffer(), clientPack.GetLength()
+    dataMsg = {"playerIDList":[playerID], "packBuff":packBuff, "packLen":packLen, "packHead":CommFunc.GetPackHead(clientPack)}
+    CrossMsg.SendToClientServer(ShareDefine.C2S_SendFakePack, dataMsg, [fromServerID], playerID)
+    CrossMsg.SendToServer(ShareDefine.C2S_SendFakePack, dataMsg, [fromServerID], ShareDefine.dirType_All, playerID)
     return
 
 def C2S_SendFakePack(dataMsg):
@@ -232,16 +242,58 @@
         #本游戏服又没有玩家的不处理
         return
     playerID = crossPlayer.GetPlayerID()
-    dataMsg = {"msgMark":msgMark, "msgParamList":msgParamList}
+    dataMsg = {"playerIDList":[playerID], "msgMark":msgMark, "msgParamList":msgParamList}
     CrossMsg.SendToClientServer(ShareDefine.C2S_NotifyCode, dataMsg, [mainServerID], playerID)
     return
 
-def C2S_NotifyCode(dataMsg, playerID):
+def FamilyNotify(familyID, msgMark, msgParamList=[], excludeIDList=[]):
+    family = DBDataMgr.GetFamilyMgr().FindFamily(familyID)
+    if not family:
+        return
+    
+    curServerID = GameWorld.GetGameWorld().GetServerID()
+    crossServerPlayerDict = {}
+    crossPlayerMgr = GetCrossPlayerMgr()
+    for index in range(family.GetCount()):
+        member = family.GetAt(index)
+        playerID = member.GetPlayerID()
+        if excludeIDList and playerID in excludeIDList:
+            continue
+        crossPlayer = crossPlayerMgr.FindCrossPlayer(playerID)
+        if not crossPlayer:
+            # 不在线
+            continue
+        curPlayer = crossPlayer.GetPlayer()
+        if curPlayer: # 有玩家,一般只有游戏服有,可视为游戏服在线,直接发送
+            PlayerControl.NotifyCode(curPlayer, msgMark, msgParamList)
+            continue
+        mainServerID = crossPlayer.GetMainServerID()
+        if mainServerID == curServerID:
+            #本游戏服又没有玩家的不处理
+            continue
+        if mainServerID not in crossServerPlayerDict:
+            crossServerPlayerDict[mainServerID] = []
+        playerIDList = crossServerPlayerDict[mainServerID]
+        if playerID not in playerIDList:
+            playerIDList.append(playerID)
+            
+    for mainServerID, playerIDList in crossServerPlayerDict.items():
+        dataMsg = {"playerIDList":playerIDList, "msgMark":msgMark, "msgParamList":msgParamList}
+        CrossMsg.SendToClientServer(ShareDefine.C2S_NotifyCode, dataMsg, [mainServerID])
+    return
+
+def C2S_NotifyCode(dataMsg):
     msgMark = dataMsg["msgMark"]
     msgParamList = dataMsg["msgParamList"]
-    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
-    if curPlayer:
+    playerIDList = dataMsg["playerIDList"]
+    
+    playerManager = GameWorld.GetPlayerManager()
+    for playerID in playerIDList:
+        curPlayer = playerManager.FindPlayerByID(playerID)
+        if curPlayer == None:
+            continue
         PlayerControl.NotifyCode(curPlayer, msgMark, msgParamList)
+        
     return
 
 def OnPlayerLogin(curPlayer):
@@ -414,8 +466,8 @@
     if resetType != "":
         centerEventValue = eventData.get("centerEventValue", 0)
         playerEventValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_OnCrossEvent)
-        centerEventTime = GameWorld.ChangeStrToDatetime("%s:%02d:%02d" % centerEventValue, ChConfig.TYPE_Time_Format_YmdHMS)
-        playerEventTime = GameWorld.ChangeStrToDatetime("%s:%02d:%02d" % playerEventValue, ChConfig.TYPE_Time_Format_YmdHMS)
+        centerEventTime = GameWorld.ChangeStrToDatetime("%s" % centerEventValue, ChConfig.TYPE_Time_Format_YmdH)
+        playerEventTime = GameWorld.ChangeStrToDatetime("%s" % playerEventValue, ChConfig.TYPE_Time_Format_YmdH)
         
         center_Day = centerEventTime.day
         center_Month = centerEventTime.month
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 434cc25..25fab78 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -4321,7 +4321,8 @@
     #if value < beforeFightPower:
     #    DataRecordPack.DR_FightPowerChangeInfo(curPlayer, beforeFightPower)
     GameWorld.DebugLog("总战力: %s, beforeFightPower=%s" % (value, beforeFightPower), curPlayer.GetPlayerID())
-    ChPlayer.OnPlayerBaseInfoChange(curPlayer, IPY_PlayerDefine.CDBPlayerRefresh_FightPower) # 战力
+    if beforeFightPower != value:
+        ChPlayer.OnPlayerBaseInfoChange(curPlayer, IPY_PlayerDefine.CDBPlayerRefresh_FightPower) # 战力
     return
 
 ## 设置模块战斗力,支持超过20E = 模块公式战力 + 技能附加战力 + 其他附加战力
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 0cdd336..5ff46fc 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -244,8 +244,8 @@
     if playerEventValue == centerEventValue:
         return
     
-    centerEventTime = GameWorld.ChangeStrToDatetime("%s:%02d:%02d" % centerEventValue, ChConfig.TYPE_Time_Format_YmdHMS)
-    playerEventTime = GameWorld.ChangeStrToDatetime("%s:%02d:%02d" % playerEventValue, ChConfig.TYPE_Time_Format_YmdHMS)
+    centerEventTime = GameWorld.ChangeStrToDatetime("%s" % centerEventValue, ChConfig.TYPE_Time_Format_YmdH)
+    playerEventTime = GameWorld.ChangeStrToDatetime("%s" % playerEventValue, ChConfig.TYPE_Time_Format_YmdH)
     
     center_Day = centerEventTime.day
     center_Month = centerEventTime.month
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 267b678..c2c6d64 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamily.py
@@ -35,6 +35,7 @@
 import DBDataMgr
 import DBFamily
 import CrossMsg
+import CrossMgr
 
 import random
 import time
@@ -77,7 +78,7 @@
 
 def FamilyOnHour():
     if not GameWorld.IsMainServer() or DBFamily.IsFamilyCross():
-        # 非游戏服或本服已跨服互通了不处理
+        GameWorld.DebugLog("非游戏服或本服已跨服互通了不处理 FamilyOnHour")
         return
     __doFamilyOnHour()
     return
@@ -101,7 +102,7 @@
     ## 本服时间自己触发的onday逻辑
     
     if not GameWorld.IsMainServer() or DBFamily.IsFamilyCross():
-        # 非游戏服或本服已跨服互通了不处理
+        GameWorld.DebugLog("非游戏服或本服已跨服互通了不处理 FamilyOnDay")
         return
     
     __doFamilyOnDay()
@@ -125,7 +126,7 @@
                 member.SetContribDay(0)
                 member.SetDonateCntDay(0)
                 
-            Broadcast_FamilyInfo(familyID)
+            Broadcast_FamilyInfo(familyID) # onday
     return
 
 def PlayerCrossCenterOnDay(curPlayer):
@@ -153,7 +154,7 @@
 def OnPlayerLogin(curPlayer, tick):
     Do_MapServer_PlayerLogin(curPlayer)
     if DBFamily.IsFamilyCross():
-        #公会已跨服不处理,由所属跨服服务器处理成员登录逻辑
+        GameWorld.DebugLog("公会已跨服不处理,由所属跨服服务器处理成员登录逻辑 OnPlayerLogin", curPlayer.GetPlayerID())
         return
     crossPlayer = CrossPlayer.GetCrossPlayerMgr().FindCrossPlayer(curPlayer.GetPlayerID())
     OnCrossPlayerLogin(crossPlayer)
@@ -168,7 +169,7 @@
 
 def OnPlayerLogout(curPlayer):
     if DBFamily.IsFamilyCross():
-        #公会已跨服不处理,由所属跨服服务器处理成员登录逻辑
+        GameWorld.DebugLog("公会已跨服不处理,由所属跨服服务器处理成员离线逻辑 OnPlayerLogout", curPlayer.GetPlayerID())
         return
     crossPlayer = CrossPlayer.GetCrossPlayerMgr().FindCrossPlayer(curPlayer.GetPlayerID())
     OnCrossPlayerLogout(crossPlayer)
@@ -190,7 +191,7 @@
     curMember.SetOffTime(int(time.time()))
     
     # 通知成员下线
-    Broadcast_FamilyInfo(familyID, changeMemIDList=[playerID])
+    Broadcast_FamilyInfo(familyID, changeMemIDList=[playerID]) # 成员下线
     return
 
 def SendToFamilyMapPlayer(crossPlayer, doType, doData):
@@ -225,6 +226,8 @@
             familyID = 0
                     
     crossPlayer.SetFamilyID(familyID)
+    # 同步更新查看缓存
+    PlayerViewCache.UpdPlayerViewFamilyInfo(playerID, familyID, FamilyName, EmblemID, EmblemWord)
     
     doData = {"FamilyID":familyID}
     if familyID:
@@ -242,7 +245,7 @@
     refreshFamilyID = familyMgr.GetPlayerFamilyID(playerID)
     GameWorld.DebugLog("PlayerLoginRefreshFamily playerID=%s,refreshFamilyID=%s" % (playerID, refreshFamilyID))
     crossPlayer.SetFamilyID(refreshFamilyID)
-    MapServer_FamilyRefresh(crossPlayer, refreshFamilyID)
+    MapServer_FamilyRefresh(crossPlayer, refreshFamilyID) # 登录
     familyID = refreshFamilyID
     if not familyID:
         return
@@ -258,7 +261,7 @@
     
     Sync_FamilyInfo(crossPlayer) # 给自己同步完整的
     # 广播成员在线
-    Broadcast_FamilyInfo(familyID, changeMemIDList=[playerID], excludeIDList=[playerID])
+    Broadcast_FamilyInfo(familyID, changeMemIDList=[playerID], excludeIDList=[playerID]) # 成员登录
     
     #通知招人
     if GetFamilyMemberHasPow(curMember, FamilyPowerID_Call):
@@ -312,13 +315,18 @@
             __doFamilyPyPackRet(curPlayer, clientData, funcName, isOK)
         return
     
+    ssServer = CrossMgr.GetSSServerMgr().GetSSServer(crossServerID)
+    if not ssServer or not ssServer.IsServerOpen():
+        PlayerControl.NotifyCode(curPlayer, "ServerNoOpen")
+        return
+    
     # 转发请求CD验证
     if reqCD:
-        reqTick = curPlayer.GetDictByKey("FamilyPyPackForwardingTick")
+        reqTick = curPlayer.GetDictByKey(funcName) # 根据函数名单独处理CD,防止相互影响
         if reqTick and (tick - reqTick) < reqCD * 1000:
             PlayerControl.NotifyCode(curPlayer, "RequestLater")
             return
-        curPlayer.SetDict("FamilyPyPackForwardingTick", tick)
+        curPlayer.SetDict(funcName, tick)
         
     # 剩下的就是大于0
     dataMsg = {"funcName":funcName}
@@ -352,10 +360,11 @@
     curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
     if not curPlayer:
         return
-    curPlayer.SetDict("FamilyPyPackForwardingTick", 0)
-    
     funcName = dataMsg["funcName"]
     packBuff = dataMsg.get("packBuff")
+    
+    curPlayer.SetDict(funcName, 0) # 重置CD
+    
     clientData = None
     if packBuff:
         clientData = NetPackCommon.ReadRecPyPackData(packBuff)
@@ -470,11 +479,13 @@
         GameWorld.ErrLog("创建家族失败", playerID)
         return
     newFamilyID = curFamily.GetID()
+    zoneMgr = familyMgr.GetZoneFamilyMgrByFamilyID(newFamilyID)
+    zoneID = zoneMgr.GetZoneID() if zoneMgr else -1
     curFamily.SetLV(1)
     emblemIDList = PlayerFamilyEmblem.GetDefaultFamilyEmblemIDList()
     if not emblemID or emblemID not in emblemIDList:
         emblemID = random.choice(emblemIDList) # 从默认徽章中随机选择一个
-    GameWorld.Log("创建公会: familyID=%s,playerID=%s,emblemID=%s,serverID=%s" % (newFamilyID, playerID, emblemID, serverID))
+    GameWorld.Log("创建公会: familyID=%s,playerID=%s,emblemID=%s,serverID=%s,zoneID=%s" % (newFamilyID, playerID, emblemID, serverID, zoneID))
     curFamily.SetEmblemID(emblemID)
     curFamily.SetEmblemWord(emblemWord)
     
@@ -486,9 +497,9 @@
         
     #-设置家族成员属性
     DoPlayerJionFamily(curFamily, playerID, crossPlayer, IPY_PlayerDefine.fmlLeader)
-    zoneMgr = familyMgr.GetZoneFamilyMgrByFamilyID(newFamilyID)
-    zoneMgr and zoneMgr.Sort()
-    
+    if zoneMgr:
+        zoneMgr.Sort()
+        
     #XW_JZ_EstablishSud <n color="255,255,0">恭喜您,家族建立成功!</n>    25  -   -
     #CrossPlayer.NotifyCode(crossPlayer, "XW_JZ_EstablishSud")
     #PlayerControl.WorldNotify(0, "jiazu_liubo_671654", [curPlayer.GetName(), fullFamilyName, newFamilyID])
@@ -559,26 +570,25 @@
     member = curFamily.AddMember(playerID)
     member.SetFmLV(jionFamilySetLv)
     member.RefreshMemberByID(playerID)
-    curFamily.SetFightPowerTotal(curFamily.GetFightPowerTotal() + member.GetFightPowerTotal())
     
     if jionFamilySetLv == IPY_PlayerDefine.fmlLeader:
         curFamily.SetLeaderID(playerID)
         
     if broadcastFamilyChange:
         # 广播其他在线成员
-        Broadcast_FamilyInfo(familyID, changeMemIDList=[playerID], excludeIDList=[playerID])
+        Broadcast_FamilyInfo(familyID, changeMemIDList=[playerID], excludeIDList=[playerID]) # 成员加入
         
     familyMgr.DelPlayerReqJoinFamilyIDAll(playerID)
     #设置玩家身上保存的家族信息
     if crossPlayer:
-        MapServer_FamilyRefresh(crossPlayer, familyID)
+        MapServer_FamilyRefresh(crossPlayer, familyID) # 加入
         Sync_FamilyInfo(crossPlayer) # 给自己同步完整的
         Sync_RequestAddFamilyInfo(crossPlayer)
         PlayerFamilyTaofa.OnCrossPlayerEnterFamily(crossPlayer)
         
-    #if jionFamilySetLv != IPY_PlayerDefine.fmlLeader:
+    if jionFamilySetLv != IPY_PlayerDefine.fmlLeader:
         #通知所有家族成员, 这个人加入了家族
-        #NotifyAllFamilyMemberMsg(familyID, "XW_JZ_EnterFamily", [member.GetPlayerName()], excludeIDList=[playerID])
+        CrossPlayer.FamilyNotify(familyID, "XW_JZ_EnterFamily", [member.GetPlayerName()], excludeIDList=[playerID])
         #if jionPlayer:
         #    PlayerControl.NotifyCode(jionPlayer, 'XW_JZ_EnterFamilyInfo', [family.GetName()])
             
@@ -1086,7 +1096,7 @@
     #    return
     SendFamilyReqJoinInfo(familyID)
     if joinOKPlayerIDList:
-        Broadcast_FamilyInfo(familyID, changeMemIDList=joinOKPlayerIDList, excludeIDList=joinOKPlayerIDList)
+        Broadcast_FamilyInfo(familyID, changeMemIDList=joinOKPlayerIDList, excludeIDList=joinOKPlayerIDList) # 审核
     return
 
 #// A6 22 修改收人方式 #tagCMChangeFamilyJoin
@@ -1124,7 +1134,7 @@
     GameWorld.DebugLog("修改招人设置: familyID=%s,joinReview=%s,joinLVMin=%s" % (familyID, joinReview, joinLVMin), playerID)
     family.SetJoinReview(joinReview)
     family.SetJoinLVMin(joinLVMin)
-    Broadcast_FamilyInfo(familyID, isSyncMem=False)
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 修改招人
     return
 
 #// A6 23 修改家族公告 #tagCMChangeFamilyBroadcast
@@ -1158,7 +1168,7 @@
         return
     family.SetBroadcast(broadcast)
     GameWorld.DebugLog('更改公会公告: Family=%s,公告=%s' % (GameWorld.CodeToGbk(family.GetName()), GameWorld.CodeToGbk(broadcast)), playerID)
-    Broadcast_FamilyInfo(familyID, isSyncMem=False)
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 修改公告
     return
 
 #// A6 24 修改家族徽章 #tagCMChangeFamilyEmblem
@@ -1265,7 +1275,7 @@
         
     if isGMOP:
         family.SetBroadcast("")
-    Broadcast_FamilyInfo(familyID, changeMemIDList=changeMemIDList)
+    Broadcast_FamilyInfo(familyID, changeMemIDList=changeMemIDList) # 修改职位
     return True
 
 def ChangeFamilyLeader(family, newLeaderMem):
@@ -1298,7 +1308,7 @@
     
     tagCrossPlayer = CrossPlayer.GetCrossPlayerMgr().FindCrossPlayer(tagID)
     if tagCrossPlayer:
-        MapServer_FamilyRefresh(tagCrossPlayer, familyID)
+        MapServer_FamilyRefresh(tagCrossPlayer, familyID) # 修改职位
         if GetFamilyMemberHasPow(tagMember, FamilyPowerID_Call):
             CrossPlayer.SendFakePack(tagCrossPlayer, GetPack_FamilyReqJoinInfo(familyID))
         
@@ -1308,8 +1318,7 @@
                         [ShareDefine.Def_FamilyActionEvent_MemberChange, ShareDefine.Def_FamilyMemberChange_FMLV, changeFamilyLV, befFamilyLV], tick)
     
     #xx被任命为xx
-    #NotifyAllFamilyMemberMsg(familyID, "XW_JZ_AppointFamily", [memName, changeFamilyLV])
-    #GetFamilyMgr().SetSyncCrossFamilyUpd(familyMember.GetFamilyID(), familyMember.GetPlayerID(), syncNow=True) # 成员职位变更
+    CrossPlayer.FamilyNotify(familyID, "XW_JZ_AppointFamily", [memName, changeFamilyLV])
     return
 
 def __AutoChangeLeader(curFamily):
@@ -1376,7 +1385,7 @@
     GameWorld.Log("公会自动传位: familyID=%s,leaderID=%s,offTime=%s,passHours=%s,newLeaderID=%s" 
                   % (familyID, leaderID, GameWorld.ChangeTimeNumToStr(offTime), passHours, newLeaderID))
     ChangeFamilyLeader(curFamily, toMember)
-    Broadcast_FamilyInfo(familyID, changeMemIDList=[leaderID, newLeaderID])
+    Broadcast_FamilyInfo(familyID, changeMemIDList=[leaderID, newLeaderID]) # 自动传位
     
     # 邮件通知
     toServerID = toMember.GetServerID()
@@ -1437,12 +1446,11 @@
     AddFamilyActionNote(crossPlayer.GetPlayerName(), familyID, ShareDefine.Def_ActionType_FamilyEvent, 
                         [ShareDefine.Def_FamilyActionEvent_MemberChange, ShareDefine.Def_FamilyMemberChange_Leave], tick)
     
-    #XW_JZ_LeaveFamily   <n color="0,190,255">{%S1%}</n><n color="255,255,0">退出了家族!</n>  25  -   -
-    #NotifyAllFamilyMemberMsg(familyID, "XW_JZ_LeaveFamily", [curPlayer.GetName()])
-    
     __DoPlayerLeaveFamilyByID(family, playerID, crossPlayer)
-    MapServer_FamilyRefresh(crossPlayer, 0, 1)
+    MapServer_FamilyRefresh(crossPlayer, 0, 1) # 主动退出
     CrossPlayer.SendFakePackByFamily(familyID, GetPack_FamilyDel(playerID, crossPlayer.GetPlayerName(), 1))
+    CrossPlayer.FamilyNotify(familyID, "XW_JZ_LeaveFamily", [crossPlayer.GetPlayerName()])
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 退出
     
     if family.GetCount() == 0:
         #玩家离开后, 家族没有人了 , 删除这个家族
@@ -1508,15 +1516,17 @@
                         [ShareDefine.Def_FamilyActionEvent_MemberChange, ShareDefine.Def_FamilyMemberChange_KickOut], tick)
     
     #XW_JZ_LeaveFamily   <n color="0,190,255">{%S1%}</n><n color="255,255,0">退出了家族!</n>  25  -   -
-    #NotifyAllFamilyMemberMsg(familyID, "XW_JZ_LeaveFamily", [tagPlayerName])
+    CrossPlayer.FamilyNotify(familyID, "XW_JZ_LeaveFamily", [tagPlayerName])
     
     #删除玩家
-    crossPlayer = CrossPlayer.GetCrossPlayerMgr().FindCrossPlayer(tagMemberID)
-    __DoPlayerLeaveFamilyByID(family, tagPlayerID, crossPlayer)
-    if crossPlayer:
-        MapServer_FamilyRefresh(crossPlayer, 0)
+    tagCrossPlayer = CrossPlayer.GetCrossPlayerMgr().FindCrossPlayer(tagMemberID)
+    __DoPlayerLeaveFamilyByID(family, tagPlayerID, tagCrossPlayer)
+    if tagCrossPlayer:
+        MapServer_FamilyRefresh(tagCrossPlayer, 0) # 被踢
+        CrossPlayer.NotifyCode(tagCrossPlayer, "XW_JZ_LeaveFamilyKick", [curMember.GetPlayerName()])
         
     CrossPlayer.SendFakePackByFamily(familyID, GetPack_FamilyDel(tagMemberID, tagPlayerName, 0))
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 踢人
     return
 
 def __DoPlayerLeaveFamilyByID(curFamily, leavePlayerID, crossPlayer=None):
@@ -1593,11 +1603,66 @@
         memCrossPlayer = crossPlayerMgr.FindCrossPlayer(memID)
         if not memCrossPlayer:
             continue
-        MapServer_FamilyRefresh(memCrossPlayer, familyID)
+        MapServer_FamilyRefresh(memCrossPlayer, familyID) # 改名
         #player.Notify_FamilyNameRefresh() #//04 36    周围玩家家族名刷新#tagPlayerFamilyNameRefresh
         
-    Broadcast_FamilyInfo(familyID, isSyncMem=False)
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 改名
     return True
+
+#// A6 19 查看目标公会 #tagCSViewTagFamily
+#
+#struct tagCSViewTagFamily
+#{
+#    tagHead        Head;
+#    DWORD        FamilyID;
+#    DWORD        DataServerID;    //数据所在服务器ID
+#};
+def OnViewTagFamily(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    tagFamilyID = clientData.FamilyID
+    dataServerID = clientData.DataServerID
+    
+    # 本服或主服是本服
+    if not dataServerID or dataServerID == GameWorld.GetGameWorld().GetServerID():
+        NetPackCommon.SendFakePack(curPlayer, GetTagFamilyInfoPack(tagFamilyID))
+        return
+    
+    CrossMsg.SendToServer(ShareDefine.S2S_ViewTagFamily, {"tagFamilyID":tagFamilyID}, [dataServerID], ShareDefine.dirType_All, playerID)
+    return
+
+def S2S_ViewTagFamily(dataMsg, fromServerID, playerID):
+    tagFamilyID = dataMsg["tagFamilyID"]
+    CrossPlayer.SendFakePackByID(playerID, GetTagFamilyInfoPack(tagFamilyID), fromServerID)
+    return
+
+def GetTagFamilyInfoPack(tagFamilyID):
+    familyMgr = DBDataMgr.GetFamilyMgr()
+    family = familyMgr.FindFamily(tagFamilyID)
+    if not family:
+        GameWorld.ErrLog("本服数据找不到目标公会! tagFamilyID=%s" % tagFamilyID)
+        return
+    clientPack = ChPyNetSendPack.tagSCTagFamilyInfo()
+    clientPack.FamilyID = family.GetID()
+    clientPack.FamilyName = family.GetName()
+    clientPack.FamilyNameLen = len(clientPack.FamilyName)
+    clientPack.LeaderID = family.GetLeaderID()
+    leaderMember = family.FindMember(clientPack.LeaderID)
+    if leaderMember:
+        clientPack.LeaderName = leaderMember.GetPlayerName()
+        clientPack.LeaderNameLen = len(clientPack.LeaderName)
+        clientPack.LeaderServerID = leaderMember.GetServerID()
+    clientPack.FamilyLV = family.GetLV()
+    clientPack.ServerID = family.GetServerID()
+    clientPack.EmblemID = family.GetEmblemID()
+    clientPack.EmblemWord = family.GetEmblemWord()
+    clientPack.FightPower = family.GetFightPower()
+    clientPack.FightPowerEx = family.GetFightPowerEx()
+    clientPack.Broadcast = family.GetBroadcast()
+    clientPack.BroadcastLen = len(clientPack.Broadcast)
+    clientPack.MemberCount = family.GetCount()
+    clientPack.DataServerID = GameWorld.GetGameWorld().GetServerID()
+    return clientPack
 
 #// A6 20 搜索家族列表 #tagCMViewFamilyPage
 #
@@ -1687,6 +1752,7 @@
         clientPack.FamilyCount = len(clientPack.FamilyList)
         if clientPack.FamilyCount >= showCount:
             break
+    clientPack.DataServerID = GameWorld.GetGameWorld().GetServerID()
     CrossPlayer.SendFakePack(crossPlayer, clientPack)
     return
 
@@ -1815,7 +1881,7 @@
     curFamily.SetLV(updLV)
     curFamily.SetExp(updExp)
     
-    Broadcast_FamilyInfo(familyID, isSyncMem=False)
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 公会经验
     return True
 
 def AddFamilyContrib(curPlayer, addContribValue):
@@ -1847,7 +1913,7 @@
     curMember.SetContribTotal(contribTotal)
     GameWorld.DebugLog("增加成员贡献: familyID=%s,addContribValue=%s,contribDay=%s,contribTotal=%s" % (familyID, addContribValue, contribDay, contribTotal), playerID)
     
-    Broadcast_FamilyInfo(familyID, isSyncMem=False)
+    Broadcast_FamilyInfo(familyID, isSyncMem=False) # 成员贡献
     return
 
 ## ------------------------------------------------------------------------------------------------
@@ -1970,6 +2036,7 @@
     return
 
 def Do_MapServer_PlayerLogin(curPlayer):
+    DBFamily.Sync_FamilyCrossInfo(curPlayer)
     SyncDonateCntInfo(curPlayer)
     PlayerFamilyZhenbaoge.OnPlayerLogin(curPlayer)
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamilyEmblem.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamilyEmblem.py
index 1d5337f..d32beed 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamilyEmblem.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFamilyEmblem.py
@@ -71,7 +71,7 @@
                     updEmblemID = random.choice(defaultEmblemIDList) if defaultEmblemIDList else 0
                     GameWorld.Log("仙盟佩戴徽章过期恢复随机默认徽章! familyID=%s,emblemID=%s,endTime=%s,updEmblemID=%s" % (familyID, emblemID, endTime, updEmblemID))
                     family.SetEmblemID(updEmblemID)
-                    PlayerFamily.Broadcast_FamilyInfo(familyID, isSyncMem=False)
+                    PlayerFamily.Broadcast_FamilyInfo(familyID, isSyncMem=False) # 徽章过期
     return
 
 def GetFamilyEmblemActionData(familyID, emblemID):
@@ -182,5 +182,5 @@
     curFamily.SetEmblemID(emblemID)
     if emblemWord:
         curFamily.SetEmblemWord(emblemWord)
-    PlayerFamily.Broadcast_FamilyInfo(familyID, isSyncMem=False)
+    PlayerFamily.Broadcast_FamilyInfo(familyID, isSyncMem=False) # 徽章修改
     return True
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
index 216ce3e..1ba03a5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
@@ -32,6 +32,7 @@
 import ShareDefine
 import TurnAttack
 import DBDataMgr
+import CrossMsg
 
 import random
 import time
@@ -267,9 +268,8 @@
     #curCache.SetFamilyEmblemWord(familyBase.GetEmblemWord())
     curCache.SetFightPowerTotal(PlayerControl.GetFightPower(curPlayer))
     curCache.SetServerID(GameWorld.GetPlayerServerID(curPlayer))
-    if isOffline:
-        curCache.SetOffTime(int(time.time()))
-        
+    curCache.SetOffTime(int(time.time()) if isOffline else 0)
+    
     # 装备
     equipDict = {}
     equipPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptEquip)
@@ -369,7 +369,7 @@
     return curCache
 
 def UpdPlayerViewFamilyInfo(playerID, familyID, familyName, emblemID, emblemWord):
-    ## 玩家公会刷新时更新,兼容本服或跨服回传回来更新
+    ## 玩家公会刷新时更新,兼容本服或跨服回传回来更新,跨服自己也更新,本服也更新
     curCache = DBDataMgr.GetPlayerViewCacheMgr().GetPlayerViewCache(playerID)
     if not curCache:
         return
@@ -393,6 +393,7 @@
                     "Face":curPlayer.GetFace(),
                     "FacePic":curPlayer.GetFacePic(),
                     "TitleID":PlayerControl.GetTitleID(curPlayer),
+                    "FamilyID":curPlayer.GetFamilyID(),
                     "ServerID":GameWorld.GetPlayerServerID(curPlayer),
                     "FightPower":PlayerControl.GetFightPower(curPlayer),
                     }
@@ -407,6 +408,7 @@
                         "Face":viewCache.GetFace(),
                         "FacePic":viewCache.GetFacePic(),
                         "TitleID":viewCache.GetTitleID(),
+                        "FamilyID":viewCache.GetFamilyID(),
                         "ServerID":viewCache.GetServerID(),
                         "FightPower":viewCache.GetFightPowerTotal(),
                         }
@@ -425,10 +427,10 @@
     curCache.SetFace(baseInfo.get("Face", curCache.GetFace()))
     curCache.SetFacePic(baseInfo.get("FacePic", curCache.GetFacePic()))
     curCache.SetTitleID(baseInfo.get("TitleID", curCache.GetTitleID()))
+    curCache.SetFamilyID(baseInfo.get("FamilyID", curCache.GetFamilyID()))
     curCache.SetServerID(baseInfo.get("ServerID", curCache.GetServerID()))
     curCache.SetFightPowerTotal(baseInfo.get("FightPower", curCache.GetFightPowerTotal()))
-    if isOffline:
-        curCache.SetOffTime(int(time.time()))
+    curCache.SetOffTime(int(time.time()) if isOffline else 0)
     return curCache
 
 def GetRobotByViewCache(curCache):
@@ -520,30 +522,34 @@
 #{
 #    tagHead        Head;
 #    DWORD        PlayerID;
-#    BYTE        EquipClassLV;    //大于0为查看指定境界阶装备信息,  0为查看默认信息
+#    DWORD        ServerID;        //玩家服务器ID,发0默认本服玩家
 #};
 def OnCMViewPlayerInfo(index, clientPack, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
     
-    findPlayerID = clientPack.PlayerID
-    #equipClassLV = clientPack.EquipClassLV
+    tagPlayerID = clientPack.PlayerID
+    tagServerID = clientPack.ServerID
     
-    clientPack = GetPack_ViewCache(findPlayerID)
-    if clientPack:
-        NetPackCommon.SendFakePack(curPlayer, clientPack)
-        return
-    if GameWorld.GetDBPlayerAccIDByID(findPlayerID):
-        PlayerControl.NotifyCode(curPlayer, "ViewPlayer_OffLine")
+    # 本服或主服是本服
+    if not tagServerID or tagServerID == GameWorld.GetGameWorld().GetServerID():
+        NetPackCommon.SendFakePack(curPlayer, GetPack_ViewCache(tagPlayerID))
         return
     
-    # 跨服玩家发送跨服查询,待扩展...
-    
+    # 直接去目标服务器查询
+    CrossMsg.SendToServer(ShareDefine.S2S_ViewTagPlayer, {"tagPlayerID":tagPlayerID}, [tagServerID], ShareDefine.dirType_All, playerID)
+    return
+
+def S2S_ViewTagPlayer(dataMsg, fromServerID, playerID):
+    tagPlayerID = dataMsg["tagPlayerID"]
+    CrossPlayer.SendFakePackByID(playerID, GetPack_ViewCache(tagPlayerID), fromServerID)
     return
 
 def GetPack_ViewCache(playerID):
     ## 获取同步封包 - 玩家查看缓存
     curCache = FindViewCache(playerID)
     if not curCache:
+        GameWorld.ErrLog("查看玩家找不到目标! playerID=%s" % playerID)
         return
     clientPack = ChPyNetSendPack.tagSCQueryPlayerCacheResult()
     clientPack.PlayerID = curCache.GetPlayerID()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index ee69cbf..41b130d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -1045,6 +1045,7 @@
 C2S_FamilyDataRet = "C2S_FamilyDataRet"                 # 公会首次跨服互通时同步数据结果回复
 C2S_FamilyMapPlayer = "C2S_FamilyMapPlayer"             # 给公会玩家处理地图服务器逻辑
 C2S_FamilyPyPackRet = "C2S_FamilyPyPackRet"             # 公会功能玩家请求包处理结束回包,一般用于重置请求cd等
+C2S_GMDebugAnswer = "C2S_GMDebugAnswer"                 # 发给玩家的DebugAnswer
 C2S_NotifyCode = "C2S_NotifyCode"                       # 给玩家发送信息提示
 C2S_CostPlayerResources = "C2S_CostPlayerResources"     # 扣除玩家资源,货币、物品等
 C2S_GivePlayerResources = "C2S_GivePlayerResources"     # 奖励玩家资源,货币、物品等
@@ -1058,12 +1059,16 @@
 S2C_FamilyPyPack = "S2C_FamilyPyPack"                   # 公会功能玩家请求包
 S2C_GMCMD = "S2C_GMCMD"                                 # GM命令
 
-# 其他
+# 游戏服  -> 任意服务器
+S2S_ViewTagFamily = "S2S_ViewTagFamily"                 # 查看目标公会
+S2S_ViewTagPlayer = "S2S_ViewTagPlayer"                 # 查看目标玩家
+
+# 任意服务器 -> 战斗服务器
 S2B_BattleRequest = "S2B_BattleRequest"                 # 战斗请求
 B2S_BattleResult = "B2S_BattleResult"                   # 战斗结果
 
 # Debug日志不输出通讯数据明细的类型,debug模式下看,一些纯数据类的可不输出通讯数据明细
-NoLogDataSSMsgTypes = [S2B_BattleRequest, B2S_BattleResult, S2C_FamilyData, C2S_SendFakePack]
+NoLogDataSSMsgTypes = [S2B_BattleRequest, B2S_BattleResult, S2C_FamilyData, C2S_SendFakePack, S2C_FamilyPyPack]
 
 # 跨服服务器发送子服信息定义
 CrossServerMsg_CrossServerState = "CrossServerState"    # 跨服服务器状态变更

--
Gitblit v1.8.0