From 5b315b895da27096b2b1d58c4d9b6ece5440c770 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 10 二月 2026 17:39:22 +0800
Subject: [PATCH] 66 【公会】基础主体-服务端(修复无公会的游戏服互通异常bug;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py |  181 ++++++++++++++++++++++++++++++++------------
 1 files changed, 131 insertions(+), 50 deletions(-)

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 de1ac31..0140257 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
@@ -230,7 +230,7 @@
         self.__dbData.FightPower = fightPowerTotal % ChConfig.Def_PerPointValue
         self.__dbData.FightPowerEx = fightPowerTotal / ChConfig.Def_PerPointValue
         return
-    def GetServerID(self): return self.__dbData.ServerID
+    def GetServerID(self): return int(self.__dbData.ServerID)
     def SetServerID(self, serverID): self.__dbData.ServerID = serverID
     def GetOffTime(self): return self.__dbData.OffTime
     def SetOffTime(self, offTime): self.__dbData.OffTime = offTime
@@ -287,7 +287,7 @@
     
     def GetID(self): return self.__dbData.ID
     def GetCreateTime(self): return self.__dbData.CreateTime
-    def GetServerID(self): return self.__dbData.ServerID
+    def GetServerID(self): return int(self.__dbData.ServerID)
     def GetName(self): return self.__dbData.Name
     def SetName(self, name): self.__dbData.Name = name
     def GetLeaderID(self): return self.__dbData.LeaderID
@@ -506,6 +506,17 @@
         self.__needSort = False
         return
     
+    def AddServerIDToZone(self, serverID):
+        '''直接将某个区服加入该分区,一般用于自身没有公会的游戏服
+        比较特殊的情况:当某个游戏服自身没有公会时,在加入互通后,当还没有玩家加入某个其他服公会时,会导致找不到该服的所属分区
+        所以游戏服在互通分区更新时在本服没有公会时需要额外同步跨服告知加入互通,否则会导致该服玩家无法正常加入公会互通
+        @return: True - 成功新加入;  False - 已经加入了
+        '''
+        if serverID not in self.__zoneServerIDList:
+            self.__zoneServerIDList.append(serverID)
+            return True
+        return False
+    
     def AddFamilyToZone(self, family):
         ## 将某个公会分配给该分区
         if not family:
@@ -534,7 +545,17 @@
             
         if familyServerID not in self.__zoneServerIDList:
             self.__zoneServerIDList.append(familyServerID)
-            
+        # 成员也需要检查,防止没有公会的游戏服玩家无法正确划入某个分区
+        for index in range(family.GetCount()):
+            member = family.GetAt(index)
+            memID = member.GetPlayerID()
+            memServerID = member.GetServerID()
+            if memID < ShareDefine.RealPlayerIDStart:
+                #GameWorld.DebugLog("非真人的成员不计入! memID=%s,memServerID=%s" % (memID, memServerID))
+                continue
+            if memServerID not in self.__zoneServerIDList:
+                self.__zoneServerIDList.append(memServerID)
+                
         self.__needSort = True
         self.__familyMgr.OnAddToZone(family, self.__zoneID)
         return
@@ -1128,11 +1149,11 @@
     Sync_CrossToServer_FamilyInfo()
     return
 
-def Sync_CrossToServer_FamilyInfo(toServerID=0, syncZoneID=0, syncFamilyIDList=[]):
+def Sync_CrossToServer_FamilyInfo(toServerID=0, syncZoneID=0, withCfg=True):
     ## 跨服服务器同步互通公会信息给游戏服
     # @param toServerID: 有指定游戏服连上时只发给该服,没有的话一般是分区配置变更时由跨服主动同步所有相关游戏服
     
-    GameWorld.DebugLog("Sync_CrossToServer_FamilyInfo toServerID=%s,syncZoneID=%s,syncFamilyIDList=%s" % (toServerID, syncZoneID, syncFamilyIDList))
+    GameWorld.DebugLog("Sync_CrossToServer_FamilyInfo toServerID=%s,syncZoneID=%s,withCfg=%s" % (toServerID, syncZoneID, withCfg))
     familyMgr = DBDataMgr.GetFamilyMgr()
     crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict() # 配置的互通
     if not crossZoneCfgDict:
@@ -1160,27 +1181,11 @@
             toServerIDList = cfgServerIDList
             
         zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
-        zoneServerIDList = zoneMgr.GetZoneServerIDList()
+        zoneServerIDList = zoneMgr.GetZoneServerIDList() # 实际已经互通的区服ID列表
         
-#        viewBaseDict = {}
-#        for index in range(zoneMgr.GetCount()):
-#            family = zoneMgr.GetAt(index)
-#            familyID = family.GetID()
-#            if syncFamilyIDList and familyID not in syncFamilyIDList:
-#                continue
-#            viewBase = familyMgr.GetFamilyViewBase(familyID)
-#            viewBaseDict[familyID] = viewBase.GetSyncData()
-            
-        # 只通知给已经互通的相关服务器即可
-        # 关于查看玩家
-        # 1. 查看玩家直接到玩家所在服务器查询即可,查看玩家需要公会的一些基本信息,如 公会名、徽章、旗帜、互通跨服ID 等
-        # 2. 玩家/查看玩家信息只需记录所属公会ID即可,公会相关基础信息通过 FamilyViewBase 获取,由互通所在跨服同步过来
-        
-        # 关于查看公会
-        # 1. 从查看玩家中查看公会,发送公会ID、所属互通跨服ID,直接去目标服务器查询即可
-        # 2. 从跨服活动中查看公会,活动相关公会记录所属互通跨服ID,同样直接去目标服务器查询即可
-        
-        dataMsg = {"crossZoneCfgDict":crossZoneCfgDict, "zoneID":zoneID, "zoneServerIDList":zoneServerIDList}
+        dataMsg = {"zoneID":zoneID, "zoneServerIDList":zoneServerIDList}
+        if withCfg:
+            dataMsg["crossZoneCfgDict"] = crossZoneCfgDict
         CrossMsg.SendToClientServer(ShareDefine.C2S_FamilyCrossInfo, dataMsg, toServerIDList)
         
     return
@@ -1192,19 +1197,6 @@
     familyMgr.SetCurCrossServerID(fromServerID) # 直接设置,哪个服同步过来的就是所属跨服ID
     familyMgr.SetCurZoneID(dataMsg["zoneID"])
     
-#    ## 本服更新跨服互通公会的基本信息
-#    if "viewBaseDict" in dataMsg:
-#        viewBaseDict = dataMsg["viewBaseDict"]
-#        for familyID, syncData in viewBaseDict.items():
-#            viewBase = familyMgr.GetFamilyViewBase(familyID)
-#            viewBase.UpdSyncData(syncData)
-            
-    # 互通配置
-    if "crossZoneCfgDict" in dataMsg:
-        # 游戏服不用验证了,直接设置,跨服中心、跟跨服数据服已经验证过了,只要验证互通条件传输数据逻辑即可
-        familyMgr.SetCrossZoneCfgDict(dataMsg["crossZoneCfgDict"])
-        CheckCrossFamilyTransData(fromServerID)
-        
     # 实际已互通分区
     if "zoneServerIDList" in dataMsg:
         curZoneServerIDList = familyMgr.GetCurZoneServerIDList()
@@ -1213,6 +1205,12 @@
         if curZoneServerIDList != updZoneServerIDList:
             Sync_FamilyCrossInfo()
             
+    # 互通配置
+    if "crossZoneCfgDict" in dataMsg:
+        # 游戏服不用验证了,直接设置,跨服中心、跟跨服数据服已经验证过了,只要验证互通条件传输数据逻辑即可
+        familyMgr.SetCrossZoneCfgDict(dataMsg["crossZoneCfgDict"])
+        CheckCrossFamilyTransData(fromServerID)
+        
     return
 
 def IsFamilyCross():
@@ -1223,11 +1221,61 @@
     ## 本服公会首次跨服互通同步数据中
     return DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyTransDataTime) > 0
 
