hxp
5 天以前 256fb6df5072850105da4b381f8ce1896c168ac1
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
@@ -20,6 +20,7 @@
import CommFunc
import GameWorld
import ShareDefine
import CheckServerID
import PlayerViewCache
import ChPyNetSendPack
import NetPackCommon
@@ -440,39 +441,6 @@
        self.__actionMgr.ClearFamilyAction(self.GetID())
        return
    
#class FamilyViewBase():
#    ## 公会基础信息,本服跨服通用,一般用于本服公会需要用的基本信息,如查看,方便本服可直接取,由跨服同步
#
#    def __init__(self, familyID):
#        self._familyID = familyID
#        self._family = None
#        self._familyName = ""
#        self._serverID = 0
#        self._emblemID = 0
#        self._emblemWord = ""
#        return
#
#    def SetFamily(self, family): self._family = family
#
#    def GetID(self): return self._familyID
#
#    # 有值以设置的值为准-跨服同步过来的,否则以本服已存在的公会数据为准-即未互通时兼容取本服公会数据
#    def GetName(self): return self._familyName if self._familyName else (self._family.GetName() if self._family else "")
#    def GetServerID(self): return self._serverID if self._serverID else (self._family.GetServerID() if self._family else 0)
#    def GetEmblemID(self): return self._emblemID if self._emblemID else (self._family.GetEmblemID() if self._family else 0)
#    def GetEmblemWord(self): return self._emblemWord if self._emblemWord else (self._family.GetEmblemWord() if self._family else "")
#
#    def GetSyncData(self):
#        return [self.GetName(), self.GetServerID(), self.GetEmblemID(), self.GetEmblemWord()]
#
#    def UpdSyncData(self, syncData):
#        ## 根据跨服同步过来的更新
#        self._familyName = syncData[0] if len(syncData) > 0 else self._familyName
#        self._serverID = syncData[1] if len(syncData) > 1 else self._serverID
#        self._emblemID = syncData[2] if len(syncData) > 2 else self._emblemID
#        self._emblemWord = syncData[3] if len(syncData) > 3 else self._emblemWord
#        return
class ZoneFamilyMgr():
    ## 跨服公会互通分区,本服的也使用,默认分区0
    ## 【注意】跨服分区只是在原公会数据的基础上进行汇总归纳分区,即使分区异常也不要影响公会数据,可重复进行修改配置重新分区
@@ -506,6 +474,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 +513,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
@@ -567,6 +556,14 @@
        elif False:
            family = Family()
        return family
    def FamilyRemainName(self, family, newName):
        if newName in self.__familyNameDict:
            return
        self.__familyNameDict.pop(family.GetName(), None) # 去除旧名
        family.SetName(newName)
        self.__familyNameDict[newName] = family # 设置新名
        return True
    
    def GetCount(self): return len(self.__familyList)
    def GetAt(self, index):
@@ -621,7 +618,6 @@
        
        ## ------------------------ 【游戏服】专有信息,一般由所属互通跨服数据服同步 ----------------------
        # 互通公会基本信息 - 查看玩家页面需要看到的所属公会最简单的信息,一般只有游戏服用到
        #self.__familyViewBaseDict = {} # 公会ID对应基础查看信息 {familyID:FamilyViewBase, ...}
        self.__curZoneServerIDList = [] # 当前游戏服主服所属互通分区实际已经互通的服务器ID列表,同步给前端的
        self.__curCrossServerID = 0 # 当前游戏服主服公会所属跨服ID
        self.__curZoneID = 0 # 当前游戏服主服所属互通分区ID
@@ -805,13 +801,15 @@
        ## 更新分区配置,重置分区,重新分配
        ## @return: 本跨服是否成功更新分区,验证不通过的话不会重置,保留原分区
        GameWorld.Log("跨服公会互通配置更新! updCrossZoneCfgDict=%s" % updCrossZoneCfgDict)
        if not CheckCrossZoneCfg(self.__crossZoneCfgDict, updCrossZoneCfgDict):
        if not CheckFamilyCrossZoneCfg(self.__crossZoneCfgDict, updCrossZoneCfgDict):
            return
        
        crossServerID = GameWorld.GetGameWorld().GetServerID()
        if crossServerID not in updCrossZoneCfgDict:
            GameWorld.Log("本跨服未分配分区的只更新配置即可!")
            self.__crossZoneCfgDict = updCrossZoneCfgDict
            if GameWorld.IsCrossCenter():
                return True
            return
        zoneDict = updCrossZoneCfgDict[crossServerID]
        
