6459 【后端】【2.0】缥缈仙域开发单(进入动态分布线路的跨服地图分配规则优化,功能对应虚拟线路支持人数控制分流)
13个文件已修改
1个文件已添加
366 ■■■■ 已修改文件
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBoss.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py 271 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossDemonKing.py 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossGrassland.py 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_OpenFB.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -683,20 +683,26 @@
Def_FBMapID_DemonKing = 22030
#骑宠Boss
Def_FBMapID_HorsePetBoss = 31200
#跨服灵草园
Def_FBMapID_CrossGrasslandLing = 32040
#跨服仙草园
Def_FBMapID_CrossGrasslandXian = 32050
#需要刷世界BOSS的副本
WorldBossFBMapIDList = [Def_FBMapID_SealDemon, Def_FBMapID_ZhuXianBoss, Def_FBMapID_DemonKing]
#跨服地图
Def_CrossMapIDList = [Def_FBMapID_CrossRealmPK, Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing]
Def_CrossMapIDList = [Def_FBMapID_CrossRealmPK, Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
#跨服分区类型配置, 没配置的默认 CrossZoneComm
Def_CrossZoneTypeName = {Def_FBMapID_CrossPenglai:"CrossZoneComm",
                         Def_FBMapID_CrossDemonKing:"CrossZonePK",
                         Def_FBMapID_CrossGrasslandLing:"CrossZonePK",
                         Def_FBMapID_CrossGrasslandXian:"CrossZonePK",
                         }
#跨服分区对应地图配置表名
Def_CrossZoneMapTableName = {Def_FBMapID_CrossPenglai:"CrossPenglaiZoneMap",
                             }
#需要动态分配线路的跨服地图
Def_CrossDynamicLineMap = [Def_FBMapID_CrossDemonKing]
Def_CrossDynamicLineMap = [Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
#同系职业枚举
JOB_TYPY_COUNT = 5
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBoss.py
@@ -26,6 +26,7 @@
import CrossRealmMsg
import ShareDefine
import PyGameData
import PlayerFB
import time
@@ -65,11 +66,7 @@
    
    # 动态线路分配的
    elif dataMapID in ChConfig.Def_CrossDynamicLineMap:
        zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(dataMapID, {}) # {dataMapID:{(zoneID, funcLineID):[mapID, copyMapID], ...}, ...}
        for zoneLineInfo, mapCopyInfo in zoneLineDict.items():
            if realMapID == mapCopyInfo[0] and copyMapID == mapCopyInfo[1]:
                return zoneLineInfo[0]
        return 0
        return PlayerFB.GetCrossDynamicLineZoneID(dataMapID, realMapID, copyMapID)
    return 0
def __GetCrossBossRecData(zoneID, bossID):
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -92,7 +92,7 @@
            PlayerQuery.ClientServerMsg_QueryNPCInfo(serverGroupID, msgData)
            
        elif msgType == ShareDefine.ClientServerMsg_EnterFB:
            PlayerFB.ClientServerMsg_EnterFB(serverGroupID, msgData)
            PlayerFB.ClientServerMsg_EnterFB(serverGroupID, msgData, tick)
            
        elif msgType == ShareDefine.ClientServerMsg_SetPlayerAttrValue:
            MapServer_CrossSetPlayerAttrValue(msgData)
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -61,6 +61,7 @@
import IPY_PlayerDefine
import CrossRealmPK
import AuctionHouse
import PlayerFB
#---------------------------------------------------------------------
#---------------------------------------------------------------------
@@ -490,6 +491,9 @@
#  @remarks 函数详细说明.
def __Func_PlayerDisconnect(curPlayer, tick):
    
    if GameWorld.IsCrossServer():
        PlayerFB.OnPlayerDisconnectCrossServer(curPlayer)
    #跨服匹配PK
    CrossRealmPK.OnLeaveServer(curPlayer)
    
@@ -753,6 +757,9 @@
    #改到mapServer登录成功通知
    #Sync_PyServerDataTimeToClient(curPlayer, tick)
    
    if GameWorld.IsCrossServer():
        PlayerFB.PlayerLoginLoadCrossMapOK(curPlayer)
    PlayerTeam.OnPlayerReadMapOK(curPlayer, tick)
    
    #刷新人物日期状态
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
@@ -38,6 +38,52 @@
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)
@@ -76,31 +122,35 @@
            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]
@@ -130,32 +180,57 @@
        
    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:
@@ -164,50 +239,54 @@
        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]
@@ -220,26 +299,29 @@
        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):