+def CheckMainServerNoFamilyToCross(connServerID=0):
+    '''已经互通的情况下,需要再额外检查本服是否有公会
+    没有公会时需要主动告知跨服检查是否成功加入互通分区,否则本服将无法正常进行公会互通
+    '''
+    if not IsFamilyCross():
+        return
+    familyMgr = DBDataMgr.GetFamilyMgr()
+    familyIDList = familyMgr.GetFamilyIDList()
+    if familyIDList:
+        return
+    
+    serverID = GameWorld.GetGameWorld().GetServerID()
+    GameWorld.Log("本服无公会需直接同步跨服请求检查加入互通分区! serverID=%s" % (serverID))
+    
+    curZoneServerIDList = familyMgr.GetCurZoneServerIDList()
+    if serverID in curZoneServerIDList:
+        GameWorld.Log("已经在互通分区里了不处理! serverID=%s in %s" % (serverID, curZoneServerIDList))
+        return
+    
+    crossServerID = 0
+    toZoneID = 0
+    crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict()
+    for cID, zoneDict in crossZoneCfgDict.items():
+        for zoneID, serverIDRangeList in zoneDict.items():
+            if GameWorld.CheckServerIDInList(serverID, serverIDRangeList):
+                crossServerID = cID
+                toZoneID = zoneID
+                GameWorld.Log("本服公会所属跨服ID! serverID=%s,crossServerID=%s,zoneID=%s,serverIDRangeList=%s" % (serverID, crossServerID, zoneID, serverIDRangeList))
+                break
+        if crossServerID:
+            break
+    if not crossServerID:
+        GameWorld.Log("本服公会未分配互通分区! serverID=%s" % (serverID))
+        return
+    
+    if connServerID:
+        if connServerID != crossServerID:
+            GameWorld.Log("本服公会互通非目标跨服ID不处理! serverID=%s,crossServerID=%s != %s" % (serverID, crossServerID, connServerID))
+            return
+    else:
+        ssServer = CrossMgr.GetSSServerMgr().GetSSServer(crossServerID)
+        connState = ssServer.GetConnState()
+        if connState != ShareDefine.ssConn_Normal:
+            GameWorld.Log("本服公会互通目标跨服ID非连接状态! serverID=%s,crossServerID=%s,connState=%s" % (serverID, crossServerID, connState))
+            return
+        
+    CrossMsg.SendToCrossServer(ShareDefine.S2C_FamilyData, {"checkInZone":1, "toZoneID":toZoneID}, [crossServerID])
+    return
+
 def CheckCrossFamilyTransData(connServerID=0, ignoreCD=False):
     ## 检查跨服公会传输数据,服务器启动时、onday时检查,或GM等指定强制调用
     
     if IsFamilyCross():
         GameWorld.DebugLog("本服公会已经跨服了!")
