From 164b1a9e2eb3f9908e95e0050de828f0e35cb74b Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期一, 23 五月 2022 16:38:31 +0800 Subject: [PATCH] 9415 【BT5】【后端】古神战场(初版:包含战场副本外的所有功能;副本中暂仅支持击杀玩家玩法) --- ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py | 356 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 297 insertions(+), 59 deletions(-) diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py index a8d5e9e..48853d9 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py @@ -31,19 +31,26 @@ import GameWorld import ChConfig import IPY_PlayerDefine +import CrossBattlefield import CrossRealmPlayer import CrossRealmMsg import ShareDefine import CrossBoss +import time +DynamicShuntType_No = 0 # 不分流 +DynamicShuntType_Fill = 1 # 填满式分流,按存在的线路人数多的优先填充,都满后开启新线路 +DynamicShuntType_Equally = 2 # 均摊式分流,按存在的线路人数少的优先填充,都满后开启新线路 #--------------------------------------------------------------------- ## 跨服地图动态分配的功能线路,如果有人数上限的,则同分区同地图玩法的可能同时存在多个相同功能线路的数据 +## {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...} class CrossFuncLineInfo(): def __init__(self): self.realMapID = 0 self.copyMapID = 0 + self.newFuncLineNum = 0 self.funcLineDataCache = None # 功能线路自定义缓存数据 return @@ -52,37 +59,48 @@ self.copyMapID = 0 return -## 跨服地图动态分配的虚拟线路信息 +## 跨服地图动态分配的虚拟线路信息 {(mapID, copyMapID):CrossCopyMapInfo, ...} class CrossCopyMapInfo(): def __init__(self, zoneID, funcLineID): self.zoneID = zoneID self.funcLineID = funcLineID + self.newFuncLineNum = 0 + self.realMapID = 0 + self.copyMapID = 0 self.openState = IPY_PlayerDefine.fbosClosed self.fbPlayerDict = {} # 副本中的玩家信息 {playerID:serverGroupID, ...} self.waitPlayerDict = {} # 等待进入的玩家信息 {playerID:[serverGroupID, tick], ...} self.offlinePlayerDict = {} # 掉线的玩家信息,非主动退出的 {playerID:serverGroupID, ...} + self.enterPlayerIDList = [] # 有进入过此分线的玩家ID列表,不会清除 [playerID, ...] return - def OnRequestEnterCrossCopyMap(self, playerID, serverGroupID, tick, copyMapPlayerMax): - # 已经在请求队列里,可进入 - if playerID in self.waitPlayerDict or not copyMapPlayerMax: - self.waitPlayerDict[playerID] = [serverGroupID, tick] - return True + def GetCopyMapPlayerCount(self, includeOffline, tick): + ## 获取该分线玩家数 + # @param includeOffline: 是否包含离线玩家 # 移除请求进入超时的玩家 for waitPlayerID, playerInfo in self.waitPlayerDict.items(): - serverGroupID, requestTick = playerInfo + _, 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 + totalPlayerCount = fbPlayerCount + waitPlayerCount + if includeOffline: + totalPlayerCount += len(self.offlinePlayerDict) + + return totalPlayerCount + + def IsMustCopyMapPlayer(self, playerID): + ## 是否必定在此分线的玩家, 在请求队列里 或 曾经进入到该分线的,都强制认为属于该分线的玩家 + return playerID in self.waitPlayerDict or playerID in self.enterPlayerIDList - self.waitPlayerDict[playerID] = [serverGroupID, tick] - return True + def OnRequestEnterCrossCopyMap(self, playerID, tick, copyMapPlayerMax, includeOffline): + if not copyMapPlayerMax or self.IsMustCopyMapPlayer(playerID): + return True + return self.GetCopyMapPlayerCount(includeOffline, tick) < copyMapPlayerMax #--------------------------------------------------------------------- def GetFBLineIpyData(mapID, lineID, isDefaultLine=True): @@ -127,37 +145,127 @@ playerID = msgData["PlayerID"] mapID = msgData["MapID"] funcLineID = msgData["FuncLineID"] + playerLV = msgData["LV"] zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByServerGroupID(mapID, serverGroupID) if not zoneIpyData: return zoneID = zoneIpyData.GetZoneID() - dynamicLineMaxPlayerCountDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 2) - copyMapPlayerMax = dynamicLineMaxPlayerCountDict.get(mapID, 0) # 0为不限制人数,默认不限制 + openHour, openMinute = None, None + dynamicShuntType = DynamicShuntType_Fill + includeOffline = False + tagCopyMapObj = None + + # 基础验证是否可进入等 及 数据准备 if mapID == ChConfig.Def_FBMapID_CrossDemonKing: bossID = msgData["BossID"] if not CrossBoss.GetCrossBossIsAliveOrCanReborn(zoneID, bossID): - GameWorld.DebugLog("当前跨服妖王死亡状态,不可进入! serverGroupID=%s,funcLineID=%s,zoneID=%s,bossID=%s" % (serverGroupID, funcLineID, zoneID, bossID)) + GameWorld.ErrLog("当前跨服妖王死亡状态,不可进入! funcLineID=%s,zoneID=%s,bossID=%s" % (funcLineID, zoneID, bossID), playerID) return elif mapID in [ChConfig.Def_FBMapID_CrossGrasslandLing, ChConfig.Def_FBMapID_CrossGrasslandXian]: pass - + + elif mapID == ChConfig.Def_FBMapID_CrossBattlefield: + openTimeInfo = CrossBattlefield.GetCrossBattlefieldOpenTime(zoneID) + if not openTimeInfo: + PlayerControl.NotifyCodeCross(serverGroupID, playerID, "FBIsNotOpen") + GameWorld.ErrLog("非活动时间或未开启! funcLineID=%s,zoneID=%s" % (funcLineID, zoneID), playerID) + return + dynamicShuntType = DynamicShuntType_Equally + isCallBattle, openHour, openMinute = openTimeInfo + if isCallBattle: + # 召集场次默认 funcLineID 为0,不分等级,不分流 + funcLineID = 0 + dynamicShuntType = DynamicShuntType_No + includeOffline = True else: return - mapCopyLineInfo = __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, tick) - if not mapCopyLineInfo: + dynamicLineMaxPlayerCountDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 2) + copyMapPlayerMin, copyMapPlayerMax = dynamicLineMaxPlayerCountDict.get(mapID, [0, 0]) # 0为不限制人数,默认不限制 + + # 除个别地图外,最优先进入上次进入的未关闭分线 + if mapID not in []: + for _, copyMapObj in PyGameData.g_crossDynamicLineCopyMapInfo.items(): + if copyMapObj.IsMustCopyMapPlayer(playerID): + tagCopyMapObj = copyMapObj + break + + # 如果没有进入过,则按功能看是否有特殊指定规则 + if tagCopyMapObj == None: + if mapID == ChConfig.Def_FBMapID_CrossBattlefield: + if isCallBattle: + copyMapPlayerMax = IpyGameDataPY.GetFuncCfg("CrossBattlefieldCall", 2) + tagCopyMapObj = CrossBattlefield.GetCallPlayerCopymapObj(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, includeOffline, tick) + + # 如果还没有取到对应的分流线,则按默认规则处理 + if tagCopyMapObj == None and dynamicShuntType: + # 非特殊动态规则,走常规逻辑 + dynamicLineLVRangeDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 4) + if mapID in dynamicLineLVRangeDict: + lvRangeList = dynamicLineLVRangeDict[mapID] + for lvFuncLineID, lvRange in enumerate(lvRangeList): + if lvRange[0] <= playerLV <= lvRange[1]: + funcLineID = lvFuncLineID + copyMapPlayerMin, copyMapPlayerMax = lvRange[2], lvRange[3] + GameWorld.DebugLog("进入跨服地图等级自动适配功能线路ID: mapID=%s,playerLV=%s,funcLineID=%s,copyMapPlayerMin=%s,copyMapPlayerMax=%s" + % (mapID, playerLV, funcLineID, copyMapPlayerMin, copyMapPlayerMax)) + break + + shuntPlayerMax = copyMapPlayerMax + + minCountTimeDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 3) # 分流下限人数有效时间配置,单位秒,{dataMapID:秒, ...} + if mapID in minCountTimeDict: + playerMinTimeSet = minCountTimeDict[mapID] + curTime = GameWorld.GetServerTime() + if openHour == None or openMinute == None: + GameWorld.ErrLog("副本开启时间未知! mapID=%s,funcLineID=%s,zoneID=%s" % (mapID, funcLineID, zoneID), playerID) + return + + openDateTimeStr = "%d-%02d-%02d %02d:%02d:00" % (curTime.year, curTime.month, curTime.day, openHour, openMinute) + openDateTime = GameWorld.ChangeStrToDatetime(openDateTimeStr) + passTime = curTime - openDateTime + ''' + 在线(包含请求中) <= 单场下限值 + 在线(包含请求中)+ 离线 <= 单场上限值 + + 前X秒大于 单场下限值 开新一场 + 任意时刻大于 单场上限值 必开新一场 + ''' + if passTime.seconds <= playerMinTimeSet: + shuntPlayerMax = copyMapPlayerMin + includeOffline = False + else: + shuntPlayerMax = copyMapPlayerMax + includeOffline = True + + tagCopyMapObj = __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, + shuntPlayerMax, copyMapPlayerMax, includeOffline, tick, dynamicShuntType) + + if not tagCopyMapObj: + PlayerControl.NotifyCodeCross(serverGroupID, playerID, "CrossFBFull") + GameWorld.ErrLog("找不到可分流的副本线路! mapID=%s,funcLineID=%s,zoneID=%s" % (mapID, funcLineID, zoneID), playerID) return - realMapID, copyMapID, openState = mapCopyLineInfo - if openState != IPY_PlayerDefine.fbosOpen: + + realMapID, copyMapID, openState = tagCopyMapObj.realMapID, tagCopyMapObj.copyMapID, tagCopyMapObj.openState + + if openState == IPY_PlayerDefine.fbosWaitForClose: + PlayerControl.NotifyCodeCross(serverGroupID, playerID, "CrossFBClose") + GameWorld.ErrLog("分流的副本线路关闭中! mapID=%s,funcLineID=%s,zoneID=%s,realMapID=%s,copyMapID=%s,openState=%s" + % (mapID, funcLineID, zoneID, realMapID, copyMapID, openState), playerID) return - playerIDList = [playerID] - retInfo = [playerIDList, mapID, realMapID, copyMapID, funcLineID] - CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID]) - return + tagCopyMapObj.waitPlayerDict[playerID] = [serverGroupID, tick] + GameWorld.DebugLog(" 分配进入跨服场景: realMapID=%s, copyMapID=%s, openState=%s" % (realMapID, copyMapID, openState), playerID) + if openState == IPY_PlayerDefine.fbosOpen: + funcLineID = tagCopyMapObj.funcLineID + playerIDList = [playerID] + retInfo = [playerIDList, mapID, realMapID, copyMapID, funcLineID] + CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID]) + + return tagCopyMapObj def CrossServerMsg_EnterFBRet(msgData, tick): ## 收到跨服服务器动态分配的跨服副本进入信息 @@ -172,26 +280,50 @@ return -def __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, tick): +def __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, shuntPlayerMax, copyMapPlayerMax, includeOffline, tick, dynamicShuntType): '''获取跨服分区对应动态分配的副本地图虚拟线路信息, 由于需要支持多地图分流,所以直接由GameServer管理分配 每个功能线路支持按人数分流,超过最大人数后可开启一条相同功能线路的虚拟线路进行分流,所以同一分区同一地图的功能线路ID可能对应多条虚拟线路 + 分流方式: + DynamicShuntType_Fill = 1 # 填满式分流,按存在的线路人数多的优先填充,都满后开启新线路 + DynamicShuntType_Equally = 2 # 均摊式分流,按存在的线路人数少的优先填充,都满后开启新线路 + 分流规则: + 时间仅决定分流人数,不影响常规分配逻辑 + 1. 优先分配到人数小于分流人数的场次 + 2. 超过分流人数的场次依次往人数少的场次分配 + 3. 当当前已开放的场次都达到人数分流人数,则开启新场次,没有空闲的场,则往未达到人数上限的场次依次分配,直到达到所有场次上限 + + 关于 shuntPlayerMax 的选择: 可根据副本规则制定 + 如前X分钟内可设定一个小于 copyMapPlayerMax 的分流人数值快速铺满各分流场次 + 当大于X分钟后则可设置 shuntPlayerMax = copyMapPlayerMax 进行饱和分流 + + 当所有分流场次达到 shuntPlayerMax 后,可尝试开启新分流线路,进行分流 + shuntPlayerMax < copyMapPlayerMax 的情况,如果没有办法开启新分流线路,则可继续强制根据分流类型分配线路,只要未达到 copyMapPlayerMax 人数,还是可以进入副本的 + shuntPlayerMax >= copyMapPlayerMax 的情况,如果没有办法开启新分流线路,则标识副本所有线路已达到饱和状态,不能再进入副本了 + + 当 shuntPlayerMax 为 0 时,达标不限制人数上限,及不分流,都在同一条线路,一般跨服副本不建议设置为0,人数太多,不合理 + + @param shuntPlayerMax: 分流最大人数限制 + @param copyMapPlayerMax: 实际最大可容纳的人数限制,一般大于等于分流人数限制 + @param includeOffline: 是否包含本线路离线玩家 + @param dynamicShuntType: 分流类型,可选择 填满式分流 或 均摊式分流 ''' zoneLineKey = (zoneID, funcLineID) - if mapID not in PyGameData.g_crossDynamicLineInfo: - PyGameData.g_crossDynamicLineInfo[mapID] = {} - zoneLineDict = PyGameData.g_crossDynamicLineInfo[mapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...} - if zoneLineKey not in zoneLineDict: - zoneLineDict[zoneLineKey] = [] - funcLineObjList = zoneLineDict[zoneLineKey] + zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {}) + funcLineObjList = zoneLineDict.get(zoneLineKey, []) + isPlayerFullMax = (shuntPlayerMax >= copyMapPlayerMax) - newFuncLineNum = None - newFuncLineObj = None - for index, funcLineObj in enumerate(funcLineObjList, 1): + GameWorld.DebugLog("获取动态分流线路: serverGroupID=%s,mapID=%s,funcLineID=%s,zoneID=%s,shuntPlayerMax=%s,copyMapPlayerMax=%s,includeOffline=%s,dynamicShuntType=%s" + % (serverGroupID, mapID, funcLineID, zoneID, shuntPlayerMax, copyMapPlayerMax, includeOffline, dynamicShuntType), playerID) + #GameWorld.DebugLog(" funcLineObjList=%s" % funcLineObjList, playerID) + + canUseShuntLine = False # 是否直接使用分流线路,如果否的话,当人数未达到真正饱和时,则还可直接分配对应分流类型的线路 + minPlayerCount, maxPlayerCount = 0, 0 + minCopyMapObj, maxCopyMapObj = None, None + for _, funcLineObj in enumerate(funcLineObjList, 1): realMapID, copyMapID = funcLineObj.realMapID, funcLineObj.copyMapID + #GameWorld.DebugLog(" realMapID=%s, copyMapID=%s" % (realMapID, copyMapID)) if not realMapID: - if not newFuncLineObj: - newFuncLineNum, newFuncLineObj = index, funcLineObj continue key = (realMapID, copyMapID) @@ -203,59 +335,161 @@ copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key] openState = copyMapObj.openState if openState == IPY_PlayerDefine.fbosWaitForClose: - if not copyMapPlayerMax: - PlayerControl.CrossNotifyCode(serverGroupID, playerID, "HazyRegionClose") + # 没有限制分流人数的情况,代表都在同一场,这种情况下当副本已经在关闭的状态下,则代表已经结束了,不可再进入 + if not shuntPlayerMax: + PlayerControl.NotifyCodeCross(serverGroupID, playerID, "CrossFBClose") return - #GameWorld.DebugLog(" 虚拟线路等待关闭中! index=%s,realMapID=%s,copyMapID=%s" % (index, realMapID, copyMapID)) + #GameWorld.DebugLog(" 虚拟线路等待关闭中! realMapID=%s,copyMapID=%s" % (realMapID, copyMapID)) continue - canEnter = copyMapObj.OnRequestEnterCrossCopyMap(playerID, serverGroupID, tick, copyMapPlayerMax) - if canEnter: - #GameWorld.DebugLog("可进入动态分布的虚拟线路! realMapID=%s,copyMapID=%s,openState=%s" % (realMapID, copyMapID, openState)) - #GameWorld.DebugLog(" 副本中的玩家ID: %s" % copyMapObj.fbPlayerDict) - #GameWorld.DebugLog(" 等待中的玩家ID: %s" % copyMapObj.waitPlayerDict) - return realMapID, copyMapID, openState + if not shuntPlayerMax or copyMapObj.IsMustCopyMapPlayer(playerID): + return copyMapObj + playerCount = copyMapObj.GetCopyMapPlayerCount(includeOffline, tick) + if minCopyMapObj == None or playerCount < minPlayerCount: + minPlayerCount = playerCount + minCopyMapObj = copyMapObj + + if maxCopyMapObj == None or playerCount > maxPlayerCount: + maxPlayerCount = playerCount + maxCopyMapObj = copyMapObj + + # 存在线路未达到规定的分流人数,则可直接使用分流线路 + if playerCount < shuntPlayerMax: + canUseShuntLine = True + + #GameWorld.DebugLog(" isPlayerFullMax=%s,canUseShuntLine=%s" % (isPlayerFullMax, canUseShuntLine)) + dynamicShuntCopyMap = None # 分流类型决定的分流线路 + + # 均摊式 + if dynamicShuntType == DynamicShuntType_Equally: + dynamicShuntCopyMap = minCopyMapObj + # 填满式 + elif dynamicShuntType == DynamicShuntType_Fill: + dynamicShuntCopyMap = maxCopyMapObj + else: + return + + shuntCopyMap = None + if canUseShuntLine: + shuntCopyMap = dynamicShuntCopyMap + + #GameWorld.DebugLog(" shuntCopyMap=%s" % shuntCopyMap) + if not shuntCopyMap: + isLog = isPlayerFullMax + shuntCopyMap = __OpenNewFuncLine(mapID, zoneID, funcLineID, isLog) + + # 即 shuntPlayerMax < copyMapPlayerMax 的情况 + if not shuntCopyMap and not isPlayerFullMax: + shuntCopyMap = dynamicShuntCopyMap + + if not shuntCopyMap: + return + + shuntCopyMap.waitPlayerDict[playerID] = [serverGroupID, tick] + + return shuntCopyMap + +def __OpenNewFuncLine(mapID, zoneID, funcLineID, isLog=True): + ## 新开功能线路分流 + + if mapID not in PyGameData.g_crossDynamicLineInfo: + PyGameData.g_crossDynamicLineInfo[mapID] = {} + zoneLineDict = PyGameData.g_crossDynamicLineInfo[mapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...} + zoneLineKey = (zoneID, funcLineID) + if zoneLineKey not in zoneLineDict: + zoneLineDict[zoneLineKey] = [] + funcLineObjList = zoneLineDict[zoneLineKey] + dynamicLineMapDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 1) dynamicMapIDList = dynamicLineMapDict.get(mapID, [mapID]) openMapID, openCopyMapID = 0, 0 - for realMapID in dynamicMapIDList: - maxCopyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0) - for copyMapID in xrange(maxCopyMapCount): + maxCopyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(dynamicMapIDList[0], 0) + # 外层为虚拟线路总数遍历,内层为分流地图,这样可以均匀分流到各个分流地图,减少单地图压力 + for copyMapID in xrange(maxCopyMapCount): + for realMapID in dynamicMapIDList: + if copyMapID >= PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0): + continue if (realMapID, copyMapID) not in PyGameData.g_crossDynamicLineCopyMapInfo: openMapID, openCopyMapID = realMapID, copyMapID break if openMapID: break + if not openMapID: - GameWorld.ErrLog("没有空余的虚拟线路,无法动态开启跨服副本!mapID=%s, funcLineID=%s, zoneID=%s, dynamicMapIDList=%s" - % (mapID, funcLineID, zoneID, dynamicMapIDList)) + if isLog: + GameWorld.ErrLog("没有空余的虚拟线路,无法动态开启跨服副本! mapID=%s,zoneID=%s,funcLineID=%s,dynamicMapIDList=%s" + % (mapID, zoneID, funcLineID, dynamicMapIDList)) return + realMapID, copyMapID = openMapID, openCopyMapID + + newFuncLineObj = None + for funcLineObj in funcLineObjList: + if not funcLineObj.realMapID: + newFuncLineObj = funcLineObj + break + if newFuncLineObj == None: newFuncLineObj = CrossFuncLineInfo() funcLineObjList.append(newFuncLineObj) - newFuncLineNum = len(funcLineObjList) - realMapID, copyMapID = openMapID, openCopyMapID + + newFuncLineNum = 1 + lineNumList = [lineObj.newFuncLineNum for lineObj in funcLineObjList] + for num in xrange(1, len(lineNumList) + 1): + if num not in lineNumList: + newFuncLineNum = num + break + GameWorld.DebugLog(" lineNumList=%s,newFuncLineNum=%s" % (lineNumList, newFuncLineNum)) + newFuncLineObj.realMapID = realMapID newFuncLineObj.copyMapID = copyMapID - funcLineDataCache = newFuncLineObj.funcLineDataCache + newFuncLineObj.newFuncLineNum = newFuncLineNum + + copyMapObj = CrossCopyMapInfo(zoneID, funcLineID) + copyMapObj.realMapID = realMapID + copyMapObj.copyMapID = copyMapID + copyMapObj.newFuncLineNum = newFuncLineNum key = (realMapID, 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,realMapID=%s,copyMapID=%s,propertyID=%s" - % (zoneID, funcLineID, realMapID, copyMapID, propertyID)) + propertyID = int("%d%03d%02d" % (zoneID, funcLineID, newFuncLineNum)) + GameWorld.Log(" 新开分区动态副本功能线路: zoneID=%s,funcLineID=%s,newFuncLineNum=%s,realMapID=%s,copyMapID=%s,propertyID=%s" + % (zoneID, funcLineID, newFuncLineNum, realMapID, copyMapID, propertyID)) # 通知地图开启新的地图虚拟分线 + funcLineDataCache = newFuncLineObj.funcLineDataCache msgInfo = str([copyMapID, propertyID, funcLineDataCache]) GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, realMapID, "OpenFB", msgInfo, len(msgInfo)) - return realMapID, copyMapID, openState + return copyMapObj + +def OpenCrossDynamicLineBySys(zoneID, mapID, funcLineIDList, checkExist): + ## 系统开启跨服动态线路 + + GameWorld.Log(" 系统开启跨服动态线路: zoneID=%s, mapID=%s, funcLineIDList=%s, checkExist=%s" % (zoneID, mapID, funcLineIDList, checkExist)) + + for funcLineID in funcLineIDList: + + if checkExist: + fincLineObj = None + zoneLineKey = (zoneID, funcLineID) + zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {}) + funcLineObjList = zoneLineDict.get(zoneLineKey, []) + for funcLineObj in funcLineObjList: + if funcLineObj.realMapID: + fincLineObj = funcLineObj + break + + if fincLineObj: + GameWorld.ErrLog("已经存在开放中的线路,不重复开启动态副本线路! mapID=%s, funcLineID=%s, zoneID=%s, realMapID=%s, copyMapID=%s" + % (mapID, funcLineID, zoneID, funcLineObj.realMapID, funcLineObj.copyMapID)) + continue + + __OpenNewFuncLine(mapID, zoneID, funcLineID) + + return def GetCrossDynamicLineZoneID(mapID, realMapID, copyMapID): ## 获取跨服动态分配的虚拟线路对应分区ID @@ -345,6 +579,8 @@ funcLineObj.OnCopyMapClose() zoneID, funcLineID = key GameWorld.Log(" 分区对应功能线路虚拟分线关闭: zoneID=%s,dataMapID%s,funcLineID=%s" % (zoneID, dataMapID, funcLineID)) + if not funcLineObj.funcLineDataCache: + funcLineObjList.remove(funcLineObj) break key = (mapID, copyMapID) @@ -401,6 +637,8 @@ copyMapObj.waitPlayerDict.pop(playerID, None) copyMapObj.offlinePlayerDict.pop(playerID, None) copyMapObj.fbPlayerDict[playerID] = serverGroupID + if playerID not in copyMapObj.enterPlayerIDList: + copyMapObj.enterPlayerIDList.append(playerID) #GameWorld.DebugLog("玩家登录动态分配的跨服地图: GetMapID=%s,GetRealMapID=%s,GetFBID()=%s,serverGroupID=%s" # % (curPlayer.GetMapID(), mapID, copyMapID, serverGroupID), playerID) -- Gitblit v1.8.0