@@ -249,14 +331,61 @@
    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: 请求回调名
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -518,8 +518,8 @@
        return
    
    if callName == "DynamicLineMapClose":
        realMapID, copyMapID = eval(resultName)
        PlayerFB.OnCrossDynamicLineClose(realMapID, copyMapID)
        realMapID, copyMapID, funcLineDataCache = eval(resultName)
        PlayerFB.OnCrossDynamicLineClose(realMapID, copyMapID, funcLineDataCache)
        return
    
    if callName == "DynamicLineMapInitOK":
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -101,7 +101,6 @@
g_crossSetPlayerAttr = {} # 跨服玩家更新玩家数据 {playerID:[[setType, setDict], ...], ...}
g_crossMapCopyMapCountDict = {} # 跨服地图动态分配虚拟线路条数信息 {mapID:copyMapCount, ...}
g_crossDynamicLineInfo = {} # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[mapID, copyMapID], ...}, ...}
g_crossDynamicLineOpeningInfo = {} # 跨服动态线路正在开启中的线路信息 {mapID:{copyMapID:{playerID:serverGroupID, ...}, ...}, ...}
g_crossDynamicLineInfo = {} # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...}
g_crossDynamicLineCopyMapInfo = {} # 跨服动态线路虚拟线路信息 {(mapID, copyMapID):CrossCopyMapInfo, ...}
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1784,16 +1784,20 @@
Def_FBMapID_HorsePetBoss = 31200
#缥缈宝藏
Def_FBMapID_FairyTreasure = 31190
#跨服灵草园
Def_FBMapID_CrossGrasslandLing = 32040
#跨服仙草园
Def_FBMapID_CrossGrasslandXian = 32050
#注册上传跨服服务器数据后直接进入跨服服务器的地图
RegisterEnter_CrossServerMapIDList = [Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing]
RegisterEnter_CrossServerMapIDList = [Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
#跨服地图
Def_CrossMapIDList = [Def_FBMapID_CrossRealmPK, Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing]
Def_CrossMapIDList = [Def_FBMapID_CrossRealmPK, Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
#跨服分区对应地图配置表名
Def_CrossZoneMapTableName = {Def_FBMapID_CrossPenglai:"CrossPenglaiZoneMap",
                             }
#需要动态分配线路的跨服地图
Def_CrossDynamicLineMap = [Def_FBMapID_CrossDemonKing]
Def_CrossDynamicLineMap = [Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
#副本关闭时未拾取的物品邮件发放给玩家
#这里只有需要的副本才配置,不做默认逻辑,防止某些副本实际不能给导致刷物品,如麒麟之府
@@ -1885,6 +1889,7 @@
                'XMZZ':[Def_FBMapID_XMZZ], #仙魔之争
                'CrossRealmPK':[Def_FBMapID_CrossRealmPK], #跨服竞技场
                'CrossDemonKing':[Def_FBMapID_DemonKing, Def_FBMapID_CrossDemonKing], #妖王
                'CrossGrassland':[Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian], #草园
                'GatherSoul':[Def_FBMapID_GatherSoul],#聚魂副本
                'ZhuXianBoss':[Def_FBMapID_ZhuXianBoss],#诛仙BOSS
                'ZhuXianTower':[Def_FBMapID_ZhuXianTower],#诛仙塔
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossDemonKing.py
@@ -60,13 +60,14 @@
def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
    return ipyEnterPosInfo
def GetCurFBLineBOSSID(lineID=-1):
def GetCurFBLineBOSSID(mapID=-1, lineID=-1):
    #该分线刷的BOSSID
    if mapID == -1:
        mapID = ChConfig.Def_FBMapID_CrossDemonKing if GameWorld.IsCrossServer() else ChConfig.Def_FBMapID_DemonKing
    if lineID == -1:
        lineID = GetCurFBFuncLineID()
    if lineID == -1:
    if mapID == -1 or lineID == -1:
        return 0
    mapID = ChConfig.Def_FBMapID_CrossDemonKing if GameWorld.IsCrossServer() else ChConfig.Def_FBMapID_DemonKing
    ipyData = IpyGameDataPY.GetIpyGameDataByCondition("FairyDomain", {"MapID":mapID, "LineID":lineID})
    if not ipyData:
        return 0
@@ -76,13 +77,13 @@
def GetCurFBFuncLineID():
    ## 获取本线路功能线路ID
    if GameWorld.IsCrossServer():
        return GameWorld.GetGameWorld().GetPropertyID() % 1000
        return GameWorld.GetGameWorld().GetPropertyID() % 10000 / 10
    return GameWorld.GetGameWorld().GetPropertyID() - 1
def GetCurFBLineZoneID():
    ## 获取本线路所属跨服分区
    if GameWorld.IsCrossServer():
        return GameWorld.GetGameWorld().GetPropertyID() / 1000
        return GameWorld.GetGameWorld().GetPropertyID() / 10000
    return 0
## 进副本
@@ -90,7 +91,7 @@
    playerID = curPlayer.GetPlayerID()
    zoneID = GetCurFBLineZoneID()
    funcLineID = GetCurFBFuncLineID()
    bossID = GetCurFBLineBOSSID(funcLineID)
    bossID = GetCurFBLineBOSSID(lineID=funcLineID)
    visitCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FairyDomainVisitCnt)
    GameWorld.Log("DoEnterFB zoneID=%s,funcLineID=%s,bossID=%s,visitCount=%s" % (zoneID, funcLineID, bossID, visitCount), playerID)
    PyGameData.g_fbPickUpItemDict.pop(playerID, 0)
@@ -154,7 +155,7 @@
def __FBNPCOnKilled(curNPC, tick):
    bossID = curNPC.GetNPCID()
    funcLineID = GetCurFBFuncLineID()
    if bossID != GetCurFBLineBOSSID(funcLineID):
    if bossID != GetCurFBLineBOSSID(lineID=funcLineID):
        return
    
    zoneID = GetCurFBLineZoneID()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossGrassland.py
New file
@@ -0,0 +1,16 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.GameLogic_CrossGrassland
#
# @todo:跨服草园
# @author hxp
# @date 2019-04-15
# @version 1.0
#
# 详细描述: 跨服草园
#
#-------------------------------------------------------------------------------
#"""Version = 2019-04-15 16:30"""
#-------------------------------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
@@ -172,7 +172,10 @@
    FreeOrClearFBByAutoSize(gameWorld)
    
    if gameWorld.GetMapID() in ChConfig.Def_CrossDynamicLineMap:
        msgInfo = str([gameWorld.GetRealMapID(), gameWorld.GetCopyMapID()])
        realMapID, copyMapID = gameWorld.GetRealMapID(), gameWorld.GetCopyMapID()
        key = (mapID, copyMapID)
        funcLineDataCache = PyGameData.g_crossFuncLineDataCache.pop(key, None)
        msgInfo = str([realMapID, copyMapID, funcLineDataCache])
        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "DynamicLineMapClose", msgInfo, len(msgInfo))
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -1630,7 +1630,7 @@
    if mapID in ChConfig.Def_CrossDynamicLineMap:
        extendInfo = {}
        if mapID == ChConfig.Def_FBMapID_CrossDemonKing:
            bossID = GameLogic_CrossDemonKing.GetCurFBLineBOSSID(lineID)
            bossID = GameLogic_CrossDemonKing.GetCurFBLineBOSSID(mapID, lineID)
            if not bossID:
                return
            extendInfo["BossID"] = bossID
@@ -1738,7 +1738,7 @@
                if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ZhuXianBossHelpCnt):
                    extendParamList = [bossID, curPlayer.GetFamilyID()]
        elif mapID == ChConfig.Def_FBMapID_DemonKing:
            bossID = GameLogic_CrossDemonKing.GetCurFBLineBOSSID(lineID)
            bossID = GameLogic_CrossDemonKing.GetCurFBLineBOSSID(mapID, lineID)
            extendParamList = [bossID]
            
        SendToGameServerEnterFB(curPlayer, mapID, lineID, tick, extendParamList)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_OpenFB.py
