| | |
| | | import random
|
| | | #---------------------------------------------------------------------
|
| | |
|
| | | ## 跨服地图动态分配的功能线路,如果有人数上限的,则同分区同地图玩法的可能同时存在多个相同功能线路的数据
|
| | | class CrossFuncLineInfo():
|
| | | |
| | | def __init__(self):
|
| | | self.mapID = 0
|
| | | self.copyMapID = 0
|
| | | self.funcLineDataCache = None # 功能线路自定义缓存数据
|
| | | return
|
| | | |
| | | def OnCopyMapClose(self, funcLineDataCache):
|
| | | self.mapID = 0
|
| | | self.copyMapID = 0
|
| | | self.funcLineDataCache = funcLineDataCache
|
| | | return
|
| | |
|
| | | ## 跨服地图动态分配的虚拟线路信息
|
| | | class CrossCopyMapInfo():
|
| | | |
| | | def __init__(self, zoneID, funcLineID):
|
| | | self.zoneID = zoneID
|
| | | self.funcLineID = funcLineID
|
| | | self.openState = 0
|
| | | self.fbPlayerDict = {} # 副本中的玩家信息 {playerID:serverGroupID, ...}
|
| | | self.waitPlayerDict = {} # 等待进入的玩家信息 {playerID:[serverGroupID, tick], ...}
|
| | | return
|
| | | |
| | | def OnRequestEnterCrossCopyMap(self, playerID, serverGroupID, tick, copyMapPlayerMax):
|
| | | # 已经在请求队列里,可进入
|
| | | if playerID in self.waitPlayerDict or not copyMapPlayerMax:
|
| | | self.waitPlayerDict[playerID] = [serverGroupID, tick]
|
| | | return True
|
| | | |
| | | # 移除请求进入超时的玩家
|
| | | for waitPlayerID, playerInfo in self.waitPlayerDict.items():
|
| | | serverGroupID, requestTick = playerInfo
|
| | | if tick - requestTick > 60000: # 请求进入时间保留1分钟
|
| | | self.waitPlayerDict.pop(waitPlayerID)
|
| | | |
| | | # 判断是否超过人数上限
|
| | | fbPlayerCount, waitPlayerCount = len(self.fbPlayerDict), len(self.waitPlayerDict)
|
| | | if fbPlayerCount + waitPlayerCount >= copyMapPlayerMax:
|
| | | return False
|
| | | |
| | | self.waitPlayerDict[playerID] = [serverGroupID, tick]
|
| | | return True
|
| | | |
| | | #---------------------------------------------------------------------
|
| | | def GetFBLineIpyData(mapID, lineID, isDefaultLine=True):
|
| | | mapID = GetRecordMapID(mapID)
|
| | |
| | | return dataMapID
|
| | | return mapID
|
| | |
|
| | | def ClientServerMsg_EnterFB(serverGroupID, msgData):
|
| | | def ClientServerMsg_EnterFB(serverGroupID, msgData, tick):
|
| | | ## 收到子服请求进入动态分配的跨服副本
|
| | | playerID = msgData["PlayerID"]
|
| | | dataMapID = msgData["DataMapID"]
|
| | | funcLineID = msgData["FuncLineID"]
|
| | |
|
| | | zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByServerGroupID(dataMapID, serverGroupID)
|
| | | if not zoneIpyData:
|
| | | return
|
| | | zoneID = zoneIpyData.GetZoneID()
|
| | | |
| | | copyMapPlayerMax = 0 # 0为不限制人数,默认不限制
|
| | | if dataMapID == ChConfig.Def_FBMapID_CrossDemonKing:
|
| | | zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByServerGroupID(dataMapID, serverGroupID)
|
| | | if not zoneIpyData:
|
| | | return
|
| | | zoneID = zoneIpyData.GetZoneID()
|
| | | bossID = msgData["BossID"]
|
| | | if not CrossBoss.GetCrossBossIsAliveOrCanReborn(zoneID, bossID):
|
| | | GameWorld.DebugLog("当前跨服妖王死亡状态,不可进入! serverGroupID=%s,funcLineID=%s,zoneID=%s,bossID=%s" % (serverGroupID, funcLineID, zoneID, bossID))
|
| | | return
|
| | |
|
| | | mapCopyLineInfo = __GetCrossDynamicLineInfo(dataMapID, funcLineID, zoneID)
|
| | | if not mapCopyLineInfo:
|
| | | return
|
| | | mapID, copyMapID, isOpenNew = mapCopyLineInfo
|
| | | elif dataMapID in [ChConfig.Def_FBMapID_CrossGrasslandLing, ChConfig.Def_FBMapID_CrossGrasslandXian]:
|
| | | copyMapPlayerMax = 10
|
| | |
|
| | | # 如果是等待线路启动中的直接返回,等启动好后再通知可进入
|
| | | if __AddWaitCrossFBOpenPlayer(mapID, copyMapID, isOpenNew, playerID, serverGroupID):
|
| | | return
|
| | | else:
|
| | | return
|
| | | |
| | | mapCopyLineInfo = __GetCrossDynamicLineInfo(playerID, serverGroupID, dataMapID, funcLineID, zoneID, copyMapPlayerMax, tick)
|
| | | if not mapCopyLineInfo:
|
| | | return
|
| | | mapID, copyMapID, openState = mapCopyLineInfo
|
| | | if not openState:
|
| | | return
|
| | |
|
| | | playerIDList = [playerID]
|
| | |
| | |
|
| | | return
|
| | |
|
| | | def __GetCrossDynamicLineInfo(dataMapID, funcLineID, zoneID):
|
| | | ## 获取跨服分区对应动态分配的副本地图虚拟线路信息
|
| | |
|
| | | isOpenNew = False |
| | | def __GetCrossDynamicLineInfo(playerID, serverGroupID, dataMapID, funcLineID, zoneID, copyMapPlayerMax, tick):
|
| | | '''获取跨服分区对应动态分配的副本地图虚拟线路信息, 由于需要支持多地图分流,所以直接由GameServer管理分配
|
| | | 每个功能线路支持按人数分流,超过最大人数后可开启一条相同功能线路的虚拟线路进行分流,所以同一分区同一地图的功能线路ID可能对应多条虚拟线路
|
| | | '''
|
| | | |
| | | zoneLineKey = (zoneID, funcLineID)
|
| | | if dataMapID not in PyGameData.g_crossDynamicLineInfo:
|
| | | PyGameData.g_crossDynamicLineInfo[dataMapID] = {}
|
| | | zoneLineDict = PyGameData.g_crossDynamicLineInfo[dataMapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[mapID, copyMapID], ...}, ...} |
| | | if zoneLineKey in zoneLineDict:
|
| | | mapID, copyMapID = zoneLineDict[zoneLineKey]
|
| | | GameWorld.DebugLog("已存在该分区功能线路ID,不需要重新分配: zoneID=%s,funcLineID=%s,mapID=%s,copyMapID=%s" % (zoneID, funcLineID, mapID, copyMapID))
|
| | | return mapID, copyMapID, isOpenNew
|
| | | zoneLineDict = PyGameData.g_crossDynamicLineInfo[dataMapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...}
|
| | | if zoneLineKey not in zoneLineDict:
|
| | | zoneLineDict[zoneLineKey] = []
|
| | | funcLineObjList = zoneLineDict[zoneLineKey]
|
| | |
|
| | | newFuncLineNum = None
|
| | | newFuncLineObj = None
|
| | | for index, funcLineObj in enumerate(funcLineObjList, 1):
|
| | | mapID, copyMapID = funcLineObj.mapID, funcLineObj.copyMapID
|
| | | if not mapID:
|
| | | newFuncLineNum, newFuncLineObj = index, funcLineObj
|
| | | break
|
| | | |
| | | key = (mapID, copyMapID)
|
| | | if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
|
| | | GameWorld.ErrLog("已经分配的虚拟线路不存在缓存对应关系里!zoneID=%s,funcLineID=%s,mapID=%s,copyMapID=%s" |
| | | % (zoneID, funcLineID, mapID, copyMapID))
|
| | | continue
|
| | | |
| | | copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
|
| | | openState = copyMapObj.openState
|
| | | canEnter = copyMapObj.OnRequestEnterCrossCopyMap(playerID, serverGroupID, tick, copyMapPlayerMax)
|
| | | if canEnter:
|
| | | #GameWorld.DebugLog("可进入动态分布的虚拟线路! mapID=%s,copyMapID=%s,openState=%s" % (mapID, copyMapID, openState))
|
| | | #GameWorld.DebugLog(" 副本中的玩家ID: %s" % copyMapObj.fbPlayerDict)
|
| | | #GameWorld.DebugLog(" 等待中的玩家ID: %s" % copyMapObj.waitPlayerDict)
|
| | | return mapID, copyMapID, openState
|
| | | |
| | | if dataMapID == ChConfig.Def_FBMapID_CrossDemonKing:
|
| | | mapIDList = IpyGameDataPY.GetFuncEvalCfg("CrossDemonKingMap", 1)
|
| | | |
| | | elif dataMapID == ChConfig.Def_FBMapID_CrossGrasslandLing:
|
| | | mapIDList = [dataMapID]
|
| | | elif dataMapID == ChConfig.Def_FBMapID_CrossGrasslandXian:
|
| | | mapIDList = [dataMapID] |
| | | # 其他地图待扩展
|
| | | else:
|
| | | return
|
| | | |
| | | usedMapCopyList = zoneLineDict.values() # 已经使用中的地图虚拟线路
|
| | | |
| | | openMapID, openCopyMapID = 0, 0
|
| | | for mapID in mapIDList:
|
| | | maxCopyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(mapID, 0)
|
| | | for copyMapID in xrange(maxCopyMapCount):
|
| | | if [mapID, copyMapID] not in usedMapCopyList:
|
| | | if (mapID, copyMapID) not in PyGameData.g_crossDynamicLineCopyMapInfo:
|
| | | openMapID, openCopyMapID = mapID, copyMapID
|
| | | break
|
| | | if openMapID:
|
| | |
| | | GameWorld.ErrLog("没有空余的虚拟线路,无法动态开启跨服副本!dataMapID=%s, funcLineID=%s, zoneID=%s, mapIDList=%s"
|
| | | % (dataMapID, funcLineID, zoneID, mapIDList))
|
| | | return
|
| | | isOpenNew = True
|
| | | mapID, copyMapID = openMapID, openCopyMapID
|
| | |
|
| | | zoneLineDict[zoneLineKey] = [mapID, copyMapID]
|
| | | propertyID = zoneID * 1000 + funcLineID
|
| | | if newFuncLineObj == None:
|
| | | newFuncLineObj = CrossFuncLineInfo()
|
| | | funcLineObjList.append(newFuncLineObj)
|
| | | newFuncLineNum = len(funcLineObjList)
|
| | | mapID, copyMapID = openMapID, openCopyMapID
|
| | | newFuncLineObj.mapID = mapID
|
| | | newFuncLineObj.copyMapID = copyMapID
|
| | | funcLineDataCache = newFuncLineObj.funcLineDataCache
|
| | | |
| | | key = (mapID, copyMapID)
|
| | | copyMapObj = CrossCopyMapInfo(zoneID, funcLineID)
|
| | | PyGameData.g_crossDynamicLineCopyMapInfo[key] = copyMapObj
|
| | | copyMapObj.waitPlayerDict[playerID] = [serverGroupID, tick]
|
| | | openState = copyMapObj.openState
|
| | | |
| | | propertyID = int("%d%03d%d" % (zoneID, funcLineID, newFuncLineNum))
|
| | | GameWorld.DebugLog("不存在该分区功能线路ID,重新分配: zoneID=%s,funcLineID=%s,mapID=%s,copyMapID=%s,propertyID=%s"
|
| | | % (zoneID, funcLineID, mapID, copyMapID, propertyID))
|
| | |
|
| | | # 通知地图开启新的地图虚拟分线
|
| | | msgInfo = str([copyMapID, propertyID])
|
| | | msgInfo = str([copyMapID, propertyID, funcLineDataCache])
|
| | | GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, mapID, "OpenFB", msgInfo, len(msgInfo))
|
| | | return mapID, copyMapID, isOpenNew
|
| | | return mapID, copyMapID, openState
|
| | |
|
| | | def __AddWaitCrossFBOpenPlayer(mapID, copyMapID, isOpenNew, playerID, serverGroupID):
|
| | | ## 添加跨服玩家进入等待动态副本虚拟线路开启队列
|
| | | |
| | | if mapID not in PyGameData.g_crossDynamicLineOpeningInfo:
|
| | | PyGameData.g_crossDynamicLineOpeningInfo[mapID] = {}
|
| | | openingMapCopyIDDict = PyGameData.g_crossDynamicLineOpeningInfo[mapID] # 跨服动态线路正在开启中的线路信息 {mapID:{copyMapID:{playerID:serverGroupID, ...}, ...}, ...}
|
| | | |
| | | if isOpenNew or copyMapID in openingMapCopyIDDict:
|
| | | if copyMapID not in openingMapCopyIDDict:
|
| | | openingMapCopyIDDict[copyMapID] = {}
|
| | | waitingPlayerDict = openingMapCopyIDDict[copyMapID]
|
| | | waitingPlayerDict[playerID] = serverGroupID
|
| | | GameWorld.Log("添加玩家进入等待跨服动态副本虚拟线路开启队列: mapID=%s,copyMapID=%s,isOpenNew=%s,playerID=%s,serverGroupID=%s" |
| | | % (mapID, copyMapID, isOpenNew, playerID, serverGroupID))
|
| | | GameWorld.Log(" PyGameData.g_crossDynamicLineOpeningInfo=%s" % PyGameData.g_crossDynamicLineOpeningInfo)
|
| | | return True
|
| | | return False
|
| | | def GetCrossDynamicLineZoneID(dataMapID, mapID, copyMapID):
|
| | | ## 获取跨服动态分配的虚拟线路对应分区ID
|
| | | zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(dataMapID, {})
|
| | | for key, funcLineObjList in zoneLineDict.items():
|
| | | for funcLineObj in funcLineObjList:
|
| | | if funcLineObj.mapID == mapID and funcLineObj.copyMapID == copyMapID:
|
| | | zoneID = key[0]
|
| | | return zoneID
|
| | | return 0
|
| | |
|
| | | def OnCrossDynamicLineOpen(mapID, copyMapID):
|
| | | ## 动态分配线路的地图虚拟线路启动成功
|
| | |
|
| | | if mapID not in PyGameData.g_crossDynamicLineOpeningInfo:
|
| | | key = (mapID, copyMapID)
|
| | | if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
|
| | | return
|
| | | openingCopyMapDict = PyGameData.g_crossDynamicLineOpeningInfo[mapID]
|
| | | waitingPlayerDict = openingCopyMapDict.pop(copyMapID, {})
|
| | | if not waitingPlayerDict:
|
| | | return
|
| | | copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
|
| | | copyMapObj.openState = 1
|
| | |
|
| | | # 通知子服等待中的玩家可以进入副本
|
| | | serverPlayerIDListDict = {}
|
| | | for playerID, serverGroupID in waitingPlayerDict.items():
|
| | | for playerID, playerInfo in copyMapObj.waitPlayerDict.items():
|
| | | serverGroupID = playerInfo[0]
|
| | | if serverGroupID not in serverPlayerIDListDict:
|
| | | serverPlayerIDListDict[serverGroupID] = []
|
| | | playerIDList = serverPlayerIDListDict[serverGroupID]
|
| | |
| | | retInfo = [playerIDList, dataMapID, mapID, copyMapID]
|
| | | CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID])
|
| | |
|
| | | GameWorld.DebugLog(" PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)
|
| | | GameWorld.DebugLog(" PyGameData.g_crossDynamicLineOpeningInfo=%s" % PyGameData.g_crossDynamicLineOpeningInfo)
|
| | | #GameWorld.DebugLog(" PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)
|
| | | #GameWorld.DebugLog(" PyGameData.g_crossDynamicLineCopyMapInfo=%s" % PyGameData.g_crossDynamicLineCopyMapInfo)
|
| | | return
|
| | |
|
| | | def OnCrossDynamicLineClose(mapID, copyMapID):
|
| | | def OnCrossDynamicLineClose(mapID, copyMapID, funcLineDataCache):
|
| | | ## 动态分配线路的地图虚拟线路关闭
|
| | |
|
| | | dataMapID = GetRecordMapID(mapID)
|
| | | GameWorld.Log("动态分配虚拟线路关闭 dataMapID=%s,mapID=%s,copyMapID=%s" % (dataMapID, mapID, copyMapID))
|
| | | zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(dataMapID, {})
|
| | | for key, mapCopyInfo in zoneLineDict.items():
|
| | | if mapCopyInfo[0] == mapID and mapCopyInfo[1] == copyMapID:
|
| | | zoneLineDict.pop(key)
|
| | | break
|
| | | |
| | | openingCopyMapDict = PyGameData.g_crossDynamicLineOpeningInfo.get(mapID, {})
|
| | | openingCopyMapDict.pop(copyMapID, {})
|
| | | for key, funcLineObjList in zoneLineDict.items():
|
| | | for funcLineObj in funcLineObjList:
|
| | | if funcLineObj.mapID == mapID and funcLineObj.copyMapID == copyMapID:
|
| | | funcLineObj.OnCopyMapClose(funcLineDataCache)
|
| | | zoneID, funcLineID = key
|
| | | GameWorld.Log(" 分区对应功能线路虚拟分线关闭: zoneID=%s,dataMapID%s,funcLineID=%s" % (zoneID, dataMapID, funcLineID))
|
| | | break
|
| | |
|
| | | GameWorld.DebugLog(" PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)
|
| | | GameWorld.DebugLog(" PyGameData.g_crossDynamicLineOpeningInfo=%s" % PyGameData.g_crossDynamicLineOpeningInfo)
|
| | | key = (mapID, copyMapID)
|
| | | PyGameData.g_crossDynamicLineCopyMapInfo.pop(key, {})
|
| | | |
| | | #GameWorld.DebugLog(" PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)
|
| | | #GameWorld.DebugLog(" PyGameData.g_crossDynamicLineCopyMapInfo=%s" % PyGameData.g_crossDynamicLineCopyMapInfo)
|
| | | return
|
| | |
|
| | | def OnCrossDynamicMapReset(mapID, copyMapCount):
|
| | |
| | | GameWorld.Log("动态分配虚拟线路地图重置 dataMapID=%s,mapID=%s,copyMapCount=%s" % (dataMapID, mapID, copyMapCount))
|
| | | PyGameData.g_crossMapCopyMapCountDict[mapID] = copyMapCount
|
| | |
|
| | | zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(dataMapID, {}) |
| | | for key, mapCopyInfo in zoneLineDict.items():
|
| | | if mapCopyInfo[0] == mapID:
|
| | | zoneLineDict.pop(key)
|
| | | zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(dataMapID, {})
|
| | | for key, funcLineObjList in zoneLineDict.items():
|
| | | for funcLineObj in funcLineObjList:
|
| | | if funcLineObj.mapID == mapID:
|
| | | funcLineObj.OnCopyMapClose(None)
|
| | |
|
| | | PyGameData.g_crossDynamicLineOpeningInfo.pop(mapID, None)
|
| | | for key in PyGameData.g_crossDynamicLineCopyMapInfo.keys():
|
| | | if key[0] == mapID:
|
| | | PyGameData.g_crossDynamicLineCopyMapInfo.pop(key)
|
| | | |
| | | #GameWorld.DebugLog(" PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)
|
| | | #GameWorld.DebugLog(" PyGameData.g_crossDynamicLineCopyMapInfo=%s" % PyGameData.g_crossDynamicLineCopyMapInfo) |
| | | return
|
| | |
|
| | | def PlayerLoginLoadCrossMapOK(curPlayer):
|
| | | ## 玩家登录跨服地图
|
| | | |
| | | mapID, copyMapID = curPlayer.GetRealMapID(), curPlayer.GetFBID()
|
| | | key = (mapID, copyMapID)
|
| | | if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
|
| | | return
|
| | | copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
|
| | | |
| | | playerID = curPlayer.GetPlayerID()
|
| | | serverGroupID = PlayerControl.GetPlayerServerGroupID(curPlayer)
|
| | | copyMapObj.waitPlayerDict.pop(playerID, None)
|
| | | copyMapObj.fbPlayerDict[playerID] = serverGroupID
|
| | | |
| | | #GameWorld.DebugLog("玩家登录动态分配的跨服地图: GetMapID=%s,GetRealMapID=%s,GetFBID()=%s,serverGroupID=%s" |
| | | # % (curPlayer.GetMapID(), mapID, copyMapID, serverGroupID), playerID)
|
| | | #GameWorld.DebugLog(" 副本中的玩家ID: %s" % copyMapObj.fbPlayerDict)
|
| | | #GameWorld.DebugLog(" 等待中的玩家ID: %s" % copyMapObj.waitPlayerDict)
|
| | | return
|
| | |
|
| | | def OnPlayerDisconnectCrossServer(curPlayer):
|
| | | ## 玩家离开跨服服务器
|
| | | |
| | | mapID, copyMapID = curPlayer.GetRealMapID(), curPlayer.GetFBID()
|
| | | key = (mapID, copyMapID)
|
| | | if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
|
| | | return
|
| | | copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
|
| | | |
| | | playerID = curPlayer.GetPlayerID()
|
| | | copyMapObj.waitPlayerDict.pop(playerID, None)
|
| | | copyMapObj.fbPlayerDict.pop(playerID, None)
|
| | | |
| | | #GameWorld.DebugLog("玩家退出动态分配的跨服地图: GetMapID=%s,GetRealMapID=%s,GetFBID()=%s" |
| | | # % (curPlayer.GetMapID(), mapID, copyMapID), playerID)
|
| | | #GameWorld.DebugLog(" 副本中的玩家ID: %s" % copyMapObj.fbPlayerDict)
|
| | | #GameWorld.DebugLog(" 等待中的玩家ID: %s" % copyMapObj.waitPlayerDict)
|
| | | return
|
| | |
|
| | | ##--------------------------------------------------------------------------------------------------
|
| | |
|
| | | ## 请求进入副本分线
|
| | | # @param curPlayer: 请求玩家
|
| | | # @param queryCallName: 请求回调名
|