@@ -916,17 +914,6 @@
            zoneMgr = ZoneFamilyMgr(zoneID)
            self.__zoneFamilyMgrDict[zoneID] = zoneMgr
        return zoneMgr
#    def GetFamilyViewBase(self, familyID):
#        ## 互通公会基本信息,本服跨服通用,实际的公会完整数据可能不在本服
#        vBase = None
#        if familyID in self.__familyViewBaseDict:
#            vBase = self.__familyViewBaseDict[familyID]
#        else:
#            vBase = FamilyViewBase(familyID)
#            self.__familyViewBaseDict[familyID] = vBase
#        vBase.SetFamily(self.FindFamily(familyID))
#        return vBase
    
    def GetCurCrossServerID(self):
        ## 游戏服获取所属的跨服互通服务器ID,一个游戏服主服只允许一个互通分区,不同分区的不能合服
@@ -1066,15 +1053,17 @@
    GameWorld.Log("跨服公会分区配置加载: appID=%s,%s" % (appID, crossZoneCfgDict))
    return crossZoneCfgDict
def CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
    # 检查待更新的分区配置是否符合规则,不符合的话保留原配置,不更新,待扩展
def CheckFamilyCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
    # 检查待更新的分区配置是否符合规则,不符合的话保留原配置,不更新
    
    if curCrossZoneCfgDict == updCrossZoneCfgDict:
        GameWorld.Log("跨服公会互通分区配置不变不处理")
        return
    
    # 验证配置,是否有交叉、拆分,并邮件通知运维,待扩展,功能完整性优先
    #GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", "noZoneServerIDList=%s" % noZoneServerIDList)
    isOK, errInfo = CheckServerID.CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict)
    if not isOK:
        GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", errInfo)
        return
    
    return True
@@ -1128,11 +1117,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 +1149,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 +1165,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 +1173,12 @@
        if curZoneServerIDList != updZoneServerIDList:
            Sync_FamilyCrossInfo()
            
    # 互通配置
    if "crossZoneCfgDict" in dataMsg:
        # 游戏服不用验证了,直接设置,跨服中心、跟跨服数据服已经验证过了,只要验证互通条件传输数据逻辑即可
        familyMgr.SetCrossZoneCfgDict(dataMsg["crossZoneCfgDict"])
        CheckCrossFamilyTransData(fromServerID)
    return
def IsFamilyCross():
@@ -1223,11 +1189,62 @@
    ## 本服公会首次跨服互通同步数据中
    return DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyTransDataTime) > 0
def CheckMainServerNoFamilyToCross(connServerID):
    '''已经互通的情况下,需要再额外检查本服是否有在目标服务器互通分区里
    有一种情况:游戏加入互通后,该服的所有公会被删除(可能玩家主动删除、可能系统认为需要删除的公会)
    导致该游戏服在跨服服务器没有公会了,且该服没有任何玩家加入任何公会,此时该服务器就无法正常被划入某个分区
    所以已互通的游戏服受到跨服同步的分区信息时,需要检查是否已在分区里,没有的话需要主动汇报请求加入
    '''
    if not IsFamilyCross():
        return
    if not connServerID:
        return
    familyMgr = DBDataMgr.GetFamilyMgr()
    #familyIDList = familyMgr.GetFamilyIDList()
    #if familyIDList:
    #    return
    serverID = GameWorld.GetGameWorld().GetServerID()
    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 != crossServerID:
        GameWorld.Log("本服公会互通非目标跨服ID不处理! serverID=%s,crossServerID=%s != %s" % (serverID, crossServerID, connServerID))
        return
    GameWorld.Log("本服已互通但没有在该跨服互通分区里,直接请求加入! serverID=%s,crossServerID=%s,toZoneID=%s" % (serverID, crossServerID, toZoneID))
    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
    if not DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_CanCross):
        GameWorld.Log("该服务器暂时未开放加入跨服!")
        return
    
    NeedServerDay = IpyGameDataPY.GetFuncCfg("FamilyCross", 1)
@@ -1241,11 +1258,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 +1291,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 +1300,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 +1365,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}