@@ -17,6 +17,7 @@
import GameWorld
import IPY_GameWorld
import PyGameData
#逻辑实现
@@ -28,7 +29,7 @@
#  @return "True" or "False" or ""
#  @remarks 函数详细说明.
def DoLogic(query_Type, query_ID, paramList, tick):
    copyMapID, propertyID = paramList
    copyMapID, propertyID, funcLineDataCache = paramList
    
    gameWorldManager = GameWorld.GetGameWorld()
    maxCopyCount = gameWorldManager.GetGameWorldCount()
@@ -51,6 +52,10 @@
    GameWorld.Log("GY_Query_OpenFB copyMapID=%s, propertyID=%s" % (copyMapID, propertyID))
    tagGameWorld.SetFBFirstOpen(1) # 开启副本
    tagGameWorld.SetPropertyID(propertyID)
    if funcLineDataCache:
        mapID = gameWorldManager.GetRealMapID()
        key = (mapID, copyMapID)
        PyGameData.g_crossFuncLineDataCache[key] = funcLineDataCache
    return ''
                
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -101,3 +101,5 @@
g_horsePetBossPlayerHurtDict = {} #骑宠boss信息 {lineID:{playerID:[playerName,hurt]}}
g_customFBPrizeInfo = {} #自定义副本奖励 {playerID:[mapID, funcLineID, [奖励物品列表], ...}
g_crossFuncLineDataCache = {} # 动态分配的跨服虚拟分线数据缓存 {(mapID, copyMapID):funcLineDataCache, ...}