+        CheckMainServerNoFamilyToCross(connServerID)
         return
     
     NeedServerDay = IpyGameDataPY.GetFuncCfg("FamilyCross", 1)
@@ -1241,11 +1289,13 @@
     crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict()
     
     crossServerID = 0
+    toZoneID = 0
     serverID = GameWorld.GetGameWorld().GetServerID()
     for cID, zoneDict in crossZoneCfgDict.items():
         for zoneID, serverIDRangeList in zoneDict.items():
             if GameWorld.CheckServerIDInList(serverID, serverIDRangeList):
                 crossServerID = cID
+                toZoneID = zoneID
                 GameWorld.Log("本服公会所属跨服ID! serverID=%s,crossServerID=%s,zoneID=%s,serverIDRangeList=%s" % (serverID, crossServerID, zoneID, serverIDRangeList))
                 break
         if crossServerID:
@@ -1272,7 +1322,7 @@
             GameWorld.Log("本服公会互通传输数据中! serverID=%s,crossServerID=%s,transDataTime=%s" % (serverID, crossServerID, GameWorld.ChangeTimeNumToStr(transDataTime)))
             return
         
-    GameWorld.Log("本服公会开启互通开始传输公会相关数据! serverID=%s,crossServerID=%s" % (serverID, crossServerID))
+    GameWorld.Log("本服公会开启互通开始传输公会相关数据! serverID=%s,crossServerID=%s,toZoneID=%s" % (serverID, crossServerID, toZoneID))
     DBDataMgr.GetEventTrigMgr().SetValue(ShareDefine.Def_FamilyTransDataTime, int(time.time()))
     
     cntDict = {}
@@ -1281,35 +1331,49 @@
     familyIDList = familyMgr.GetFamilyIDList()
     
     GameWorld.Log("dataslen=%s" % len(syncData))
-    CrossMsg.SendToCrossServer(ShareDefine.S2C_FamilyData, {"syncData":syncData, "familyIDList":familyIDList, "cntDict":cntDict}, [crossServerID])
+    CrossMsg.SendToCrossServer(ShareDefine.S2C_FamilyData, {"syncData":syncData, "familyIDList":familyIDList, "cntDict":cntDict, "toZoneID":toZoneID}, [crossServerID])
     return
 
 def S2C_FamilyData(dataMsg, fromServerID):
+    if "checkInZone" in dataMsg:
+        toZoneID = dataMsg["toZoneID"]
+        __doCheckServerInZone(fromServerID, toZoneID)
+        return
     syncData = dataMsg["syncData"]
     familyIDList = dataMsg["familyIDList"]
     cntDict = dataMsg["cntDict"]
