| #!/usr/bin/python  | 
| # -*- coding: GBK -*-  | 
| #-------------------------------------------------------------------------------  | 
| #  | 
| ##@package CrossBoss  | 
| #  | 
| # @todo:¿ç·þboss  | 
| # @author hxp  | 
| # @date 2019-01-09  | 
| # @version 1.0  | 
| #  | 
| # ÏêϸÃèÊö: ¿ç·þboss  | 
| #  | 
| #-------------------------------------------------------------------------------  | 
| #"""Version = 2019-01-09 15:30"""  | 
| #-------------------------------------------------------------------------------  | 
|   | 
| import ChConfig  | 
| import GameWorld  | 
| import IpyGameDataPY  | 
| import ChPyNetSendPack  | 
| import CrossRealmPlayer  | 
| import DataRecordPack  | 
| import PlayerControl  | 
| import NetPackCommon  | 
| import CrossRealmMsg  | 
| import ShareDefine  | 
| import PyGameData  | 
|   | 
| import time  | 
|   | 
| '''  | 
| ShareDefine.Def_UniversalGameRecType_CrossBossInfo  | 
| value1:bossID  | 
| value2:killedTime  | 
| value4:refreshTime  | 
| value5:zoneID  | 
| StrValue3:"ʱ¼ä_Íæ¼ÒÃû|..."  | 
| '''  | 
|   | 
| def GetRecBossID(recData): return recData.GetValue1()  | 
| def SetRecBossID(recData, value): return recData.SetValue1(value)  | 
| def GetRecKilledTime(recData): return recData.GetValue2()  | 
| def SetRecKilledTime(recData, value): return recData.SetValue2(value)  | 
| def GetRecRefreshTime(recData): return recData.GetValue4()  | 
| def SetRecRefreshTime(recData, value): return recData.SetValue4(value)  | 
| def GetRecZoneID(recData): return recData.GetValue5()  | 
| def SetRecZoneID(recData, value): return recData.SetValue5(value)  | 
| def GetRecKilledRecord(recData): return recData.GetStrValue3()  | 
| def SetRecKilledRecord(recData, value): return recData.SetStrValue3(value)  | 
|   | 
| g_bossRecDataDict = {} # boss¶ÔÓ¦rec¼Ç¼»º´æ {(zoneID, bossID):recData, ...}  | 
|   | 
| def GetCrossBossZoneIpyData(realMapID, dataMapID, copyMapID):  | 
|     ## »ñÈ¡µØÍ¼¿ç·þbossËùÊô·ÖÇø  | 
|     if dataMapID not in ChConfig.Def_CrossMapIDList:  | 
|         return  | 
|     if dataMapID not in ChConfig.Def_CrossZoneTableName:  | 
|         GameWorld.ErrLog("¿ç·þbossûÓзÖÇø±í!dataMapID=%s" % dataMapID)  | 
|         return  | 
|     tableName = ChConfig.Def_CrossZoneTableName[dataMapID]  | 
|     return IpyGameDataPY.GetIpyGameData(tableName, realMapID, dataMapID, copyMapID)  | 
|   | 
| def __GetCrossBossRecData(zoneID, bossID):  | 
|     ## »ñÈ¡¿ç·þBoss RecÊý¾Ý  | 
|     #  @param zoneID: ·ÖÇøID  | 
|     #  @param bossID: bossID  | 
|       | 
|     global g_bossRecDataDict  | 
|     key = (zoneID, bossID)  | 
|     if key in g_bossRecDataDict:  | 
|         return g_bossRecDataDict[key]  | 
|       | 
|     recTypeListData = GameWorld.GetUniversalRecMgr().GetTypeList(ShareDefine.Def_UniversalGameRecType_CrossBossInfo)  | 
|       | 
|     # ²éÕÒÊÇ·ñÒÑÓмǼ  | 
|     bossRec = None  | 
|     for index in xrange(recTypeListData.Count()):  | 
|         recData = recTypeListData.At(index)  | 
|         if GetRecBossID(recData) == bossID and GetRecZoneID(recData) == zoneID:  | 
|             bossRec = recData  | 
|             break  | 
|           | 
|     if bossRec == None:  | 
|         #»¹Î´¼Ç¼£¬ÔòÌí¼ÓÒ»¸ö¼Ç¼¶ÔÏó  | 
|         bossRec = recTypeListData.AddRec()  | 
|         SetRecBossID(bossRec, bossID)  | 
|         SetRecZoneID(bossRec, zoneID)  | 
|           | 
|     g_bossRecDataDict[key] = bossRec  | 
|     return bossRec  | 
|   | 
| def __SetCrossBossIsAlive(zoneID, bossID, isAlive):  | 
|     ## ÉèÖÿç·þÊÀ½çbossÊÇ·ñ»î×Å  | 
|     GameWorld.GetGameWorld().SetDict(ChConfig.Def_WorldKey_CrossBossIsAlive % (zoneID, bossID), isAlive)  | 
|     return  | 
|   | 
| def __GetCrossBossIsAlive(zoneID, bossID):  | 
|     ## »ñÈ¡¿ç·þÊÀ½çbossÊÇ·ñ»î×Å  | 
|     return GameWorld.GetGameWorld().GetDictByKey(ChConfig.Def_WorldKey_CrossBossIsAlive % (zoneID, bossID))  | 
|   | 
| def ClientServerMsg_ServerInitOK(serverGroupID):  | 
|     ## ×Ó·þÁ¬½Ó³É¹¦  | 
|       | 
|     bossInfoList = []  | 
|     ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|     for i in xrange(ipyDataMgr.GetBOSSInfoCount()):  | 
|         ipyData = ipyDataMgr.GetBOSSInfoByIndex(i)  | 
|         mapID = ipyData.GetMapID()  | 
|         zoneIpyData = CrossRealmPlayer.GetServerCrossZoneIpyData(mapID, serverGroupID)  | 
|         if not zoneIpyData:  | 
|             continue  | 
|         zoneID = zoneIpyData.GetZoneID()  | 
|         bossID = ipyData.GetNPCID()  | 
|         bossRecData = __GetCrossBossRecData(zoneID, bossID)  | 
|         killedTime = GetRecKilledTime(bossRecData)  | 
|         refreshTime = GetRecRefreshTime(bossRecData)  | 
|         killedRecord = GetRecKilledRecord(bossRecData)  | 
|         isAlive = __GetCrossBossIsAlive(zoneID, bossID)  | 
|         killerExInfo = [] # ÖØÁ¬³É¹¦µÄÐÅϢͬ²½²»·¢ËÍ»÷ɱÕßÐÅÏ¢  | 
|         bossInfoList.append([zoneID, bossID, killedTime, refreshTime, killedRecord, isAlive, killerExInfo])  | 
|           | 
|     if bossInfoList:  | 
|         bossInfoDict = {"BossInfoType":"InitOK", "BossInfoList":bossInfoList}  | 
|         CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossBossInfo, bossInfoDict, [serverGroupID])  | 
|           | 
|     return  | 
|   | 
| def DoCrossBossOnKilled(bossID, killPlayerName, realMapID, dataMapID, copyMapID, killerIDList):  | 
|     ## ¿ç·þboss±»É±  | 
|     zoneIpyData = GetCrossBossZoneIpyData(realMapID, dataMapID, copyMapID)  | 
|     zoneID = 0 if not zoneIpyData else zoneIpyData.GetZoneID()  | 
|     GameWorld.Log("»÷ɱ¿ç·þboss: zoneID=%s,bossID=%s,realMapID=%s,dataMapID=%s,copyMapID=%s,killerIDList=%s"   | 
|                   % (zoneID, bossID, realMapID, dataMapID, copyMapID, killerIDList))  | 
|     if not zoneID:  | 
|         return  | 
|       | 
|     isAlive = 0  | 
|     killedTime = int(time.time())  | 
|     # ²éÕҼǼ  | 
|     bossRecData = __GetCrossBossRecData(zoneID, bossID)  | 
|       | 
|     __SetKilledRecord(bossRecData, killedTime, killPlayerName)  | 
|       | 
|     __SetCrossBossIsAlive(zoneID, bossID, isAlive)  | 
|     refreshTime = SetBossRefreshTime(zoneID, bossID, killedTime, bossRecData)  | 
|       | 
|     # ¹ã²¥×Ó·þ¿ç·þboss±»»÷ɱ  | 
|     serverGroupIDList = zoneIpyData.GetServerGroupIDList()  | 
|     killedRecord = GetRecKilledRecord(bossRecData)  | 
|     killerExInfo = [killerIDList, dataMapID]  | 
|     bossInfoList = [[zoneID, bossID, killedTime, refreshTime, killedRecord, isAlive, killerExInfo]]  | 
|     bossInfoDict = {"BossInfoType":"OnKilled", "BossInfoList":bossInfoList}  | 
|     CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossBossInfo, bossInfoDict, serverGroupIDList)  | 
|     return  | 
|   | 
| def DoCrossBossStateChange(bossID, isAlive, dataMapID, realMapID, copyMapID):  | 
|     ## ¿ç·þboss״̬±ä¸ü  | 
|     zoneIpyData = GetCrossBossZoneIpyData(realMapID, dataMapID, copyMapID)  | 
|     zoneID = 0 if not zoneIpyData else zoneIpyData.GetZoneID()  | 
|     GameWorld.Log("¿ç·þboss״̬±ä¸ü: zoneID=%s,bossID=%s,isAlive=%s,realMapID=%s,dataMapID=%s,copyMapID=%s"   | 
|                   % (zoneID, bossID, isAlive, realMapID, dataMapID, copyMapID))  | 
|     if not zoneID:  | 
|         return  | 
|       | 
|     __SetCrossBossIsAlive(zoneID, bossID, isAlive)  | 
|       | 
|     if isAlive:  | 
|         # ¹ã²¥×Ó·þ¿ç·þboss¸´»î  | 
|         serverGroupIDList = zoneIpyData.GetServerGroupIDList()  | 
|         stateInfo = [zoneID, bossID, isAlive]  | 
|         CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossBossState, stateInfo, serverGroupIDList)  | 
|           | 
|     return  | 
|   | 
| def __SetKilledRecord(bossRecData, killedTime, playerName):  | 
|     ## ÉèÖÃÊÀ½çbossÉÏÒ»´Î»÷ɱ¼Ç¼  | 
|     killedRecord = GetRecKilledRecord(bossRecData)  | 
|     killedRecordList = killedRecord.split('|') if killedRecord else []  | 
|     killedRecordList.append("%s_%s" % (killedTime, playerName))  | 
|     #¼Ç¼×î½ü5´Î  | 
|     if len(killedRecordList) > 5:  | 
|         del killedRecordList[0]  | 
|     killedRecord = '|'.join(killedRecordList)  | 
|     SetRecKilledRecord(bossRecData, killedRecord)  | 
|     SetRecKilledTime(bossRecData, killedTime)  | 
|     return  | 
|   | 
| def SetBossRefreshTime(zoneID, bossID, killedTime, bossRecData):  | 
|     '''ÉèÖÃbossË¢ÐÂʱ¼ä'''  | 
|     ipyData = IpyGameDataPY.GetIpyGameData('BOSSInfo', bossID)  | 
|     if not ipyData:  | 
|         return 0  | 
|     #onlineCnt = 0  | 
|     #yesterdayCnt = 0  | 
|     refreshTime = eval(ipyData.GetRefreshTime())  | 
|     SetRecRefreshTime(bossRecData, refreshTime)  | 
|     __UpdateBossRefreshList(zoneID, bossID, killedTime, refreshTime)  | 
|     GameWorld.DebugLog('    ÉèÖÃbossË¢ÐÂʱ¼ä: zoneID=%s,bossID=%s,refreshTime=%s' % (zoneID, bossID, refreshTime))  | 
|     return refreshTime  | 
|   | 
| def __UpdateBossRefreshList(zoneID, bossID, killedTime=0, refreshTime=0):  | 
|     for bossInfo in PyGameData.g_sortBOSSRefreshList:  | 
|         if bossID == bossInfo[0] and zoneID == bossInfo[3]:  | 
|             if killedTime:  | 
|                 bossInfo[1] = killedTime  | 
|             if refreshTime:  | 
|                 bossInfo[2] = refreshTime  | 
|             break  | 
|     curTime = int(time.time())  | 
|     PyGameData.g_sortBOSSRefreshList.sort(key=lambda asd:max(0, asd[2] - (curTime - asd[1])))  | 
|     GameWorld.DebugLog('    PyGameData.g_sortBOSSRefreshList=%s' % PyGameData.g_sortBOSSRefreshList)  | 
|     return  | 
|   | 
| def DoCheckCrossBossReborn(tick):  | 
|     ## ¿ç·þboss¸´»î¼ì²é  | 
|       | 
|     curTime = int(time.time())  | 
|     if not PyGameData.g_sortBOSSRefreshList:  | 
|         ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|         for i in xrange(ipyDataMgr.GetBOSSInfoCount()):  | 
|             ipyData = ipyDataMgr.GetBOSSInfoByIndex(i)  | 
|             bossID = ipyData.GetNPCID()  | 
|             mapID = ipyData.GetMapID()  | 
|             if mapID not in ChConfig.Def_CrossZoneTableName:  | 
|                 continue  | 
|             tableName = ChConfig.Def_CrossZoneTableName[mapID]  | 
|             if not hasattr(ipyDataMgr, "Get%sCount" % tableName):  | 
|                 continue  | 
|             for i in xrange(getattr(ipyDataMgr, "Get%sCount" % tableName)()):  | 
|                 zoneIpyData = getattr(ipyDataMgr, "Get%sByIndex" % tableName)(i)  | 
|                 zoneID = zoneIpyData.GetZoneID()  | 
|                 bossRecData = __GetCrossBossRecData(zoneID, bossID)  | 
|                 killedTime = GetRecKilledTime(bossRecData)  | 
|                 refreshTime = GetRecRefreshTime(bossRecData)  | 
|                 PyGameData.g_sortBOSSRefreshList.append([bossID, killedTime, refreshTime, zoneID])  | 
|         PyGameData.g_sortBOSSRefreshList.sort(key=lambda asd:max(0, asd[2] - (curTime - asd[1])))  | 
|           | 
|     #GameWorld.DebugLog("¼ì²éboss¸´»î: PyGameData.g_sortBOSSRefreshList=%s" % PyGameData.g_sortBOSSRefreshList)  | 
|     syncBOSSIDList = []  | 
|     for bossInfo in PyGameData.g_sortBOSSRefreshList:  | 
|         bossID, killedTime, refreshTime, zoneID = bossInfo  | 
|         isAlive = __GetCrossBossIsAlive(zoneID, bossID)  | 
|         if isAlive:  | 
|             #GameWorld.DebugLog("    zoneID=%s,bossID=%s,δ±»»÷ɱ£¡" % (zoneID, bossID))  | 
|             continue  | 
|         rebornSecond = max(0, refreshTime - (curTime - killedTime))  | 
|           | 
|         if rebornSecond > 0:  | 
|             #GameWorld.DebugLog("    zoneID=%s,bossID=%s,refreshTime=%s,curTime=%s,killedTime=%s,ÖØÉúµ¹¼ÆÊ±Ãë(%s)£¡" % (zoneID, bossID, refreshTime, curTime, killedTime, rebornSecond))  | 
|             break  | 
|           | 
|         __SetCrossBossIsAlive(zoneID, bossID, 1)  | 
|         syncBOSSIDList.append(bossID)  | 
|           | 
|         GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_GameWorldBossRebornCross % (zoneID, bossID), 1)  | 
|         GameWorld.DebugLog("    Í¨ÖªMapServerÖØÉú: zoneID=%s,bossID=%s,killedTime=%s,rebornSecond=%s" % (zoneID, bossID, killedTime, rebornSecond))  | 
|           | 
|     return  | 
|   | 
| def OnCrossMapServerInitOK():  | 
|     __SendMapServerAliveCrossBoss()  | 
|     return  | 
|   | 
| def __SendMapServerAliveCrossBoss():  | 
|     ## Í¬²½µ±Ç°»¹»î×ŵÄboss£¬·ÀÖ¹µØÍ¼ÖØÆôºóÒѾˢеÄboss²»Ë¢Ð  | 
|     ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|     for i in xrange(IpyGameDataPY.IPY_Data().GetBOSSInfoCount()):  | 
|         ipyData = IpyGameDataPY.IPY_Data().GetBOSSInfoByIndex(i)  | 
|         bossID = ipyData.GetNPCID()  | 
|         mapID = ipyData.GetMapID()  | 
|         if mapID not in ChConfig.Def_CrossZoneTableName:  | 
|             continue  | 
|         tableName = ChConfig.Def_CrossZoneTableName[mapID]  | 
|         if not hasattr(ipyDataMgr, "Get%sCount" % tableName):  | 
|             continue  | 
|         for i in xrange(getattr(ipyDataMgr, "Get%sCount" % tableName)()):  | 
|             zoneIpyData = getattr(ipyDataMgr, "Get%sByIndex" % tableName)(i)  | 
|             zoneID = zoneIpyData.GetZoneID()  | 
|             isAlive = __GetCrossBossIsAlive(zoneID, bossID)  | 
|             if not isAlive:  | 
|                 continue  | 
|             GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_GameWorldBossRebornCross % (zoneID, bossID), 1)  | 
|               | 
|     return  | 
|   | 
| ##------------------------------------- ÒÔÏÂÊDZ¾·þ´¦Àí -------------------------------------------  | 
|   | 
| def OnPlayerLogin(curPlayer):  | 
|     Sync_CrossBossInfo(curPlayer)  | 
|     return  | 
|   | 
| def CrossServerMsg_CrossBossInfo(bossInfoDict):  | 
|     ## ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¿ç·þbossÐÅÏ¢ {"BossInfoType":"InitOK", "BossInfoList":bossInfoList}  | 
|     global g_bossRecDataDict  | 
|       | 
|     bossInfoType = bossInfoDict["BossInfoType"]  | 
|     bossInfoList = bossInfoDict["BossInfoList"]  | 
|       | 
|     GameWorld.DebugLog("ÊÕµ½¿ç·þͬ²½µÄ¿ç·þbossÐÅÏ¢: bossInfoType=%s" % (bossInfoType))  | 
|       | 
|     if bossInfoType == "InitOK":  | 
|         # ×Ó·þÊÕµ½³õʼ»¯Êý¾ÝµÄ£¬¸²¸Ç¸üР | 
|         recTypeListData = GameWorld.GetUniversalRecMgr().GetTypeList(ShareDefine.Def_UniversalGameRecType_CrossBossInfo)  | 
|         recTypeListData.Clear()  | 
|         g_bossRecDataDict = {}  | 
|           | 
|     syncBOSSIDList = []  | 
|     for bossInfo in bossInfoList:  | 
|         zoneID, bossID, killedTime, refreshTime, killedRecord, isAlive, killerExInfo = bossInfo  | 
|         bossRecData = __GetCrossBossRecData(zoneID, bossID)  | 
|         SetRecKilledTime(bossRecData, killedTime)  | 
|         SetRecRefreshTime(bossRecData, refreshTime)  | 
|         SetRecKilledRecord(bossRecData, killedRecord)  | 
|         __SetCrossBossIsAlive(zoneID, bossID, isAlive)  | 
|         syncBOSSIDList.append(bossID)  | 
|           | 
|         if not killerExInfo:  | 
|             continue  | 
|           | 
|         killerIDList, dataMapID = killerExInfo  | 
|         for playerID in killerIDList:  | 
|             killer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)  | 
|             if not killer:  | 
|                 GameWorld.ErrLog("»÷ɱ¿ç·þbossʱÖ÷·þÍæ¼Ò²»ÔÚÏß, playerID=%s,dataMapID=%s,bossID=%s" % (playerID, dataMapID, bossID))  | 
|                 DataRecordPack.SendEventPack("CrossBoss_Error", {"PlayerID":playerID, "Error":"MainServerOffline"})  | 
|                 continue  | 
|             msgInfo = str([dataMapID, bossID])  | 
|             killer.MapServer_QueryPlayerResult(0, 0, "CrossKillBoss", msgInfo, len(msgInfo))  | 
|               | 
|     Sync_CrossBossInfo(None, syncBOSSIDList)  | 
|     return  | 
|   | 
| def CrossServerMsg_CrossBossState(msgInfo):  | 
|     ## ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¿ç·þboss״̬  | 
|       | 
|     zoneID, bossID, isAlive = msgInfo  | 
|     GameWorld.DebugLog("ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¿ç·þboss״̬: zoneID=%s, bossID=%s, isAlive=%s" % (zoneID, bossID, isAlive))  | 
|       | 
|     __SetCrossBossIsAlive(zoneID, bossID, isAlive)  | 
|       | 
|     if isAlive:  | 
|         Sync_CrossBossInfo(None, [bossID])  | 
|           | 
|     return  | 
|   | 
|   | 
| def Sync_CrossBossInfo(curPlayer=None, syncBOSSIDList=[]):  | 
|     ## Í¬²½bossÏà¹ØÐÅÏ¢  | 
|       | 
|     curTime = int(time.time())  | 
|       | 
|     recTypeListData = GameWorld.GetUniversalRecMgr().GetTypeList(ShareDefine.Def_UniversalGameRecType_CrossBossInfo)  | 
|       | 
|     bossInfo = ChPyNetSendPack.tagGCGameWorldBossInfo()  | 
|     bossInfo.BossInfoList = []  | 
|     for index in xrange(recTypeListData.Count()):  | 
|         recData = recTypeListData.At(index)  | 
|         bossID = GetRecBossID(recData)  | 
|         if not bossID:  | 
|             continue  | 
|         if syncBOSSIDList and bossID not in syncBOSSIDList:  | 
|             continue  | 
|         zoneID = GetRecZoneID(recData)  | 
|         killedTime = GetRecKilledTime(recData)  | 
|         refreshTime = GetRecRefreshTime(recData)  | 
|         bossInfoObj = ChPyNetSendPack.tagBossInfoObj()  | 
|         bossInfoObj.BossID = bossID  | 
|         bossInfoObj.IsAlive = __GetCrossBossIsAlive(zoneID, bossID)  | 
|         bossInfoObj.KillRecord = GetRecKilledRecord(recData)  | 
|         bossInfoObj.RecordLen = len(bossInfoObj.KillRecord)  | 
|         bossInfoObj.RefreshSecond = max(0, refreshTime - (curTime - killedTime))  | 
|         bossInfoObj.RefreshCD = refreshTime  | 
|         bossInfo.BossInfoList.append(bossInfoObj)  | 
|           | 
|     bossInfo.BossCnt = len(bossInfo.BossInfoList)  | 
|     if not curPlayer:  | 
|         # È«·þ¹ã²¥ÔÚÏßÍæ¼Ò  | 
|         playerManager = GameWorld.GetPlayerManager()  | 
|         for i in xrange(playerManager.GetActivePlayerCount()):  | 
|             curPlayer = playerManager.GetActivePlayerAt(i)  | 
|             if curPlayer == None:  | 
|                 continue  | 
|             if PlayerControl.GetIsTJG(curPlayer):  | 
|                 continue  | 
|             NetPackCommon.SendFakePack(curPlayer, bossInfo)  | 
|     else:  | 
|         if PlayerControl.GetIsTJG(curPlayer):  | 
|             return  | 
|         NetPackCommon.SendFakePack(curPlayer, bossInfo)  | 
|     return  | 
|   | 
|   |