| #!/usr/bin/python  | 
| # -*- coding: GBK -*-  | 
| #---------------------------------------------------------------------  | 
| #  | 
| #---------------------------------------------------------------------  | 
| ##@package PlayerFB  | 
| # @todo: Íæ¼Ò¸±±¾  | 
| #  | 
| # @author: hxp  | 
| # @date 2013-08-23  | 
| # @version 1.5  | 
| #  | 
| # @note  | 
| # @change: "2014-04-16 18:00" hxp Ôö¼Ó¼Ò×åboss¸±±¾½øÈëÅÐ¶Ï  | 
| # @change: "2015-01-09 10:30" hxp ¸ÄΪGetRouteServerIndex  | 
| # @change: "2015-03-20 15:00" hxp Ìõ¼þÅжÏÐÞ¸Ä  | 
| # @change: "2015-10-22 23:00" hxp Ôö¼Ó¿ç·þPK  | 
| # @change: "2017-01-04 12:00" hxp Ôö¼ÓÒì½çÈëÇÖ  | 
| #---------------------------------------------------------------------  | 
| #"""Version = 2017-01-04 12:00"""  | 
| #---------------------------------------------------------------------  | 
| import GameWorldBoss  | 
| import PlayerFamilyBoss  | 
| import PlayerHorsePetBoss  | 
| import GameWorldFamilyWar  | 
| import PlayerControl  | 
| import PyGameData  | 
| import IpyGameDataPY  | 
| import PlayerDBGSEvent  | 
| import PlayerTeam  | 
| import GameWorld  | 
| import ChConfig  | 
| import IPY_PlayerDefine  | 
| import CrossRealmPlayer  | 
| import CrossRealmMsg  | 
| import ShareDefine  | 
| import CrossBoss  | 
|   | 
| #---------------------------------------------------------------------  | 
|   | 
| ## ¿ç·þµØÍ¼¶¯Ì¬·ÖÅäµÄ¹¦ÄÜÏß·£¬Èç¹ûÓÐÈËÊýÉÏÏ޵ģ¬Ôòͬ·ÖÇøÍ¬µØÍ¼Íæ·¨µÄ¿ÉÄÜͬʱ´æÔÚ¶à¸öÏàͬ¹¦ÄÜÏß·µÄÊý¾Ý  | 
| class CrossFuncLineInfo():  | 
|       | 
|     def __init__(self):  | 
|         self.realMapID = 0  | 
|         self.copyMapID = 0  | 
|         self.funcLineDataCache = None # ¹¦ÄÜÏß·×Ô¶¨Ò建´æÊý¾Ý  | 
|         return  | 
|       | 
|     def OnCopyMapClose(self):  | 
|         self.realMapID = 0  | 
|         self.copyMapID = 0  | 
|         return  | 
|   | 
| ## ¿ç·þµØÍ¼¶¯Ì¬·ÖÅäµÄÐéÄâÏß·ÐÅÏ¢  | 
| class CrossCopyMapInfo():  | 
|       | 
|     def __init__(self, zoneID, funcLineID):  | 
|         self.zoneID = zoneID  | 
|         self.funcLineID = funcLineID  | 
|         self.openState = IPY_PlayerDefine.fbosClosed  | 
|         self.fbPlayerDict = {} # ¸±±¾ÖеÄÍæ¼ÒÐÅÏ¢ {playerID:serverGroupID, ...}  | 
|         self.waitPlayerDict = {} # µÈ´ý½øÈëµÄÍæ¼ÒÐÅÏ¢ {playerID:[serverGroupID, tick], ...}  | 
|         self.offlinePlayerDict = {} # µôÏßµÄÍæ¼ÒÐÅÏ¢£¬·ÇÖ÷¶¯Í˳öµÄ {playerID:serverGroupID, ...}  | 
|         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)  | 
|     fbLineIpyData = IpyGameDataPY.GetIpyGameDataNotLog("FBLine", mapID, lineID)  | 
|     if not fbLineIpyData and isDefaultLine:  | 
|         #GameWorld.DebugLog("ûÓÐÖ¸¶¨¹¦ÄÜÏß·µÄÔòĬÈÏÈ¡0£¬ÔÙûÓеϰ¾ÍÊDz»ÐèÒªµÄmapID=%s, lineID=%s" % (mapID, lineID))  | 
|         fbLineIpyData = IpyGameDataPY.GetIpyGameDataNotLog("FBLine", mapID, 0)  | 
|     return fbLineIpyData  | 
|   | 
| ## »ñÈ¡¼Ç¼ֵµÄmapID  | 
| #  @param mapID ËùÒª²éµÄmapID  | 
| #  @return  | 
| #  @remarks Ò»°ãÓÃÓÚ¼¸ÕŵØÍ¼¹«ÓÃÒ»·Ý´æ´¢¼Ç¼£¬Èç×é¶Ó¸±±¾½øÈë´ÎÊý£¬CDʱ¼äµÈÊý¾ÝÐè¹²Ïí  | 
| def GetRecordMapID(mapID):  | 
|     DataMapIDDict = IpyGameDataPY.GetConfigEx("DataMapIDDict")  | 
|     if not DataMapIDDict:  | 
|         dMapIDDict = {}  | 
|         ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|         for i in xrange(ipyDataMgr.GetFBLineCount()):  | 
|             ipyData = ipyDataMgr.GetFBLineByIndex(i)  | 
|             dMapID = ipyData.GetDataMapID()  | 
|             mID = ipyData.GetMapID()  | 
|             dMapIDList= dMapIDDict.get(dMapID, [])  | 
|             if mID not in dMapIDList:  | 
|                 dMapIDList.append(mID)  | 
|                 dMapIDDict[dMapID] = dMapIDList  | 
|               | 
|         for dMapID in dMapIDDict.keys():  | 
|             if len(dMapIDDict[dMapID]) == 1:  | 
|                 dMapIDDict.pop(dMapID)  | 
|         DataMapIDDict = IpyGameDataPY.SetConfigEx("DataMapIDDict", dMapIDDict)  | 
|         #GameWorld.Log("¼ÓÔØDataMapIDDict=%s" % DataMapIDDict)  | 
|           | 
|     for dataMapID, mapIDList in DataMapIDDict.items():  | 
|         if mapID in mapIDList:  | 
|             return dataMapID  | 
|     return mapID  | 
|   | 
| def ClientServerMsg_EnterFB(serverGroupID, msgData, tick):  | 
|     ## ÊÕµ½×Ó·þÇëÇó½øÈ붯̬·ÖÅäµÄ¿ç·þ¸±±¾  | 
|     playerID = msgData["PlayerID"]  | 
|     mapID = msgData["MapID"]  | 
|     funcLineID = msgData["FuncLineID"]  | 
|       | 
|     zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByServerGroupID(mapID, serverGroupID)  | 
|     if not zoneIpyData:  | 
|         return  | 
|     zoneID = zoneIpyData.GetZoneID()  | 
|       | 
|     dynamicLineMaxPlayerCountDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 2)  | 
|     copyMapPlayerMax = dynamicLineMaxPlayerCountDict.get(mapID, 0) # 0Ϊ²»ÏÞÖÆÈËÊý£¬Ä¬Èϲ»ÏÞÖÆ  | 
|     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))  | 
|             return  | 
|           | 
|     elif mapID in [ChConfig.Def_FBMapID_CrossGrasslandLing, ChConfig.Def_FBMapID_CrossGrasslandXian]:  | 
|         pass  | 
|           | 
|     else:  | 
|         return  | 
|       | 
|     mapCopyLineInfo = __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, tick)  | 
|     if not mapCopyLineInfo:  | 
|         return  | 
|     realMapID, copyMapID, openState = mapCopyLineInfo  | 
|     if openState != IPY_PlayerDefine.fbosOpen:  | 
|         return  | 
|       | 
|     playerIDList = [playerID]  | 
|     retInfo = [playerIDList, mapID, realMapID, copyMapID, funcLineID]  | 
|     CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID])  | 
|     return  | 
|   | 
| def CrossServerMsg_EnterFBRet(msgData, tick):  | 
|     ## ÊÕµ½¿ç·þ·þÎñÆ÷¶¯Ì¬·ÖÅäµÄ¿ç·þ¸±±¾½øÈëÐÅÏ¢  | 
|       | 
|     playerIDList, dataMapID, mapID, copyMapID, funcLineID = msgData  | 
|       | 
|     for playerID in playerIDList:  | 
|         curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)  | 
|         if not curPlayer:  | 
|             continue  | 
|         CrossRealmPlayer.SendCrossRealmReg(curPlayer, dataMapID, mapID, dataMapID, copyMapID, lineID=funcLineID)  | 
|           | 
|     return  | 
|   | 
| def __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, tick):  | 
|     '''»ñÈ¡¿ç·þ·ÖÇø¶ÔÓ¦¶¯Ì¬·ÖÅäµÄ¸±±¾µØÍ¼ÐéÄâÏß·ÐÅÏ¢, ÓÉÓÚÐèÒªÖ§³Ö¶àµØÍ¼·ÖÁ÷£¬ËùÒÔÖ±½ÓÓÉGameServer¹ÜÀí·ÖÅä  | 
|             Ã¿¸ö¹¦ÄÜÏß·֧³Ö°´ÈËÊý·ÖÁ÷£¬³¬¹ý×î´óÈËÊýºó¿É¿ªÆôÒ»ÌõÏàͬ¹¦ÄÜÏß·µÄÐéÄâÏß·½øÐзÖÁ÷£¬ËùÒÔͬһ·ÖÇøÍ¬Ò»µØÍ¼µÄ¹¦ÄÜÏß·ID¿ÉÄܶÔÓ¦¶àÌõÐéÄâÏß·  | 
|     '''  | 
|       | 
|     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]  | 
|       | 
|     newFuncLineNum = None  | 
|     newFuncLineObj = None  | 
|     for index, funcLineObj in enumerate(funcLineObjList, 1):  | 
|         realMapID, copyMapID = funcLineObj.realMapID, funcLineObj.copyMapID  | 
|         if not realMapID:  | 
|             if not newFuncLineObj:  | 
|                 newFuncLineNum, newFuncLineObj = index, funcLineObj  | 
|             continue  | 
|           | 
|         key = (realMapID, copyMapID)  | 
|         if key not in PyGameData.g_crossDynamicLineCopyMapInfo:  | 
|             GameWorld.ErrLog("ÒѾ·ÖÅäµÄÐéÄâÏß·²»´æÔÚ»º´æ¶ÔÓ¦¹ØÏµÀzoneID=%s,funcLineID=%s,realMapID=%s,copyMapID=%s"   | 
|                              % (zoneID, funcLineID, realMapID, copyMapID))  | 
|             continue  | 
|           | 
|         copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]  | 
|         openState = copyMapObj.openState  | 
|         if openState == IPY_PlayerDefine.fbosWaitForClose:  | 
|             if not copyMapPlayerMax:  | 
|                 PlayerControl.CrossNotifyCode(serverGroupID, playerID, "HazyRegionClose")  | 
|                 return  | 
|             #GameWorld.DebugLog("    ÐéÄâÏß·µÈ´ý¹Ø±ÕÖÐ! index=%s,realMapID=%s,copyMapID=%s" % (index, 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  | 
|           | 
|     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):  | 
|             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))  | 
|         return  | 
|       | 
|     if newFuncLineObj == None:  | 
|         newFuncLineObj = CrossFuncLineInfo()  | 
|         funcLineObjList.append(newFuncLineObj)  | 
|         newFuncLineNum = len(funcLineObjList)  | 
|     realMapID, copyMapID = openMapID, openCopyMapID  | 
|     newFuncLineObj.realMapID = realMapID  | 
|     newFuncLineObj.copyMapID = copyMapID  | 
|     funcLineDataCache = newFuncLineObj.funcLineDataCache  | 
|       | 
|     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))  | 
|       | 
|     # Í¨ÖªµØÍ¼¿ªÆôеĵØÍ¼ÐéÄâ·ÖÏß  | 
|     msgInfo = str([copyMapID, propertyID, funcLineDataCache])  | 
|     GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, realMapID, "OpenFB", msgInfo, len(msgInfo))  | 
|     return realMapID, copyMapID, openState  | 
|   | 
| def GetCrossDynamicLineZoneID(mapID, realMapID, copyMapID):  | 
|     ## »ñÈ¡¿ç·þ¶¯Ì¬·ÖÅäµÄÐéÄâÏß·¶ÔÓ¦·ÖÇøID  | 
|     zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {})  | 
|     for key, funcLineObjList in zoneLineDict.items():  | 
|         for funcLineObj in funcLineObjList:  | 
|             if funcLineObj.realMapID == realMapID and funcLineObj.copyMapID == copyMapID:  | 
|                 zoneID = key[0]  | 
|                 return zoneID  | 
|     return 0  | 
|   | 
| def OnCrossDynamicLineStateChange(msgList):  | 
|     realMapID, copyMapID, state = msgList[:3]  | 
|       | 
|     if state == IPY_PlayerDefine.fbosWaitForClose:  | 
|         funcLineDataCache = msgList[3]  | 
|         OnCrossDynamicLineWaitForClose(realMapID, copyMapID, funcLineDataCache)  | 
|     elif state == IPY_PlayerDefine.fbosClosed:  | 
|         OnCrossDynamicLineClose(realMapID, copyMapID)  | 
|     elif state == IPY_PlayerDefine.fbosOpen:  | 
|         OnCrossDynamicLineOpen(realMapID, copyMapID)  | 
|           | 
|     return  | 
|   | 
| def OnCrossDynamicLineOpen(realMapID, copyMapID):  | 
|     ## ¶¯Ì¬·ÖÅäÏß·µÄµØÍ¼ÐéÄâÏß·Æô¶¯³É¹¦  | 
|       | 
|     key = (realMapID, copyMapID)  | 
|     if key not in PyGameData.g_crossDynamicLineCopyMapInfo:  | 
|         return  | 
|     copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]  | 
|     copyMapObj.openState = IPY_PlayerDefine.fbosOpen  | 
|     funcLineID = copyMapObj.funcLineID  | 
|       | 
|     # Í¨Öª×Ó·þµÈ´ýÖеÄÍæ¼Ò¿ÉÒÔ½øÈ븱±¾  | 
|     serverPlayerIDListDict = {}  | 
|     for playerID, playerInfo in copyMapObj.waitPlayerDict.items():  | 
|         serverGroupID = playerInfo[0]  | 
|         if serverGroupID not in serverPlayerIDListDict:  | 
|             serverPlayerIDListDict[serverGroupID] = []  | 
|         playerIDList = serverPlayerIDListDict[serverGroupID]  | 
|         playerIDList.append(playerID)  | 
|           | 
|     mapID = GetRecordMapID(realMapID)  | 
|     GameWorld.Log("¶¯Ì¬·ÖÅäÐéÄâÏß·Æô¶¯³É¹¦£¬Í¨Öª×Ó·þµÈ´ýÍæ¼Ò¿É½øÈë: mapID=%s,realMapID=%s,copyMapID=%s,serverPlayerIDListDict=%s"   | 
|                   % (mapID, realMapID, copyMapID, serverPlayerIDListDict))  | 
|     for serverGroupID, playerIDList in serverPlayerIDListDict.items():  | 
|         retInfo = [playerIDList, mapID, realMapID, copyMapID, funcLineID]  | 
|         CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID])  | 
|           | 
|     #GameWorld.DebugLog("    PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)  | 
|     #GameWorld.DebugLog("    PyGameData.g_crossDynamicLineCopyMapInfo=%s" % PyGameData.g_crossDynamicLineCopyMapInfo)  | 
|     return  | 
|   | 
| def OnCrossDynamicLineWaitForClose(realMapID, copyMapID, funcLineDataCache):  | 
|     ## ¶¯Ì¬·ÖÅäÏß·µÄµØÍ¼ÐéÄâÏß·¹Ø±Õ  | 
|           | 
|     mapID = GetRecordMapID(realMapID)  | 
|     GameWorld.Log("¶¯Ì¬·ÖÅäÐéÄâÏß·µÈ´ý¹Ø±Õ mapID=%s,realMapID=%s,copyMapID=%s,funcLineDataCache=%s" % (mapID, realMapID, copyMapID, funcLineDataCache))  | 
|     zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {})   | 
|     for key, funcLineObjList in zoneLineDict.items():  | 
|         for funcLineObj in funcLineObjList:  | 
|             if funcLineObj.realMapID == realMapID and funcLineObj.copyMapID == copyMapID:  | 
|                 funcLineObj.funcLineDataCache = funcLineDataCache  | 
|                 zoneID, funcLineID = key  | 
|                 GameWorld.Log("    ·ÖÇø¶ÔÓ¦¹¦ÄÜÏß·ÐéÄâ·ÖÏߵȴý¹Ø±Õ: zoneID=%s,mapID=%s,funcLineID=%s" % (zoneID, mapID, funcLineID))  | 
|                 break  | 
|       | 
|     key = (realMapID, copyMapID)  | 
|     if key in PyGameData.g_crossDynamicLineCopyMapInfo:  | 
|         copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]  | 
|         copyMapObj.openState = IPY_PlayerDefine.fbosWaitForClose  | 
|           | 
|     #GameWorld.DebugLog("    PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)  | 
|     #GameWorld.DebugLog("    PyGameData.g_crossDynamicLineCopyMapInfo=%s" % PyGameData.g_crossDynamicLineCopyMapInfo)  | 
|     return  | 
|   | 
| def OnCrossDynamicLineClose(mapID, copyMapID):  | 
|     ## ¶¯Ì¬·ÖÅäÏß·µÄµØÍ¼ÐéÄâÏß·¹Ø±Õ  | 
|       | 
|     dataMapID = GetRecordMapID(mapID)  | 
|     GameWorld.Log("¶¯Ì¬·ÖÅäÐéÄâÏß·¹Ø±Õ dataMapID=%s,mapID=%s,copyMapID=%s" % (dataMapID, mapID, copyMapID))  | 
|     zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(dataMapID, {})   | 
|     for key, funcLineObjList in zoneLineDict.items():  | 
|         for funcLineObj in funcLineObjList:  | 
|             if funcLineObj.realMapID == mapID and funcLineObj.copyMapID == copyMapID:  | 
|                 funcLineObj.OnCopyMapClose()  | 
|                 zoneID, funcLineID = key  | 
|                 GameWorld.Log("    ·ÖÇø¶ÔÓ¦¹¦ÄÜÏß·ÐéÄâ·ÖÏ߹رÕ: zoneID=%s,dataMapID%s,funcLineID=%s" % (zoneID, dataMapID, funcLineID))  | 
|                 break  | 
|       | 
|     key = (mapID, copyMapID)  | 
|     copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo.pop(key, None)  | 
|     if not copyMapObj:  | 
|         return  | 
|     #GameWorld.DebugLog("    PyGameData.g_crossDynamicLineInfo=%s" % PyGameData.g_crossDynamicLineInfo)  | 
|     #GameWorld.DebugLog("    PyGameData.g_crossDynamicLineCopyMapInfo=%s" % PyGameData.g_crossDynamicLineCopyMapInfo)  | 
|       | 
|     playerCount = 0  | 
|     zoneID = copyMapObj.zoneID  | 
|     funcLineID = copyMapObj.funcLineID  | 
|     playerCountInfo = [playerCount]  | 
|     SyncClientServerCrossFBFuncLinePlayerCount(zoneID, mapID, funcLineID, playerCountInfo)  | 
|       | 
|     #Èç¹ûÐéÄâ·ÖÏ߹رÕʱ£¬ÓеôÏßµÄÍæ¼Ò£¬Ôò֪ͨ×Ó·þÖØÖÃÕâÐ©Íæ¼ÒµÄ¿ç·þ״̬  | 
|     for playerID, serverGroupID in copyMapObj.offlinePlayerDict.items():  | 
|         CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ExitCrossServer, playerID, [serverGroupID])  | 
|           | 
|     return  | 
|   | 
| def OnCrossDynamicMapReset(msgList):  | 
|     ## ¶¯Ì¬·ÖÅäÏß·µÄµØÍ¼ÖØÖà  | 
|     realMapID, copyMapCount = msgList  | 
|     mapID = GetRecordMapID(realMapID)  | 
|     GameWorld.Log("¶¯Ì¬·ÖÅäÐéÄâÏß·µØÍ¼ÖØÖàmapID=%s,realMapID=%s,copyMapCount=%s" % (mapID, realMapID, copyMapCount))  | 
|     PyGameData.g_crossMapCopyMapCountDict[realMapID] = copyMapCount  | 
|       | 
|     zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {})  | 
|     for key, funcLineObjList in zoneLineDict.items():  | 
|         for funcLineObj in funcLineObjList:  | 
|             if funcLineObj.realMapID == realMapID:  | 
|                 funcLineObj.OnCopyMapClose()  | 
|               | 
|     for key in PyGameData.g_crossDynamicLineCopyMapInfo.keys():  | 
|         if key[0] == realMapID:  | 
|             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.offlinePlayerDict.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)  | 
|     #GameWorld.DebugLog("    ÀëÏßÖеÄÍæ¼ÒID: %s" % copyMapObj.offlinePlayerDict)  | 
|       | 
|     playerCount = len(copyMapObj.fbPlayerDict) # µÈ´ý½øÈëµÄÔÝʱ²»Ëã  | 
|     zoneID = copyMapObj.zoneID  | 
|     funcLineID = copyMapObj.funcLineID  | 
|     playerCountInfo = [playerCount]  | 
|     SyncClientServerCrossFBFuncLinePlayerCount(zoneID, mapID, funcLineID, playerCountInfo)  | 
|     return  | 
|   | 
| def SyncClientServerCrossFBFuncLinePlayerCount(zoneID, mapID, funcLineID, playerCountInfo):  | 
|     ## Í¬²½×Ó·þ¿ç·þ¸±±¾¹¦ÄÜÏß·ÈËÊý  | 
|     ## ×¢Ò⣺ ´ËÈËÊý²»ÊÇÒ»¸ö¾«È·ÈËÊýÖµ£¬Ö»ÊÇÒ»¸ö´ó¸ÅÈËÊýÖµ£¬²»Óúܾ«È·£¬ÔÝÊ±Ö»Íæ¼Ò½øÈëʱͬ²½ÈËÊýÐÅÏ¢£¬Íæ¼ÒÍ˳öÔݲ»´¦Àí   | 
|     mapID = GetRecordMapID(mapID)  | 
|     if mapID not in ChConfig.Def_NeedCountFBFuncLinePlayerCrossMap:  | 
|         return  | 
|     zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(mapID, zoneID)  | 
|     if not zoneIpyData:  | 
|         return  | 
|     serverGroupIDList = zoneIpyData.GetServerGroupIDList()  | 
|     playerCountInfo = [mapID, funcLineID, playerCountInfo]  | 
|     CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FBPlayerCount, playerCountInfo, serverGroupIDList)  | 
|     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)  | 
|       | 
|     crossMapID = PlayerControl.GetCrossMapID(curPlayer)  | 
|     # ²»ÊÇÖ÷¶¯Í˳öµÄ  | 
|     if crossMapID:  | 
|         copyMapObj.offlinePlayerDict[playerID] = PlayerControl.GetPlayerServerGroupID(curPlayer)  | 
|       | 
|     #GameWorld.DebugLog("Íæ¼ÒÍ˳ö¶¯Ì¬·ÖÅäµÄ¿ç·þµØÍ¼: GetMapID=%s,GetRealMapID=%s,GetFBID()=%s,crossMapID=%s"   | 
|     #                   % (curPlayer.GetMapID(), mapID, copyMapID, crossMapID), playerID)  | 
|     #GameWorld.DebugLog("    ¸±±¾ÖеÄÍæ¼ÒID: %s" % copyMapObj.fbPlayerDict)  | 
|     #GameWorld.DebugLog("    µÈ´ýÖеÄÍæ¼ÒID: %s" % copyMapObj.waitPlayerDict)  | 
|     #GameWorld.DebugLog("    ÀëÏßÖеÄÍæ¼ÒID: %s" % copyMapObj.offlinePlayerDict)  | 
|     return  | 
|   | 
| def CrossServerMsg_FBPlayerCount(msgData):  | 
|     ## ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¸±±¾¹¦ÄÜÏß·ÈËÊýÐÅÏ¢  | 
|       | 
|     mapID, funcLineID, playerCountInfo = msgData  | 
|     if mapID not in PyGameData.g_crossFBFuncLinePlayerCountInfo:  | 
|         PyGameData.g_crossFBFuncLinePlayerCountInfo[mapID] = {}  | 
|     fbLinePlayerInfoDict = PyGameData.g_crossFBFuncLinePlayerCountInfo[mapID]  | 
|     fbLinePlayerInfoDict[funcLineID] = playerCountInfo  | 
|     return  | 
|   | 
| ##--------------------------------------------------------------------------------------------------  | 
|   | 
| ## ÇëÇó½øÈ븱±¾·ÖÏß  | 
| #  @param curPlayer: ÇëÇóÍæ¼Ò  | 
| #  @param queryCallName: ÇëÇ󻨵÷Ãû  | 
| #  @param sendCMD: ÇëÇóµÄÃüÁî ¸ù¾ÝÇëÇóÀàÐͺÍÇëÇóÃüÁîÀ´¾ö¶¨×îÖÕ²Ù×÷  | 
| #  @return None  | 
| def EnterFBLine(curPlayer, queryCallName, sendCMD, tick):  | 
|     GameWorld.Log("EnterFBLine()...queryCallName=%s,sendCMD=%s" % (queryCallName, sendCMD), curPlayer.GetPlayerID())  | 
|     playerManager = GameWorld.GetPlayerManager()  | 
|     try:  | 
|         mapInfo = eval(sendCMD)  | 
|     except Exception, e:  | 
|         GameWorld.ErrLog("EnterFBLine() sendCMD=%s error" % sendCMD)  | 
|         return  | 
|       | 
|     if not mapInfo or len(mapInfo) < 2:  | 
|         GameWorld.ErrLog("EnterFBLine() sendCMD=%s error!" % sendCMD)  | 
|         return  | 
|       | 
|     #if mapInfo and len(mapInfo) == 2:  | 
|     tagMapID = mapInfo[0]  | 
|     tagLineID = mapInfo[1]  | 
|       | 
|     fbLineIpyData = GetFBLineIpyData(tagMapID, tagLineID)  | 
|     sceneMapID = tagMapID if not fbLineIpyData else fbLineIpyData.GetMapID()  | 
|     gameMap = GameWorld.GetMap(sceneMapID)  | 
|     if not gameMap:  | 
|         GameWorld.ErrLog("Ä¿±ê¸±±¾µØÍ¼²»´æÔÚ!tagMapID=%s,sceneMapID=%s" % (tagMapID, sceneMapID), curPlayer.GetPlayerID())  | 
|         return  | 
|       | 
|     # ×é¶Ó¸±±¾, ÓжÓÎéµÄÇé¿ö²ÅÑéÖ¤ÆäËû¶ÓÔ±¿É·ñ½øÈ룬·ñÔò´ú±íµ¥È˽øÈë  | 
|     if gameMap.GetMapFBType() == ChConfig.fbtTeam:  | 
|         PlayerTeam.OnEnterFBTeamAsk(curPlayer, PlayerTeam.TeamFBAskType_Enter, tagMapID, tagLineID, tick)  | 
|         return  | 
|       | 
|     #·âħ̳¸±±¾ÅжÏÀïÃæµÄBOSSÊÇ·ñµ½ÁËË¢ÐÂʱ¼ä  | 
|     if tagMapID in ChConfig.WorldBossFBMapIDList:  | 
|         bossID = mapInfo[2]  | 
|         if not GameWorldBoss.GetBossIsAliveOrCanReborn(bossID):  | 
|             return  | 
|           | 
|     elif tagMapID == ChConfig.Def_FBMapID_FamilyWar:  | 
|         if not GameWorldFamilyWar.CheckPlayerCanEnterFamilyWarFBMap(curPlayer):  | 
|             return  | 
|           | 
|     elif tagMapID == ChConfig.Def_FBMapID_FamilyBossMap:  | 
|         if not PlayerFamilyBoss.CheckIsFamilyBossFBOpen(curPlayer.GetFamilyID(), tagMapID):  | 
|             GameWorld.Log("EnterFBLine mapID=%s is familyBossFB, but is not open!" % tagMapID)  | 
|             return  | 
|     #ÊØÎÀÈ˻ʠÊÇ·ñÒÑ²Î¼Ó  | 
|     elif tagMapID == ChConfig.Def_FBMapID_FamilyInvade:  | 
|         if curPlayer.GetFamilyID() in PyGameData.g_swrhJoinRecord:  | 
|             PlayerControl.NotifyCode(curPlayer, "TheEmperor1")  | 
|             return  | 
|     #¶àÏÉÃËBOSS ÊÇ·ñÒѽáÊø  | 
|     elif tagMapID == ChConfig.Def_FBMapID_AllFamilyBoss:  | 
|         if not PlayerFamilyBoss.IsInAllFamilyBoss(tagLineID):  | 
|             #»î¶¯Î´¿ªÆô  | 
|             return  | 
|         if PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_AllFamilyBossTime):  | 
|             #BOSSÒѱ»»÷ɱ  | 
|             return  | 
|     #Æï³èBOSS ÊÇ·ñÒѽáÊø  | 
|     elif tagMapID == ChConfig.Def_FBMapID_HorsePetBoss:  | 
|         if not PlayerHorsePetBoss.IsInHorsePetBoss():  | 
|             #»î¶¯Î´¿ªÆô  | 
|             return  | 
|         if PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_HorsePetBossTime % tagLineID):  | 
|             #BOSSÒѱ»»÷ɱ  | 
|             return  | 
|     # MapServer_QueryPlayer(int srcPlayerID, int queryType, int queryID, int mapID, char *callName, char *cmd,WORD cmdLen, int RouteServerIndex)  | 
|     playerManager.MapServer_QueryPlayer(curPlayer.GetPlayerID(), ChConfig.queryType_EnterFB, 0, tagMapID,  | 
|                 queryCallName, sendCMD, len(sendCMD), curPlayer.GetRouteServerIndex())  | 
|     return  |