-    GameWorld.Log("收到游戏服同步的互通公会数据! fromServerID=%s,cntDict=%s,familyIDList=%s" % (fromServerID, cntDict, familyIDList))
+    toZoneID = dataMsg["toZoneID"]
+    GameWorld.Log("收到游戏服同步的互通公会数据! fromServerID=%s,toZoneID=%s,cntDict=%s,familyIDList=%s" % (fromServerID, toZoneID, cntDict, familyIDList))
     
-    unpackRet = __unpackFamilyData(syncData, familyIDList, cntDict)
-    isOK = unpackRet[0]
-    if not isOK:
-        errorMsg = unpackRet[1]
-        GameWorld.SendGameErrorEx("S2C_FamilyDataError", "互通公会数据同步失败! fromServerID=%s,errorMsg=%s" % (fromServerID, errorMsg))
+    if not familyIDList:
+        GameWorld.Log("该服没有公会,直接加入互通范围! fromServerID=%s,toZoneID=%s" % (fromServerID, toZoneID))
+        familyMgr = DBDataMgr.GetFamilyMgr()
+        zoneID = familyMgr.GetZoneIDInThisServer(fromServerID)
+        familyDataList, memberDataList, actionDataList = [], [], []
+    else:
+        unpackRet = __unpackFamilyData(syncData, familyIDList, cntDict)
+        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
+        zoneID, familyDataList, memberDataList, actionDataList = unpackRet[1:]
+        
+    if toZoneID != zoneID:
+        GameWorld.SendGameErrorEx("S2C_FamilyDataError", "加入的互通分区不一致! fromServerID=%s,toZoneID=%s != %s" % (fromServerID, toZoneID, zoneID))
         CrossMsg.SendToClientServer(ShareDefine.C2S_FamilyDataRet, {"isOK":False}, [fromServerID])
         return
-    zoneID, familyDataList, memberDataList, actionDataList = unpackRet[1:]
     
     # 插入新数据,重名的会在加入分区后自动改名
     familyMgr = DBDataMgr.GetFamilyMgr()
     zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
     actionMgr = familyMgr.GetFamilyActionMgr()
     
-    syncFamilyIDList = []
     for dbData in familyDataList:
         familyID = dbData.ID
         familyMgr.DelFamily(familyID, False) # 每次都强制先删除,支持重复同步
         zoneMgr.AddFamilyToZone(familyMgr.InitFamilyInstance(dbData))
-        syncFamilyIDList.append(familyID)
         
     # 成员
     for dbData in memberDataList:
@@ -1332,13 +1396,30 @@
         action = actionMgr.GetFamilyAction(familyID, actionType)
         action.InitActionInstance(dbData)
         
+    zoneMgr.AddServerIDToZone(fromServerID) # 再补设置一次,确保没有公会时也能正常加入互通分区
+    
     # 同步给相同互通分区的服务器
-    Sync_CrossToServer_FamilyInfo(syncZoneID=zoneID, syncFamilyIDList=syncFamilyIDList)
+    Sync_CrossToServer_FamilyInfo(syncZoneID=zoneID)
     
     # 最后回复同步结果
     CrossMsg.SendToClientServer(ShareDefine.C2S_FamilyDataRet, {"isOK":True}, [fromServerID])
     return
 
+def __doCheckServerInZone(fromServerID, toZoneID):
+    GameWorld.Log("检查游戏服是否已经成功加入互通分区! fromServerID=%s,toZoneID=%s" % (fromServerID, toZoneID))
+    familyMgr = DBDataMgr.GetFamilyMgr()
+    zoneID = familyMgr.GetZoneIDInThisServer(fromServerID)
+    if toZoneID != zoneID:
+        GameWorld.SendGameErrorEx("CheckServerInZoneError", "检查的互通分区不一致! fromServerID=%s,toZoneID=%s != %s" % (fromServerID, toZoneID, zoneID))
+        return
+    zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
+    if not zoneMgr.AddServerIDToZone(fromServerID):
+        GameWorld.Log("已经在该互通分区里了不处理! fromServerID=%s,toZoneID=%s" % (fromServerID, toZoneID))
+        return
+    GameWorld.Log("检查且成功加入公会互通分区! fromServerID=%s,toZoneID=%s" % (fromServerID, toZoneID))
+    Sync_CrossToServer_FamilyInfo(syncZoneID=zoneID, withCfg=False) # 需传False,防止一直重复检查
+    return
+
 def __unpackFamilyData(syncData, familyIDList, cntDict):
     ## 解包,验证数据
     # @param cntDict: {"familyDataCnt":familyDataCnt, "membreDataCnt":membreDataCnt, "actionDataCnt":actionDataCnt}

--
Gitblit v1.8.0