| | |
| | | #"""Version = 2025-05-09 12:20"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import ChPlayer
|
| | | import DBStruct
|
| | | import CommFunc
|
| | | import GameWorld
|
| | | import ShareDefine
|
| | | import PlayerControl
|
| | | import PlayerViewCache
|
| | | import ChPyNetSendPack
|
| | | import NetPackCommon
|
| | | import IpyGameDataPY
|
| | | import PyMongoMain
|
| | | import DBDataMgr
|
| | | import CrossMgr
|
| | | import CrossMsg
|
| | | import ChConfig
|
| | | import DBComm
|
| | |
|
| | | import time
|
| | |
|
| | | FamilyUpperLimitCount = 2000
|
| | | #FamilyUpperLimitCount = 2000
|
| | |
|
| | | class FamilyActionData():
|
| | |
|
| | |
| | |
|
| | | class FamilyMem():
|
| | |
|
| | | def __init__(self, dbData=None):
|
| | | def __init__(self, dbData=None, family=None):
|
| | | self.__dbData = DBStruct.tagDBFamilyMem() if not dbData else dbData
|
| | | self.__family = family
|
| | | return
|
| | |
|
| | | def GetFamily(self): return DBDataMgr.GetFamilyMgr().FindFamily(self.__dbData.FamilyID)
|
| | | def GetFamily(self):
|
| | | if not self.__family:
|
| | | self.__family = DBDataMgr.GetFamilyMgr().FindFamily(self.__dbData.FamilyID)
|
| | | return self.__family
|
| | | def GetPlayerID(self): return self.__dbData.PlayerID
|
| | | def GetFamilyID(self): return self.__dbData.FamilyID
|
| | | def GetJoinTime(self): return self.__dbData.JoinTime
|
| | |
| | | def GetBuffer(self): return self.__dbData.getBuffer()
|
| | |
|
| | | def RefreshMemberByID(self, playerID):
|
| | | ## 根据玩家ID更新成员数据,一般用于离线功能,如添加离线成员,直接使用查看缓存更新
|
| | | '''刷新成员信息,仙盟成员属于永久功能数据,除非仙盟解散,所以单独存一份成员基础信息,支持离线玩家,直接使用查看缓存更新
|
| | | @return: 战力是否变更
|
| | | '''
|
| | | if playerID != self.GetPlayerID():
|
| | | return
|
| | | viewCache = PlayerViewCache.FindViewCache(playerID)
|
| | |
| | | self.SetServerID(viewCache.GetServerID())
|
| | | fpChange = False
|
| | | fightPowerTotal = viewCache.GetFightPowerTotal()
|
| | | if self.GetFightPowerTotal() < fightPowerTotal:
|
| | | if self.GetFightPowerTotal() != fightPowerTotal:
|
| | | self.SetFightPowerTotal(fightPowerTotal)
|
| | | fpChange = True
|
| | | family = self.GetFamily()
|
| | | if family:
|
| | | family.SetMemFightPowerChange()
|
| | | return fpChange
|
| | | |
| | | def RefreshMember(self, curPlayer):
|
| | | '''刷新成员信息,仙盟成员属于永久功能数据,除非仙盟解散,所以单独存一份成员基础信息,防止过度依赖查看缓存数据引发的问题
|
| | | @return: 战力是否变更
|
| | | '''
|
| | | if not curPlayer or curPlayer.GetPlayerID() != self.GetPlayerID():
|
| | | return
|
| | | self.SetPlayerName(curPlayer.GetPlayerName())
|
| | | self.SetLV(curPlayer.GetLV())
|
| | | self.SetJob(curPlayer.GetJob())
|
| | | self.SetRealmLV(curPlayer.GetOfficialRank())
|
| | | self.SetFace(curPlayer.GetFace())
|
| | | self.SetFacePic(curPlayer.GetFacePic())
|
| | | self.SetTitleID(PlayerControl.GetTitleID(curPlayer))
|
| | | self.SetServerID(GameWorld.GetPlayerServerID(curPlayer))
|
| | | fightPowerTotal = PlayerControl.GetFightPower(curPlayer)
|
| | | fpChange = self.GetFightPowerTotal() != fightPowerTotal
|
| | | self.SetFightPowerTotal(fightPowerTotal)
|
| | | if fpChange:
|
| | | family = self.GetFamily()
|
| | | if family:
|
| | | family.SetMemFightPowerChange()
|
| | | family.RefrshFightPowerTotal()
|
| | | return fpChange
|
| | |
|
| | | class Family():
|
| | |
| | | self.__memberDict = {} # 成员字典 {playerID:FamilyMem, ...}
|
| | | self.__familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | self.__actionMgr = DBDataMgr.GetFamilyActionMgr()
|
| | | self.__memFightPowerChange = None # 成员战力是否有变化,默认None,代表未处理过
|
| | | return
|
| | |
|
| | | def GetID(self): return self.__dbData.ID
|
| | |
| | | return
|
| | | def GetFightPower(self): return self.__dbData.FightPower
|
| | | def GetFightPowerEx(self): return self.__dbData.FightPowerEx
|
| | | def GetFightPowerTotal(self): return self.__dbData.FightPowerEx * ChConfig.Def_PerPointValue + self.__dbData.FightPower
|
| | | def GetFightPowerTotal(self):
|
| | | return self.__dbData.FightPowerEx * ChConfig.Def_PerPointValue + self.__dbData.FightPower
|
| | | def SetFightPowerTotal(self, fightPowerTotal):
|
| | | fpBef = self.GetFightPowerTotal()
|
| | | self.__dbData.FightPower = fightPowerTotal % ChConfig.Def_PerPointValue
|
| | | self.__dbData.FightPowerEx = fightPowerTotal / ChConfig.Def_PerPointValue
|
| | | fpAft = self.GetFightPowerTotal()
|
| | | if fpBef != fpAft:
|
| | | self.__familyMgr.OnFightPowerChange(self)
|
| | | return
|
| | | def GetEmblemID(self): return self.__dbData.EmblemID
|
| | | def SetEmblemID(self, emblemID): self.__dbData.EmblemID = emblemID
|
| | | def GetEmblemWord(self): return self.__dbData.EmblemWord
|
| | | def SetEmblemWord(self, emblemWord): self.__dbData.EmblemWord = emblemWord
|
| | | def GetExtra1(self): return self.__dbData.Extra1
|
| | | def SetExtra1(self, extra1): self.__dbData.Extra1 = extra1
|
| | | def GetExtra2(self): return self.__dbData.Extra2
|
| | | def SetExtra2(self, extra2): self.__dbData.Extra2 = extra2
|
| | | def GetExtra3(self): return self.__dbData.Extra3
|
| | | def SetExtra3(self, extra3): self.__dbData.Extra3 = extra3
|
| | | def GetExtra4(self): return self.__dbData.Extra4
|
| | | def SetExtra4(self, extra4): self.__dbData.Extra4 = extra4
|
| | | def GetExtra5(self): return self.__dbData.Extra5
|
| | | def SetExtra5(self, extra5): self.__dbData.Extra5 = extra5
|
| | | def GetBuffer(self): return self.__dbData.getBuffer()
|
| | | |
| | | |
| | | ## ------------------------------------------------
|
| | | def InitMemberInstance(self, dbData):
|
| | | '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
|
| | | @param dbData: 实例对应绑定的dbData
|
| | | @return: 成功返回实例对象,失败返回None
|
| | | '''
|
| | | member = FamilyMem(dbData)
|
| | | member = FamilyMem(dbData, self)
|
| | | playerID = member.GetPlayerID()
|
| | | if playerID in self.__memberDict:
|
| | | return
|
| | |
| | | member = self.InitMemberInstance(dbData)
|
| | | if not member and False:
|
| | | member = FamilyMem()
|
| | | self.__memFightPowerChange = True
|
| | | self.RefrshFightPowerTotal()
|
| | | self.__familyMgr.OnAddMember(self, playerID)
|
| | | return member
|
| | |
|
| | | def DeleteMember(self, playerID):
|
| | | delMem = self.__memberDict.pop(playerID, None)
|
| | | if delMem in self.__memberList:
|
| | | self.__memberList.remove(delMem)
|
| | | self.__memFightPowerChange = True
|
| | | self.RefrshFightPowerTotal()
|
| | | self.__familyMgr.OnDelMember(self, playerID)
|
| | | return delMem
|
| | |
|
| | | def FindMember(self, playerID):
|
| | |
| | | mem = FamilyMem()
|
| | | return mem
|
| | |
|
| | | def SetMemFightPowerChange(self): self.__memFightPowerChange = True
|
| | | def RefrshFightPowerTotal(self, checkChange=False):
|
| | | def RefrshFightPowerTotal(self):
|
| | | ## 刷新总战力
|
| | | if checkChange and self.__memFightPowerChange == False: # 默认None,首次必刷新
|
| | | #GameWorld.DebugLog("没有成员战力变化可不刷新仙盟总战力! familyID=%s" % self.GetID())
|
| | | return
|
| | | familyFightPowerTotal = 0
|
| | | for index in range(self.GetCount()):
|
| | | member = self.GetAt(index)
|
| | |
| | | continue
|
| | | familyFightPowerTotal += member.GetFightPowerTotal()
|
| | | self.SetFightPowerTotal(familyFightPowerTotal)
|
| | | #GameWorld.DebugLog("刷新仙盟总战力! familyID=%s" % self.GetID())
|
| | | self.__memFightPowerChange = False
|
| | | return familyFightPowerTotal
|
| | |
|
| | | def GetReqJoinPlayerInfo(self):
|
| | |
| | | return
|
| | |
|
| | | def OnDelete(self):
|
| | | for memID in self.__memberDict.keys():
|
| | | self.DeleteMember(memID)
|
| | | self.DelReqJoinPlayerAll()
|
| | | self.__actionMgr.ClearFamilyAction(self.GetID())
|
| | | return
|
| | |
|
| | | class FamilyMgr():
|
| | | #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
|
| | |
|
| | | def __init__(self):
|
| | | self.__familyList = [] # 仙盟对象列表,可进行排序 [Family, ...]
|
| | | self.__familyIDDict = {} # 仙盟ID对象字典, {familyID:Family, ...}
|
| | | self.__familyNameDict = {} # 仙盟名称对象字典, {familyName:Family, ...}
|
| | | self.__actionMgr = FamilyActionMgr()
|
| | | self.__playerReqJoinDict = None # 玩家申请加入仙盟列表 {playerID:[familyID, ...], ...}
|
| | | class ZoneFamilyMgr():
|
| | | ## 跨服公会互通分区,本服的也使用,默认分区0
|
| | | ## 【注意】跨服分区只是在原公会数据的基础上进行汇总归纳分区,即使分区异常也不要影响公会数据,可重复进行修改配置重新分区
|
| | | |
| | | def __init__(self, zoneID=0):
|
| | | self.__familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | self.__zoneID = zoneID # 本服默认分区0,即未互通的服务器
|
| | | self.__familyList = [] # 公会对象列表,可进行排序 [Family, ...]
|
| | | self.__familyIDDict = {} # 公会ID对象字典, {familyID:Family, ...}
|
| | | self.__familyNameDict = {} # 公会名称对象字典, {familyName:Family, ...}
|
| | | self.__zoneServerIDList = [] # 本分区实际已经互通的公会服务器ID列表 [serverID, ...]
|
| | | self.__familyIDRankDict = {} # 公会名次字典 {familyID:rank, ...}
|
| | | self.__needSort = True
|
| | | |
| | | ## 注意!注意!注意!暂时只存分区的公会列表管理,其他分区相关的缓存数据暂不要放这里
|
| | | ## 因为分区配置重读变更后会被重置可能导致丢失,如需要存储其他数据再另行处理
|
| | | return
|
| | |
|
| | | def InitFamilyInstance(self, dbData):
|
| | | '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
|
| | | @param dbData: 实例对应绑定的dbData
|
| | | @return: 成功返回实例对象,失败返回None
|
| | | def GetZoneID(self): return self.__zoneID
|
| | | |
| | | def SetSort(self): self.__needSort = True # 设置需要排序
|
| | | |
| | | def Sort(self, checkSort=False):
|
| | | ''' 默认排序倒序,按 仙盟总战力 -> 仙盟等级
|
| | | @param checkSort: 是否检查需要排序,如果需要排序才会排序,设置True时则强制排序不检查
|
| | | '''
|
| | | family = Family(dbData)
|
| | | if checkSort and not self.__needSort:
|
| | | return
|
| | | self.__familyList.sort(key=lambda f: (f.GetFightPowerTotal(), f.GetLV()), reverse=True)
|
| | | self.__familyIDRankDict = {}
|
| | | self.__needSort = False
|
| | | return
|
| | | |
| | | def AddFamilyToZone(self, family):
|
| | | ## 将某个公会分配给该分区
|
| | | if not family:
|
| | | return
|
| | | familyID = family.GetID()
|
| | | if familyID in self.__familyIDDict:
|
| | | return
|
| | | self.__familyList.append(family)
|
| | | self.__familyIDDict[familyID] = family
|
| | | self.__familyNameDict[family.GetName()] = family
|
| | | return family
|
| | | |
| | | def Sort(self):
|
| | | ''' 默认排序倒序,按 仙盟总战力 -> 仙盟等级
|
| | | '''
|
| | | self.__familyList.sort(key=lambda f: (f.GetFightPowerTotal(), f.GetLV()), reverse=True)
|
| | | |
| | | familyServerID = family.GetServerID()
|
| | | familyName = family.GetName()
|
| | | # 规定相同分区名字唯一,如重名,强制修改为唯一的;合服数据合并、首次互通传数据等均支持自动改名
|
| | | if familyName in self.__familyNameDict:
|
| | | for doCnt in range(1, 1000):
|
| | | fixName = "%s%s" % (familyName, doCnt) # 强制加个编号
|
| | | if fixName not in self.__familyNameDict:
|
| | | familyName = fixName
|
| | | break
|
| | | self.__familyNameDict[familyName] = family
|
| | | |
| | | if family not in self.__familyList:
|
| | | self.__familyList.append(family)
|
| | | self.__familyIDRankDict = {} # 新公会加入时重置
|
| | | |
| | | if familyServerID not in self.__zoneServerIDList:
|
| | | self.__zoneServerIDList.append(familyServerID)
|
| | | |
| | | self.__needSort = True
|
| | | self.__familyMgr.OnAddToZone(family, self.__zoneID)
|
| | | return
|
| | |
|
| | | def AddFamily(self, familyName, serverID, familyID=None):
|
| | | ## 创建新仙盟
|
| | | newFamily = None
|
| | | if familyID == None:
|
| | | familyID = PyMongoMain.GetUserCtrlDB().GetNewFamilyID()
|
| | | if familyID <= 0:
|
| | | GameWorld.ErrLog("创建仙盟时生成新ID异常!")
|
| | | return newFamily
|
| | | if familyID in self.__familyIDDict:
|
| | | GameWorld.ErrLog("创建仙盟时ID已存在! familyID=%s" % familyID)
|
| | | return newFamily
|
| | | if familyName in self.__familyNameDict:
|
| | | GameWorld.ErrLog("创建仙盟时名称已存在! familyName=%s" % familyName)
|
| | | return newFamily
|
| | | if len(self.__familyList) >= FamilyUpperLimitCount:
|
| | | GameWorld.ErrLog("单服限制创建仙盟数已达上限!")
|
| | | return newFamily
|
| | | |
| | | dbData = DBStruct.tagDBFamily()
|
| | | dbData.ID = familyID
|
| | | dbData.Name = familyName
|
| | | dbData.ServerID = serverID
|
| | | dbData.CreateTime = int(time.time())
|
| | | |
| | | newFamily = self.InitFamilyInstance(dbData)
|
| | | if not newFamily and False: # 不执行,为了代码提示
|
| | | newFamily = Family()
|
| | | return newFamily
|
| | | def DelZoneFamily(self, familyID):
|
| | | family = self.__familyIDDict.pop(familyID, None)
|
| | | if not family:
|
| | | return
|
| | | if family in self.__familyList:
|
| | | self.__familyList.remove(family)
|
| | | self.__familyNameDict.pop(family.GetName(), None)
|
| | | self.__familyIDRankDict.pop(familyID, None)
|
| | | self.__needSort = True
|
| | | return
|
| | | |
| | | def GetZoneServerIDList(self): return self.__zoneServerIDList
|
| | |
|
| | | def FindFamily(self, familyID):
|
| | | family = None
|
| | |
| | | family = Family()
|
| | | return family
|
| | |
|
| | | def DelFamily(self, familyID):
|
| | | family = self.FindFamily(familyID)
|
| | | if family:
|
| | | self.__familyNameDict.pop(family.GetName(), None)
|
| | | if family in self.__familyList:
|
| | | self.__familyList.remove(family)
|
| | | family.OnDelete()
|
| | | self.__familyIDDict.pop(familyID, None)
|
| | | if familyID >= ShareDefine.RealFamilyIDStart:
|
| | | PyMongoMain.GetUserCtrlDB().FreeFamilyID(familyID) # 归还仙盟ID,重复使用
|
| | | return family
|
| | | |
| | | def DelAllFamily(self):
|
| | | for index in range(self.GetCount())[::-1]:
|
| | | family = self.GetAt(index)
|
| | | familyID = family.GetID()
|
| | | self.DelFamily(familyID)
|
| | | return
|
| | | |
| | | def GetCount(self): return len(self.__familyList)
|
| | | def GetAt(self, index):
|
| | | family = None
|
| | |
| | | family = Family()
|
| | | return family
|
| | |
|
| | | def GetPlayerFamilyID(self, playerID):
|
| | | ## 获取玩家当前所属的仙盟ID
|
| | | for index in range(self.GetCount()):
|
| | | family = self.GetAt(index)
|
| | | if family.FindMember(playerID):
|
| | | return family.GetID()
|
| | | return 0
|
| | | def GetFamilyRank(self, familyID):
|
| | | ## 获取公会ID所在排名
|
| | | # @return: 0-未上榜; >0-名次
|
| | | if not familyID:
|
| | | return 0
|
| | | if not self.__familyIDRankDict:
|
| | | self.__familyIDRankDict = {}
|
| | | for rank, family in enumerate(self.__familyList, 1):
|
| | | self.__familyIDRankDict[family.GetID()] = rank
|
| | | if familyID not in self.__familyIDRankDict:
|
| | | return 0
|
| | | return self.__familyIDRankDict[familyID]
|
| | | |
| | | class FamilyMgr():
|
| | | ''' 所有分区的公会总管理,本服、跨服通用,zoneID为0时默认是本服的非跨服互通公会
|
| | | '''
|
| | | |
| | | def __init__(self):
|
| | | |
| | | ## ----------------------- 公会数据服务器的信息,如【未互通游戏服】 或 【跨服】 ------------------------
|
| | | # 本服务器数据,可能是游戏服本服 或 跨服互通数据
|
| | | self.__familyIDDict = {} # 公会ID对象字典, {familyID:Family, ...}
|
| | | self.__playerFamilyIDDict = {} # 玩家所属公会ID字典 {playerID:familyID, ...}
|
| | | self.__playerReqJoinDict = {} # 玩家申请加入仙盟列表 {playerID:[familyID, ...], ...}
|
| | | self.__actionMgr = FamilyActionMgr()
|
| | | |
| | | # 本服数据分区管理,游戏服尚未未分区的默认使用分区0,因为只管理本服公会数据,故不用再按crossServerID区分,默认都属于本服的serverID
|
| | | # 分区可能随时被重置重新分配,故如有需要持久化的逻辑数据需要另行处理,或在重置后复制所需持久化的数据,暂时不用,之后有需要再处理
|
| | | self.__zoneFamilyMgrDict = {} # 分区对应公会分区管理器 {zoneID:ZoneFamilyMgr(), ...}
|
| | | self.__familyIDZoneIDDict = {} # 公会ID对应所属分区 {familyID:zoneID, ...}
|
| | | |
| | | ## ------------------------ 【所有服务器】会有的信息,由跨服中心或跨服同步 ------------------------
|
| | | # 分区配置说明:
|
| | | # 1. 启动时由跨服中心初步验证配置合理性,如服务器范围有交叉、拆分等,验证不通过不会通知,且邮件通知运维
|
| | | # 2. 跨服中心验证通过后广播给所有跨服服务器,跨服服务器进一步验证是否有未分配的公会,有则验证不通过,且邮件通知运维
|
| | | # 3. 跨服中心、跨服均验证通过后,会按配置的分区初始化各分区公会管理,然后同步给各自的分区游戏服
|
| | | # 4. 热更分区配置时,只更新跨服中心即可,由跨服中心发起验证,同样执行流程 1~3,验证不通过的不会更新配置,保留原分区配置
|
| | | # 5. 热更分区验证通过后,会重新生成公会分区,热更仅对不需要不改变公会数据所在服务器时有效
|
| | | # 6. 如需改变已互通公会数据所在跨服,需停服维护先进行跨服数据合并后,重启服务器
|
| | | # 【注】游戏服首次跨服,根据收到的互通配置进行验证是否开始跨服,开始后同步数据给所属跨服,可重复同步直到成功,否则还是保持使用本服公会数据
|
| | | self.__crossZoneCfgDict = {} # 跨服互通分区配置 {crossServerID:{zoneID:[互通服务器ID范围列表], ...}, ...},由跨服中心同步
|
| | | |
| | | ## ------------------------ 【游戏服】专有信息,一般由所属互通跨服数据服同步 ----------------------
|
| | | # 互通公会基本信息 - 查看玩家页面需要看到的所属公会最简单的信息,一般只有游戏服用到
|
| | | #self.__familyViewBaseDict = {} # 公会ID对应基础查看信息 {familyID:FamilyViewBase, ...}
|
| | | self.__curZoneServerIDList = [] # 当前游戏服主服所属互通分区实际已经互通的服务器ID列表,同步给前端的
|
| | | self.__curCrossServerID = 0 # 当前游戏服主服公会所属跨服ID
|
| | | self.__curZoneID = 0 # 当前游戏服主服所属互通分区ID
|
| | | ## 【不允许不同互通分区的合服】
|
| | | return
|
| | | |
| | | def InitFamilyInstance(self, dbData):
|
| | | '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
|
| | | @param dbData: 实例对应绑定的dbData
|
| | | @return: 成功返回实例对象,失败返回None
|
| | | '''
|
| | | family = Family(dbData)
|
| | | familyID = family.GetID()
|
| | | if familyID in self.__familyIDDict:
|
| | | return self.__familyIDDict[familyID]
|
| | | self.__familyIDDict[familyID] = family
|
| | | return family
|
| | | |
| | | def AddFamily(self, familyName, serverID, familyID=None):
|
| | | ## 创建新仙盟
|
| | | newFamily = None
|
| | | if not familyName or not serverID:
|
| | | GameWorld.ErrLog("创建公会参数异常,无法创建! serverID=%s" % serverID)
|
| | | return newFamily
|
| | | zoneID = self.GetZoneIDInThisServer(serverID)
|
| | | if zoneID < 0:
|
| | | GameWorld.ErrLog("服务器ID创建的公会不属于本服管理,无法创建! serverID=%s" % serverID)
|
| | | return newFamily
|
| | | if familyID == None:
|
| | | familyID = PyMongoMain.GetUserCtrlDB().GetNewFamilyID()
|
| | | if familyID <= 0:
|
| | | GameWorld.ErrLog("创建公会时生成新ID异常!")
|
| | | return newFamily
|
| | | if familyID in self.__familyIDDict:
|
| | | GameWorld.ErrLog("创建公会时ID已存在! familyID=%s" % familyID)
|
| | | return newFamily
|
| | | # 名字通过分区管理验证并自动修改为不重名
|
| | | #if familyName in self.__familyNameDict:
|
| | | # GameWorld.ErrLog("创建仙盟时名称已存在! familyName=%s" % familyName)
|
| | | # return newFamily
|
| | | #if len(self.__familyList) >= FamilyUpperLimitCount:
|
| | | # GameWorld.ErrLog("单服限制创建仙盟数已达上限!")
|
| | | # return newFamily
|
| | | |
| | | dbData = DBStruct.tagDBFamily()
|
| | | dbData.ID = familyID
|
| | | dbData.Name = familyName
|
| | | dbData.ServerID = serverID
|
| | | dbData.CreateTime = int(time.time())
|
| | | |
| | | newFamily = self.InitFamilyInstance(dbData)
|
| | | if not newFamily and False: # 不执行,为了代码提示
|
| | | newFamily = Family()
|
| | | |
| | | # 添加到所属分区
|
| | | zoneMgr = self.GetZoneFamilyMgr(zoneID)
|
| | | zoneMgr.AddFamilyToZone(newFamily)
|
| | | |
| | | return newFamily
|
| | | |
| | | def OnFightPowerChange(self, family):
|
| | | zoneMgr = self.GetZoneFamilyMgrByFamilyID(family.GetID())
|
| | | if not zoneMgr:
|
| | | return
|
| | | zoneMgr.SetSort()
|
| | | return
|
| | | |
| | | def OnAddToZone(self, family, zoneID):
|
| | | familyID = family.GetID()
|
| | | self.__familyIDZoneIDDict[familyID] = zoneID
|
| | | return
|
| | | |
| | | def OnAddMember(self, family, playerID):
|
| | | self.__playerFamilyIDDict[playerID] = family.GetID()
|
| | | return
|
| | | |
| | | def OnDelMember(self, family, playerID):
|
| | | self.__playerFamilyIDDict.pop(playerID, None)
|
| | | return
|
| | | |
| | | def GetFamilyIDList(self): return self.__familyIDDict.keys()
|
| | | |
| | | def FindFamily(self, familyID):
|
| | | family = None
|
| | | if familyID and familyID in self.__familyIDDict:
|
| | | family = self.__familyIDDict[familyID]
|
| | | elif False:
|
| | | family = Family()
|
| | | return family
|
| | | |
| | | def DelFamily(self, familyID, isFreeID=True):
|
| | | family = self.FindFamily(familyID)
|
| | | self.__familyIDDict.pop(familyID, None)
|
| | | |
| | | # 同步从分区中删除
|
| | | if familyID in self.__familyIDZoneIDDict:
|
| | | zoneID = self.__familyIDZoneIDDict.get(familyID)
|
| | | zoneMgr = self.GetZoneFamilyMgr(zoneID)
|
| | | zoneMgr.DelZoneFamily(familyID)
|
| | | |
| | | # 最后删除自身
|
| | | if family:
|
| | | family.OnDelete()
|
| | | if isFreeID and familyID >= ShareDefine.RealFamilyIDStart:
|
| | | PyMongoMain.GetUserCtrlDB().FreeFamilyID(familyID) # 归还仙盟ID,重复使用
|
| | | return family
|
| | | |
| | | def DelAllFamily(self):
|
| | | for familyID in self.__familyIDDict.keys():
|
| | | self.DelFamily(familyID)
|
| | | return
|
| | |
|
| | | def GetFamilyActionMgr(self): return self.__actionMgr
|
| | |
|
| | | def __afterLoadDBFamilyData(self):
|
| | | self.__playerFamilyIDDict = {}
|
| | | self.__playerReqJoinDict = {}
|
| | | for family in self.__familyIDDict.values():
|
| | | familyID = family.GetID()
|
| | | family.RefrshFightPowerTotal()
|
| | | |
| | | for index in range(family.GetCount()):
|
| | | member = family.GetAt(index)
|
| | | self.__playerFamilyIDDict[member.GetPlayerID()] = familyID
|
| | | |
| | | reqPlayerIDDict = family.GetReqJoinPlayerInfo()
|
| | | #key强制转为int,线上的是字符串,做数据兼容
|
| | | for reqIDStr, v in reqPlayerIDDict.items():
|
| | | reqID = int(reqIDStr)
|
| | | reqPlayerIDDict.pop(reqIDStr, None)
|
| | | reqPlayerIDDict[reqID] = v
|
| | | if reqID not in self.__playerReqJoinDict:
|
| | | self.__playerReqJoinDict[reqID] = []
|
| | | reqFamilyIDList = self.__playerReqJoinDict[reqID]
|
| | | if familyID not in reqFamilyIDList:
|
| | | reqFamilyIDList.append(familyID)
|
| | | |
| | | return
|
| | | |
| | | def GetPlayerFamilyID(self, playerID):
|
| | | ## 获取玩家ID当前所在的公会ID
|
| | | return self.__playerFamilyIDDict.get(playerID, 0)
|
| | | |
| | | def GetPlayerReqJoinFamilyIDList(self, playerID):
|
| | | ## 获取玩家申请加入的仙盟ID列表
|
| | | if self.__playerReqJoinDict == None:
|
| | | self.__playerReqJoinDict = {}
|
| | | for index in xrange(self.GetCount()):
|
| | | family = self.GetAt(index)
|
| | | familyID = family.GetID()
|
| | | reqPlayerIDDict = family.GetReqJoinPlayerInfo()
|
| | | for reqID in reqPlayerIDDict.keys():
|
| | | if reqID not in self.__playerReqJoinDict:
|
| | | self.__playerReqJoinDict[reqID] = []
|
| | | reqFamilyIDList = self.__playerReqJoinDict[reqID]
|
| | | if familyID not in reqFamilyIDList:
|
| | | reqFamilyIDList.append(familyID)
|
| | | |
| | | if playerID not in self.__playerReqJoinDict:
|
| | | self.__playerReqJoinDict[playerID] = []
|
| | | return self.__playerReqJoinDict[playerID]
|
| | |
| | | family.DelReqJoinPlayerID(playerID)
|
| | | return
|
| | |
|
| | | def GetCrossZoneCfgDict(self): return self.__crossZoneCfgDict # {crossServerID:{zoneID:[互通服务器ID范围列表], ...}, ...}
|
| | | def SetCrossZoneCfgDict(self, crossZoneCfgDict): self.__crossZoneCfgDict = crossZoneCfgDict # 直接设置的不做更新检测逻辑,一般游戏服用
|
| | | def UpdCrossZoneCfgDict(self, updCrossZoneCfgDict):
|
| | | ## 更新分区配置,重置分区,重新分配
|
| | | ## @return: 本跨服是否成功更新分区,验证不通过的话不会重置,保留原分区
|
| | | GameWorld.Log("跨服公会互通配置更新! updCrossZoneCfgDict=%s" % updCrossZoneCfgDict)
|
| | | if not CheckCrossZoneCfg(self.__crossZoneCfgDict, updCrossZoneCfgDict):
|
| | | return
|
| | | |
| | | crossServerID = GameWorld.GetGameWorld().GetServerID()
|
| | | if crossServerID not in updCrossZoneCfgDict:
|
| | | GameWorld.Log("本跨服未分配分区的只更新配置即可!")
|
| | | self.__crossZoneCfgDict = updCrossZoneCfgDict
|
| | | return
|
| | | zoneDict = updCrossZoneCfgDict[crossServerID]
|
| | | |
| | | # 存在没有分配的公会,不应该处理,可能分区配置与实际数据不一致,一般发生在调整分区时,邮件通知运维
|
| | | familyZoneDict = {}
|
| | | noZoneServerIDList = [] # 没有所属分区的服务器ID列表
|
| | | for family in self.__familyIDDict.values():
|
| | | familyID = family.GetID()
|
| | | familyServerID = family.GetServerID()
|
| | | zoneID = 0
|
| | | for zID, serverIDRangeList in zoneDict.items():
|
| | | if GameWorld.CheckServerIDInList(familyServerID, serverIDRangeList):
|
| | | zoneID = zID
|
| | | break
|
| | | if not zoneID:
|
| | | if familyServerID not in noZoneServerIDList:
|
| | | noZoneServerIDList.append(familyServerID)
|
| | | else:
|
| | | familyZoneDict[familyID] = zoneID
|
| | | |
| | | if noZoneServerIDList:
|
| | | GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", "noZoneServerIDList=%s" % noZoneServerIDList)
|
| | | return
|
| | | |
| | | # 更新配置、重置、重新分区
|
| | | self.__crossZoneCfgDict = updCrossZoneCfgDict
|
| | | self.__zoneFamilyMgrDict = {}
|
| | | self.__familyIDZoneIDDict = {}
|
| | | zoneDict = self.__crossZoneCfgDict[crossServerID]
|
| | | for family in self.__familyIDDict.values():
|
| | | familyID = family.GetID()
|
| | | zoneID = familyZoneDict.get(familyID, 0) # 理论上不可能再为0
|
| | | zoneMgr = self.GetZoneFamilyMgr(zoneID)
|
| | | zoneMgr.AddFamilyToZone(family)
|
| | | |
| | | return True
|
| | | |
| | | def __setFamilyToDefaultZone(self):
|
| | | ## 将本服公会全部归到默认分区0,仅游戏服使用
|
| | | self.__zoneFamilyMgrDict = {}
|
| | | self.__familyIDZoneIDDict = {}
|
| | | zoneID = 0
|
| | | zoneMgr = self.GetZoneFamilyMgr(zoneID)
|
| | | for family in self.__familyIDDict.values():
|
| | | zoneMgr.AddFamilyToZone(family)
|
| | | return
|
| | | |
| | | def GetZoneIDInThisServer(self, serverID=None):
|
| | | '''获取服务器ID在本公会数据服务器中所属的分区ID,
|
| | | @return: zoneID -2-或传输数据中;-1-分区不在本服务器;0-未互通默认分区0;>0-在本服数据中所在分区ID
|
| | | '''
|
| | | curServerID = GameWorld.GetGameWorld().GetServerID()
|
| | | if not serverID:
|
| | | serverID = curServerID
|
| | | zoneID = -1
|
| | | serverType = GameWorld.GetServerType()
|
| | | if serverType == ShareDefine.serverType_Main:
|
| | | if IsFamilyCrossInTransData():
|
| | | zoneID = -2
|
| | | elif not IsFamilyCross():
|
| | | zoneID = 0 # 本服未跨服互通的默认分区0
|
| | | elif GameWorld.IsCrossServer() and curServerID in self.__crossZoneCfgDict:
|
| | | # 跨服服务器不适用 __zoneFamilyMgr 判断是因为如果出现某个服务器ID的所有公会都被删除了,重启服务器的时候从分区管理中可能找不到该服务器ID
|
| | | # 所以使用已验证过的互通配置即可,互通配置已经验证过合理性,可以直接用
|
| | | zoneDict = self.__crossZoneCfgDict[curServerID]
|
| | | for zID, serverIDRangeList in zoneDict.items():
|
| | | if GameWorld.CheckServerIDInList(serverID, serverIDRangeList):
|
| | | zoneID = zID
|
| | | break
|
| | | return zoneID
|
| | | |
| | | def GetZoneIDListThisServer(self): return self.__zoneFamilyMgrDict.keys() # 在本服数据中已存在的分区
|
| | | |
| | | def GetFamilyZoneID(self, familyID): return self.__familyIDZoneIDDict.get(familyID, -1) # -1-未找到所属分区;>=0-所属分区
|
| | | |
| | | def GetZoneFamilyMgrByFamilyID(self, familyID):
|
| | | ## 获取公会ID在本服数据所属分区管理器
|
| | | # @return: 可能返回None - 公会数据不在本服
|
| | | zoneID = -1
|
| | | if familyID in self.__familyIDZoneIDDict:
|
| | | zoneID = self.__familyIDZoneIDDict[familyID]
|
| | | zoneMgr = None
|
| | | if zoneID >= 0:
|
| | | zoneMgr = self.GetZoneFamilyMgr(zoneID)
|
| | | return zoneMgr
|
| | | |
| | | def GetZoneFamilyMgr(self, zoneID=0):
|
| | | ## 获取某个分区的公会管理器
|
| | | # @param zoneID: 未互通的服务器默认使用0,使用方法一致
|
| | | zoneMgr = None
|
| | | if zoneID in self.__zoneFamilyMgrDict:
|
| | | zoneMgr = self.__zoneFamilyMgrDict[zoneID]
|
| | | else:
|
| | | 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,一个游戏服主服只允许一个互通分区,不同分区的不能合服
|
| | | # @return: -2-传输数据中;-1-非游戏服或没有正确的跨服ID;0-未互通;>0-互通的目标跨服ID
|
| | | serverType = GameWorld.GetServerType()
|
| | | if serverType != ShareDefine.serverType_Main:
|
| | | return -1
|
| | | |
| | | if IsFamilyCrossInTransData():
|
| | | return -2
|
| | | |
| | | # 未互通
|
| | | if not IsFamilyCross():
|
| | | return 0
|
| | | |
| | | if self.__curCrossServerID:
|
| | | return self.__curCrossServerID
|
| | | |
| | | curServerID = GameWorld.GetGameWorld().GetServerID()
|
| | | for crossServerID, zoneDict in self.__crossZoneCfgDict.items():
|
| | | for serverIDRangeList in zoneDict.values():
|
| | | if GameWorld.CheckServerIDInList(curServerID, serverIDRangeList):
|
| | | return crossServerID
|
| | | |
| | | return -1
|
| | | |
| | | def SetCurCrossServerID(self, curCrossServerID): self.__curCrossServerID = curCrossServerID # 直接设置的游戏服专用
|
| | | def GetCurZoneID(self): # 本游戏服主服所属互通分区ID
|
| | | return 0 if not IsFamilyCross() else self.__curZoneID
|
| | | def SetCurZoneID(self, curZoneID): self.__curZoneID = curZoneID # 直接设置的游戏服专用
|
| | | def GetCurZoneServerIDList(self): return self.__curZoneServerIDList # 本游戏服主服实际已互通的服务器ID列表
|
| | | def SetCurZoneServerIDList(self, curZoneServerIDList): self.__curZoneServerIDList = curZoneServerIDList # 直接设置的游戏服专用
|
| | | |
| | | # 保存数据 存数据库和realtimebackup
|
| | | def GetSaveData(self):
|
| | | def GetSaveData(self, cntDict=None):
|
| | |
|
| | | familyDataCnt, familySavaData = 0, ""
|
| | | membreDataCnt, memberSavaData = 0, ""
|
| | | actionDataCnt, actionSavaData = 0, ""
|
| | | for family in self.__familyList:
|
| | | |
| | | for family in self.__familyIDDict.values():
|
| | | |
| | | familyID = family.GetID()
|
| | | familySavaData += family.GetBuffer()
|
| | | familyDataCnt += 1
|
| | |
| | |
|
| | | saveData += CommFunc.WriteDWORD("", actionDataCnt) + actionSavaData
|
| | | GameWorld.Log("Save DBFamilyAction count :%s len=%s" % (actionDataCnt, len(actionSavaData)))
|
| | | |
| | | if isinstance(cntDict, dict):
|
| | | cntDict.update({"familyDataCnt":familyDataCnt, "membreDataCnt":membreDataCnt, "actionDataCnt":actionDataCnt})
|
| | | return saveData
|
| | |
|
| | | # 从数据库载入数据
|
| | | def LoadPyGameData(self, datas, pos, dataslen): |
| | | # 仙盟
|
| | | def LoadPyGameData(self, datas, pos, dataslen):
|
| | | # 公会
|
| | | cnt, pos = CommFunc.ReadDWORD(datas, pos)
|
| | | GameWorld.Log("Load DBFamily count :%s" % cnt)
|
| | | for _ in xrange(cnt):
|
| | | dbData = DBStruct.tagDBFamily()
|
| | | pos += dbData.readData(datas, pos, dataslen)
|
| | | self.InitFamilyInstance(dbData)
|
| | | self.Sort()
|
| | | |
| | | |
| | | # 成员
|
| | | cnt, pos = CommFunc.ReadDWORD(datas, pos)
|
| | | GameWorld.Log("Load DBFamilyMem count :%s" % cnt)
|
| | |
| | |
|
| | | familyID = dbData.FamilyID
|
| | | actionType = dbData.ActionType
|
| | | |
| | | family = self.FindFamily(familyID)
|
| | | if not family:
|
| | | continue
|
| | | action = self.__actionMgr.GetFamilyAction(familyID, actionType)
|
| | | action.InitActionInstance(dbData)
|
| | |
|
| | | self.__afterLoadDBFamilyData()
|
| | | |
| | | PyMongoMain.GetUserCtrlDB().OnFamilyIDInit(self.__familyIDDict.keys())
|
| | | |
| | | serverType = GameWorld.GetServerType()
|
| | | if serverType == ShareDefine.serverType_CrossCenter:
|
| | | self.UpdCrossZoneCfgDict(LoadZoneCfg())
|
| | | elif serverType == ShareDefine.serverType_Main:
|
| | | self.__setFamilyToDefaultZone() # 游戏服本服的数据无论有没有跨服了都同意设置到默认分区
|
| | | return pos
|
| | |
|
| | | def OnMinute():
|
| | | |
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | # 每分钟刷新下仙盟战力排序
|
| | | isSort = False
|
| | | for index in range(familyMgr.GetCount()):
|
| | | family = familyMgr.GetAt(index)
|
| | | if not family:
|
| | | def LoadZoneCfg(self):
|
| | | crossZoneCfgDict = {}
|
| | | appID = GameWorld.GetAppID()
|
| | | ipyDataMgr = IpyGameDataPY.IPY_Data()
|
| | | for index in range(ipyDataMgr.GetFamilyCrossCount()):
|
| | | ipyData = ipyDataMgr.GetFamilyCrossByIndex(index)
|
| | | if ipyData.GetAppID() != appID:
|
| | | continue
|
| | | if family.RefrshFightPowerTotal(True):
|
| | | isSort = True
|
| | | if isSort:
|
| | | familyMgr.Sort()
|
| | | crossServerID = ipyData.GetCrossServerID()
|
| | | zoneID = ipyData.GetZoneID()
|
| | | if crossServerID not in crossZoneCfgDict:
|
| | | crossZoneCfgDict[crossServerID] = {}
|
| | | zoneDict = crossZoneCfgDict[crossServerID]
|
| | | zoneDict[zoneID] = [] + ipyData.GetServerIDList()
|
| | | return crossZoneCfgDict
|
| | |
|
| | | def CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
|
| | | # 检查待更新的分区配置是否符合规则,不符合的话保留原配置,不更新,待扩展
|
| | | |
| | | if curCrossZoneCfgDict == updCrossZoneCfgDict:
|
| | | GameWorld.Log("跨服公会互通分区配置不变不处理")
|
| | | return
|
| | | |
| | | # 验证配置,是否有交叉、拆分,并邮件通知运维,待扩展,先开发功能
|
| | | #GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", "noZoneServerIDList=%s" % noZoneServerIDList)
|
| | | |
| | | return True
|
| | |
|
| | | def OnReloadConfig():
|
| | | '''重读配置验证修改后的配置是否符合规定,不符合的话,还是使用旧配置的范围,并邮件通知运维
|
| | | 公会分区配置同步规则: 由跨服中心加载配置 -> 验证通过后发给所有跨服 -> 跨服验证通过后发给所管辖的分区所有游戏服务器
|
| | | '''
|
| | | |
| | | if GameWorld.IsCrossCenter():
|
| | | crossZoneCfgDict = LoadZoneCfg()
|
| | | if not crossZoneCfgDict or not DBDataMgr.GetFamilyMgr().UpdCrossZoneCfgDict(crossZoneCfgDict):
|
| | | return
|
| | | Sync_CenterToCross_FamilyCrossCfg()
|
| | |
|
| | | return
|
| | |
|
| | | def Sync_CenterToCross_FamilyInfo(serverType, serverID):
|
| | | ## 跨服中心同步给跨服服务器
|
| | | if serverType == ShareDefine.serverType_Cross:
|
| | | Sync_CenterToCross_FamilyCrossCfg(serverID)
|
| | | return
|
| | |
|
| | | def Sync_CenterToCross_FamilyCrossCfg(serverID=0):
|
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict()
|
| | | if not crossZoneCfgDict:
|
| | | GameWorld.Log("没有公会互通配置或没有验证正确的互通分区配置不通知!")
|
| | | return
|
| | | dataMsg = {"crossZoneCfgDict":crossZoneCfgDict}
|
| | | serverIDList = [serverID] if serverID else crossZoneCfgDict.keys()
|
| | | CrossMsg.SendToServer(ShareDefine.CC2C_FamilyCrossCfg, dataMsg, serverIDList, ShareDefine.dirType_Cross)
|
| | | return
|
| | |
|
| | | def CC2C_FamilyCrossCfg(dataMsg, fromServerID, serverType):
|
| | | # 跨服中心同步的分区配置,仅跨服服务器处理即可,游戏服以所属跨服处理后的最终数据为准
|
| | | if serverType != ShareDefine.serverType_CrossCenter:
|
| | | return
|
| | | updCrossZoneCfgDict = dataMsg["crossZoneCfgDict"]
|
| | | |
| | | if not updCrossZoneCfgDict:
|
| | | return
|
| | | |
| | | if GameWorld.GetServerType() != ShareDefine.serverType_Cross:
|
| | | return
|
| | | |
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | if not familyMgr.UpdCrossZoneCfgDict(updCrossZoneCfgDict):
|
| | | return
|
| | | Sync_CrossToServer_FamilyInfo()
|
| | | return
|
| | |
|
| | | def Sync_CrossToServer_FamilyInfo(toServerID=0, syncZoneID=0, syncFamilyIDList=[]):
|
| | | ## 跨服服务器同步互通公会信息给游戏服
|
| | | # @param toServerID: 有指定游戏服连上时只发给该服,没有的话一般是分区配置变更时由跨服主动同步所有相关游戏服
|
| | | |
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict() # 配置的互通
|
| | | if not crossZoneCfgDict:
|
| | | return
|
| | | crossServerID = GameWorld.GetGameWorld().GetServerID()
|
| | | if crossServerID not in crossZoneCfgDict:
|
| | | return
|
| | | zoneCfgDict = crossZoneCfgDict[crossServerID]
|
| | | |
| | | for zoneID in familyMgr.GetZoneIDListThisServer():
|
| | | if syncZoneID and syncZoneID != zoneID:
|
| | | continue
|
| | | if zoneID not in zoneCfgDict:
|
| | | continue
|
| | | cfgServerIDList = zoneCfgDict[zoneID] # 配置需要互通的服务器信息,需要同步给这些服务器
|
| | | |
| | | if toServerID:
|
| | | if not GameWorld.CheckServerIDInList(toServerID, cfgServerIDList):
|
| | | # 非指定目标服务器所属分区不同步
|
| | | continue
|
| | | toServerIDList = [toServerID]
|
| | | else:
|
| | | toServerIDList = cfgServerIDList
|
| | | |
| | | zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
|
| | | zoneServerIDList = zoneMgr.GetZoneServerIDList()
|
| | | |
| | | # 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}
|
| | | CrossMsg.SendToClientServer(ShareDefine.C2S_FamilyCrossInfo, dataMsg, toServerIDList)
|
| | | |
| | | return
|
| | |
|
| | | def C2S_FamilyCrossInfo(dataMsg, fromServerID):
|
| | | ## 游戏服收到互通跨服同步的公会互通信息,按分区同步
|
| | | |
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | 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()
|
| | | updZoneServerIDList = dataMsg["zoneServerIDList"]
|
| | | familyMgr.SetCurZoneServerIDList(updZoneServerIDList)
|
| | | if curZoneServerIDList != updZoneServerIDList:
|
| | | Sync_FamilyCrossInfo()
|
| | | |
| | | return
|
| | |
|
| | | def IsFamilyCross():
|
| | | ## 本服公会是否已跨服
|
| | | return DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyCrossState) == 1
|
| | |
|
| | | def IsFamilyCrossInTransData():
|
| | | ## 本服公会首次跨服互通同步数据中
|
| | | return DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyTransDataTime) > 0
|
| | |
|
| | | def CheckCrossFamilyTransData(connServerID=0, ignoreCD=False):
|
| | | ## 检查跨服公会传输数据,服务器启动时、onday时检查,或GM等指定强制调用
|
| | | |
| | | if IsFamilyCross():
|
| | | GameWorld.DebugLog("本服公会已经跨服了!")
|
| | | return
|
| | | |
| | | NeedServerDay = IpyGameDataPY.GetFuncCfg("FamilyCross", 1)
|
| | | serverDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_ServerDay) + 1
|
| | | if serverDay < NeedServerDay:
|
| | | GameWorld.DebugLog("本服公会互通所需开服天不足! serverDay=%s < %s" % (serverDay, NeedServerDay))
|
| | | return
|
| | | |
| | | # 如果合服也以主服为准,所有合服的服务器要求本身必须也已经是跨服公会的才能合服
|
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | crossZoneCfgDict = familyMgr.GetCrossZoneCfgDict()
|
| | | |
| | | crossServerID = 0
|
| | | serverID = GameWorld.GetGameWorld().GetServerID()
|
| | | for cID, zoneDict in crossZoneCfgDict.items():
|
| | | for zoneID, serverIDRangeList in zoneDict.items():
|
| | | if GameWorld.CheckServerIDInList(serverID, serverIDRangeList):
|
| | | crossServerID = cID
|
| | | 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
|
| | | |
| | | transDataTime = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyTransDataTime)
|
| | | if transDataTime and not ignoreCD:
|
| | | curTime = int(time.time())
|
| | | if curTime - transDataTime < 30 * 60: # 30分钟内不重复传输
|
| | | GameWorld.Log("本服公会互通传输数据中! serverID=%s,crossServerID=%s,transDataTime=%s" % (serverID, crossServerID, GameWorld.ChangeTimeNumToStr(transDataTime)))
|
| | | return
|
| | | |
| | | GameWorld.Log("本服公会开启互通开始传输公会相关数据! serverID=%s,crossServerID=%s" % (serverID, crossServerID))
|
| | | DBDataMgr.GetEventTrigMgr().SetValue(ShareDefine.Def_FamilyTransDataTime, int(time.time()))
|
| | | |
| | | cntDict = {}
|
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | syncData = familyMgr.GetSaveData(cntDict)
|
| | | familyIDList = familyMgr.GetFamilyIDList()
|
| | | |
| | | CrossMsg.SendToCrossServer(ShareDefine.S2C_FamilyData, {"syncData":syncData, "familyIDList":familyIDList, "cntDict":cntDict}, [crossServerID])
|
| | | return
|
| | |
|
| | | def S2C_FamilyData(dataMsg, fromServerID):
|
| | | syncData = dataMsg["syncData"]
|
| | | familyIDList = dataMsg["familyIDList"]
|
| | | cntDict = dataMsg["cntDict"]
|
| | | 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:
|
| | | 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:]
|
| | | |
| | | # 插入新数据,重名的会在加入分区后自动改名
|
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
|
| | | actionMgr = familyMgr.GetFamilyActionMgr()
|
| | | |
| | | syncFamilyIDList = []
|
| | | for dbData in familyDataList:
|
| | | dbData = DBStruct.tagDBFamily()
|
| | | familyID = dbData.ID
|
| | | familyMgr.DelFamily(familyID, False) # 每次都强制先删除,支持重复同步
|
| | | zoneMgr.AddFamilyToZone(familyMgr.InitFamilyInstance(dbData))
|
| | | syncFamilyIDList.append(familyID)
|
| | | |
| | | # 成员
|
| | | for dbData in memberDataList:
|
| | | familyID = dbData.FamilyID
|
| | | family = familyMgr.FindFamily(familyID)
|
| | | if not family:
|
| | | continue
|
| | | family.InitMemberInstance(dbData)
|
| | | |
| | | # 行为
|
| | | for dbData in actionDataList:
|
| | | familyID = dbData.FamilyID
|
| | | |
| | | familyID = dbData.FamilyID
|
| | | actionType = dbData.ActionType
|
| | | |
| | | family = familyMgr.FindFamily(familyID)
|
| | | if not family:
|
| | | continue
|
| | | action = actionMgr.GetFamilyAction(familyID, actionType)
|
| | | action.InitActionInstance(dbData)
|
| | | |
| | | # 同步给相同互通分区的服务器
|
| | | Sync_CrossToServer_FamilyInfo(syncZoneID=zoneID, syncFamilyIDList=syncFamilyIDList)
|
| | | |
| | | # 最后回复同步结果
|
| | | CrossMsg.SendToClientServer(ShareDefine.C2S_FamilyDataRet, {"isOK":True}, [fromServerID])
|
| | | return
|
| | |
|
| | | def __unpackFamilyData(syncData, familyIDList, cntDict):
|
| | | ## 解包,验证数据
|
| | | # @param cntDict: {"familyDataCnt":familyDataCnt, "membreDataCnt":membreDataCnt, "actionDataCnt":actionDataCnt}
|
| | | |
| | | errorMsg = ""
|
| | | datas, pos, dataslen = syncData, 0, len(syncData)
|
| | | |
| | | zoneIDDict = {}
|
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | |
| | | # 公会
|
| | | familyDataList = []
|
| | | cnt, pos = CommFunc.ReadDWORD(datas, pos)
|
| | | GameWorld.Log("Read DBFamily count :%s" % cnt)
|
| | | for _ in xrange(cnt):
|
| | | dbData = DBStruct.tagDBFamily()
|
| | | pos += dbData.readData(datas, pos, dataslen)
|
| | | familyDataList.append(dbData)
|
| | | familyID = dbData.ID
|
| | | if familyID not in familyIDList:
|
| | | errorMsg = "同步的数据公会ID不匹配! familyID=%s not in %s" % (familyID, familyIDList)
|
| | | return errorMsg
|
| | | |
| | | familyServerID = dbData.ServerID
|
| | | zoneID = familyMgr.GetZoneIDInThisServer(familyServerID)
|
| | | if zoneID <= 0:
|
| | | errorMsg = "同步的公会数据不属于本跨服! familyID=%s,familyServerID=%s,zoneID=%s" % (familyID, familyServerID, zoneID)
|
| | | return errorMsg
|
| | | zoneIDDict[zoneID] = familyServerID
|
| | | |
| | | if len(zoneIDDict) != 1:
|
| | | errorMsg = "同步的公会数据分区异常可能存在多个分区! zoneIDDict=%s" % zoneIDDict
|
| | | return errorMsg
|
| | | zoneID = zoneIDDict.keys()[0]
|
| | | |
| | | uppackFamilyCnt = len(familyDataList)
|
| | | familyDataCnt = cntDict.get("familyDataCnt", 0)
|
| | | if uppackFamilyCnt != familyDataCnt:
|
| | | errorMsg = "同步的公会个数不匹配! uppackFamilyCnt=%s != %s" % (uppackFamilyCnt, familyDataCnt)
|
| | | return errorMsg
|
| | | |
| | | # 成员
|
| | | memberDataList = []
|
| | | cnt, pos = CommFunc.ReadDWORD(datas, pos)
|
| | | GameWorld.Log("Read DBFamilyMem count :%s" % cnt)
|
| | | for _ in xrange(cnt):
|
| | | dbData = DBStruct.tagDBFamilyMem()
|
| | | pos += dbData.readData(datas, pos, dataslen)
|
| | | memberDataList.append(dbData)
|
| | | |
| | | uppackMemberCnt = len(memberDataList)
|
| | | membreDataCnt = cntDict.get("membreDataCnt", 0)
|
| | | if uppackMemberCnt != membreDataCnt:
|
| | | errorMsg = "同步的成员个数不匹配! uppackMemberCnt=%s != %s" % (uppackMemberCnt, membreDataCnt)
|
| | | return errorMsg
|
| | | |
| | | # 行为
|
| | | actionDataList = []
|
| | | cnt, pos = CommFunc.ReadDWORD(datas, pos)
|
| | | GameWorld.Log("Read DBFamilyAction count :%s" % cnt)
|
| | | for _ in xrange(cnt):
|
| | | dbData = DBStruct.tagDBFamilyAction()
|
| | | pos += dbData.readData(datas, pos, dataslen)
|
| | | actionDataList.append(dbData)
|
| | | |
| | | uppackActionCnt = len(actionDataList)
|
| | | actionDataCnt = cntDict.get("actionDataCnt", 0)
|
| | | if uppackMemberCnt != membreDataCnt:
|
| | | errorMsg = "同步的行为个数不匹配! uppackActionCnt=%s != %s" % (uppackActionCnt, actionDataCnt)
|
| | | return errorMsg
|
| | | |
| | | return errorMsg, zoneID, familyDataList, memberDataList, actionDataList
|
| | |
|
| | | def C2S_FamilyDataRet(dataMsg, fromServerID):
|
| | | isOK = dataMsg["isOK"]
|
| | | GameWorld.Log("收到互通公会数据同步结果! fromServerID=%s,isOK=%s" % (fromServerID, isOK))
|
| | | # 重置传输数据状态
|
| | | DBDataMgr.GetEventTrigMgr().SetValue(ShareDefine.Def_FamilyTransDataTime, 0) |
| | | if not isOK:
|
| | | # 失败,暂时还是使用本服公会,等Onday再触发,或排查问题后维护,后续再优化多次同步方案
|
| | | # 运维邮件已在跨服发送,不服可不处理
|
| | | return
|
| | | |
| | | GameWorld.Log("互通公会数据同步成功,本服正式开启跨服公会互通! fromServerID=%s" % (fromServerID))
|
| | | DBDataMgr.GetEventTrigMgr().SetValue(ShareDefine.Def_FamilyCrossState, 1)
|
| | | ChPlayer.SyncOnlinePlayerToCross(fromServerID) |
| | | return
|
| | |
|
| | | def OnMinute():
|
| | | |
| | | if GameWorld.IsMainServer():
|
| | | if IsFamilyCross():
|
| | | # 游戏服公会已跨服不处理
|
| | | return
|
| | | |
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | # 每分钟刷新下仙盟战力排序
|
| | | for zoneID in familyMgr.GetZoneIDListThisServer():
|
| | | zoneMgr = familyMgr.GetZoneFamilyMgr(zoneID)
|
| | | zoneMgr.Sort(True)
|
| | | |
| | | return
|
| | |
|
| | | def Sync_FamilyCrossInfo(curPlayer=None):
|
| | | ## 同步本服公会互通信息
|
| | | if not IsFamilyCross():
|
| | | return
|
| | | familyMgr = DBDataMgr.GetFamilyMgr()
|
| | | clientPack = ChPyNetSendPack.tagSCFamilyCrossInfo()
|
| | | clientPack.ZoneID = familyMgr.GetCurZoneID()
|
| | | clientPack.ServerIDList = familyMgr.GetCurZoneServerIDList()
|
| | | clientPack.ServerCnt = len(clientPack.ServerIDList)
|
| | | if curPlayer:
|
| | | NetPackCommon.SendFakePack(curPlayer, clientPack)
|
| | | else:
|
| | | NetPackCommon.SendFackPackOnline(clientPack)
|
| | | return
|
| | | |