From 3afcfad8a40b4638ff069c63a83af90640fa6559 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 11 二月 2026 17:32:52 +0800
Subject: [PATCH] 66 【公会】基础主体-服务端(优化公会互通后某个游戏服在没有公会没有玩家加入跨服公会时下次维护无法成功显示加入跨服分区;优化分区配置检查,异常时不应用配置且发送qq邮件;)
---
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py | 242 ++++++++++++++++++++++++++++-------------------
1 files changed, 144 insertions(+), 98 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 312ce65..b085183 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
@@ -20,6 +20,7 @@
import 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,58 @@
## 本服公会首次跨服互通同步数据中
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
NeedServerDay = IpyGameDataPY.GetFuncCfg("FamilyCross", 1)
@@ -1241,11 +1254,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 +1287,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 +1296,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 +1361,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