#!/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 PlayerFB 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 GetCrossBossZoneID(mapID, realMapID, copyMapID): ## »ñÈ¡µØÍ¼¿ç·þbossËùÊô·ÖÇø if mapID not in ChConfig.Def_CrossMapIDList: return 0 # ¹Ì¶¨Ïß··ÖÅäµÄ if mapID in ChConfig.Def_CrossZoneMapTableName: tableName = ChConfig.Def_CrossZoneMapTableName[mapID] zoneIpyData = IpyGameDataPY.GetIpyGameData(tableName, realMapID, mapID, copyMapID) if not zoneIpyData: return 0 return zoneIpyData.GetZoneID() # ¶¯Ì¬Ïß··ÖÅäµÄ elif mapID in ChConfig.Def_CrossDynamicLineMap: return PlayerFB.GetCrossDynamicLineZoneID(mapID, realMapID, copyMapID) return 0 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 Sync_CrossBossInitDataToClientServer(serverGroupID=0): ''' ͬ²½¿ç·þBoss»î¶¯Êý¾Ýµ½×Ó·þÎñÆ÷ @param serverGroupID: Ϊ0ʱͬ²½ËùÓÐ×Ó·þ ''' crossMapBossIDListDict = {} ipyDataMgr = IpyGameDataPY.IPY_Data() for i in xrange(ipyDataMgr.GetBOSSInfoCount()): ipyData = ipyDataMgr.GetBOSSInfoByIndex(i) mapID = ipyData.GetMapID() bossID = ipyData.GetNPCID() if mapID not in ChConfig.Def_CrossZoneTypeName: continue if mapID not in crossMapBossIDListDict: crossMapBossIDListDict[mapID] = [] bossIDList = crossMapBossIDListDict[mapID] bossIDList.append(bossID) crossZoneName = GameWorld.GetCrossZoneName() GameWorld.Log("ͬ²½¸ø×Ó·þ¿ç·þbossÐÅÏ¢: crossZoneName=%s,syncServerGroupID=%s" % (crossZoneName, serverGroupID)) # ÓÉÓÚ²»Í¬¹¦ÄܵĿç·þboss·ÖÇø¿ÉÄܲ»Ò»Ñù£¬Í¬²½×Ó·þ¾ÍÐèÒª°´·ÖÇø·Ö²½Í¬²½£¬ËùÒÔÐèÏÈ·¢ËÍÒ»Ìõ³õʼ»¯µÄÐÅÏ¢ÀàÐÍÏÈÇå¿Õ×Ó·þ±£´æµÄ¿ç·þbossÊý¾Ý£¬ÔÙ¸ù¾Ý¹¦ÄÜËùÊô·ÖÇøÍÆËÍ serverGroupIDList = [serverGroupID] if serverGroupID else [] bossInfoDict = {"BossInfoType":"InitOK"} CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossBossInfo, bossInfoDict, serverGroupIDList) for mapID, bossIDList in crossMapBossIDListDict.items(): GameWorld.Log(" mapID=%s, bossIDList=%s" % (mapID, bossIDList)) zoneIpyDataList = CrossRealmPlayer.GetCrossZoneIpyDataListByServerGroupID(mapID, serverGroupID) if not zoneIpyDataList: continue for zoneIpyData in zoneIpyDataList: zoneID = zoneIpyData.GetZoneID() serverGroupIDList = [serverGroupID] if serverGroupID else zoneIpyData.GetServerGroupIDList() bossInfoList = [] for bossID in bossIDList: 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 = {"BossInfoList":bossInfoList} CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossBossInfo, bossInfoDict, serverGroupIDList) else: GameWorld.Log("ûÓпç·þbossÐÅÏ¢! mapID=%s,zoneID=%s" % (mapID, zoneID)) return def DoCrossBossOnKilled(bossID, killPlayerName, mapID, realMapID, copyMapID, killerIDList): ## ¿ç·þboss±»É± zoneID = GetCrossBossZoneID(mapID, realMapID, copyMapID) GameWorld.Log("»÷ɱ¿ç·þboss: zoneID=%s,bossID=%s,mapID=%s,realMapID=%s,copyMapID=%s,killerIDList=%s" % (zoneID, bossID, mapID, realMapID, 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±»»÷ɱ zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(mapID, zoneID) if zoneIpyData == None: return serverGroupIDList = zoneIpyData.GetServerGroupIDList() killedRecord = GetRecKilledRecord(bossRecData) killerExInfo = [killerIDList, mapID] 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, mapID, realMapID, copyMapID): ## ¿ç·þboss״̬±ä¸ü zoneID = GetCrossBossZoneID(mapID, realMapID, copyMapID) GameWorld.Log("¿ç·þboss״̬±ä¸ü: zoneID=%s,bossID=%s,isAlive=%s,mapID=%s,realMapID=%s,copyMapID=%s" % (zoneID, bossID, isAlive, mapID, realMapID, copyMapID)) if not zoneID: return if __GetCrossBossIsAlive(zoneID, bossID) != isAlive: __SetCrossBossIsAlive(zoneID, bossID, isAlive) if isAlive: # ¹ã²¥×Ó·þ¿ç·þboss¸´»î SendClientServerCrossBossState(mapID, zoneID, {bossID:isAlive}) return def SendClientServerCrossBossState(mapID, zoneID, bossStateDict={}): # ¹ã²¥×Ó·þ¿ç·þboss¸´»î zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(mapID, zoneID) if zoneIpyData != None: serverGroupIDList = zoneIpyData.GetServerGroupIDList() stateInfo = [zoneID, bossStateDict] 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: crossZoneName = GameWorld.GetCrossZoneName() 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_CrossZoneTypeName: continue refreshTimeStr = ipyData.GetRefreshTime() if not refreshTimeStr or refreshTimeStr == "0": continue zoneTypeName = ChConfig.Def_CrossZoneTypeName[mapID] if not hasattr(ipyDataMgr, "Get%sCount" % zoneTypeName): continue for i in xrange(getattr(ipyDataMgr, "Get%sCount" % zoneTypeName)()): zoneIpyData = getattr(ipyDataMgr, "Get%sByIndex" % zoneTypeName)(i) if zoneIpyData.GetCrossZoneName() != crossZoneName: continue zoneID = zoneIpyData.GetZoneID() bossRecData = __GetCrossBossRecData(zoneID, bossID) killedTime = GetRecKilledTime(bossRecData) refreshTime = GetRecRefreshTime(bossRecData) PyGameData.g_sortBOSSRefreshList.append([bossID, killedTime, refreshTime, zoneID, mapID]) PyGameData.g_sortBOSSRefreshList.sort(key=lambda asd:max(0, asd[2] - (curTime - asd[1]))) #GameWorld.DebugLog("¼ì²éboss¸´»î: PyGameData.g_sortBOSSRefreshList=%s" % PyGameData.g_sortBOSSRefreshList) zoneMapBossStateDict = {} for bossInfo in PyGameData.g_sortBOSSRefreshList: bossID, killedTime, refreshTime, zoneID, mapID = 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 isAlive = 1 __SetCrossBossIsAlive(zoneID, bossID, isAlive) key = (mapID, zoneID) if key not in zoneMapBossStateDict: zoneMapBossStateDict[key] = {} bossStateDict = zoneMapBossStateDict[key] bossStateDict[bossID] = isAlive 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)) for key, bossStateDict in zoneMapBossStateDict.items(): mapID, zoneID = key SendClientServerCrossBossState(mapID, zoneID, bossStateDict) return def GetCrossBossIsAliveOrCanReborn(zoneID, bossID): ##BOSSÊÇ·ñ»î×Å»òÕß¿ÉÖØÉú if __GetCrossBossIsAlive(zoneID, bossID): return True bossRecData = __GetCrossBossRecData(zoneID, bossID) killedTime = GetRecKilledTime(bossRecData) refreshTime = GetRecRefreshTime(bossRecData) curTime = int(time.time()) rebornSecond = max(0, refreshTime - (curTime - killedTime)) return rebornSecond == 0 def OnCrossMapServerInitOK(): __SendMapServerAliveCrossBoss() return def __SendMapServerAliveCrossBoss(): ## ͬ²½µ±Ç°»¹»î×ŵÄboss£¬·ÀÖ¹µØÍ¼ÖØÆôºóÒѾ­Ë¢ÐµÄboss²»Ë¢Ð crossZoneName = GameWorld.GetCrossZoneName() 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_CrossZoneTypeName: continue zoneTypeName = ChConfig.Def_CrossZoneTypeName[mapID] if not hasattr(ipyDataMgr, "Get%sCount" % zoneTypeName): continue for i in xrange(getattr(ipyDataMgr, "Get%sCount" % zoneTypeName)()): zoneIpyData = getattr(ipyDataMgr, "Get%sByIndex" % zoneTypeName)(i) if zoneIpyData.GetCrossZoneName() != crossZoneName: continue 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) __LoginNotifyKillCrossBoss(curPlayer) return def CrossServerMsg_CrossBossInfo(bossInfoDict): ## ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¿ç·þbossÐÅÏ¢ {"BossInfoType":"InitOK", "BossInfoList":bossInfoList} global g_bossRecDataDict bossInfoType = bossInfoDict.get("BossInfoType", "") bossInfoList = bossInfoDict.get("BossInfoList", []) GameWorld.DebugLog("ÊÕµ½¿ç·þͬ²½µÄ¿ç·þbossÐÅÏ¢: bossInfoType=%s" % (bossInfoType)) if bossInfoType == "InitOK": # ×Ó·þÊÕµ½³õʼ»¯Êý¾ÝµÄ£¬¸²¸Ç¸üРrecTypeListData = GameWorld.GetUniversalRecMgr().GetTypeList(ShareDefine.Def_UniversalGameRecType_CrossBossInfo) recTypeListData.Clear() g_bossRecDataDict = {} return 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, mapID = killerExInfo for playerID in killerIDList: killer = GameWorld.GetPlayerManager().FindPlayerByID(playerID) if not killer: #GameWorld.ErrLog("»÷ɱ¿ç·þbossʱÖ÷·þÍæ¼Ò²»ÔÚÏß, playerID=%s,mapID=%s,bossID=%s" % (playerID, mapID, bossID)) #DataRecordPack.SendEventPack("CrossBoss_Error", {"PlayerID":playerID, "Error":"MainServerOffline"}) killTime = int(time.time()) PyGameData.g_unNotifyKillCrossBossDict[playerID] = [killTime, mapID, bossID] continue msgInfo = str([mapID, bossID]) killer.MapServer_QueryPlayerResult(0, 0, "CrossKillBoss", msgInfo, len(msgInfo)) Sync_CrossBossInfo(None, syncBOSSIDList) return def __LoginNotifyKillCrossBoss(curPlayer): ## µÇ¼ʱ֪ͨδ֪ͨµ½µÄ»÷ɱ¿ç·þboss playerID = curPlayer.GetPlayerID() if playerID not in PyGameData.g_unNotifyKillCrossBossDict: return killTime, mapID, bossID = PyGameData.g_unNotifyKillCrossBossDict.pop(playerID) curTime = int(time.time()) passSeconds = curTime - killTime if passSeconds >= 120: GameWorld.DebugLog("³¬¹ý120ÃëÉÏÏß²»´¦Àí£¬Ö÷ҪΪÁË·ÀË¢ÉÏÏß¼ñÎïÆ·!", playerID) return msgInfo = str([mapID, bossID]) curPlayer.MapServer_QueryPlayerResult(0, 0, "CrossKillBoss", msgInfo, len(msgInfo)) GameWorld.Log("ÉÏÏß²¹Í¨Öª»÷ɱ¿ç·þboss: passSeconds=%s, mapID=%s, bossID=%s" % (passSeconds, mapID, bossID), playerID) return def CrossServerMsg_CrossBossState(msgInfo): ## ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¿ç·þboss״̬ zoneID, bossStateDict = msgInfo GameWorld.DebugLog("ÊÕµ½¿ç·þ·þÎñÆ÷ͬ²½µÄ¿ç·þboss״̬: zoneID=%s, bossStateDict=%s" % (zoneID, bossStateDict)) aliveBossIDList = [] for bossID, isAlive in bossStateDict.items(): __SetCrossBossIsAlive(zoneID, bossID, isAlive) if isAlive: aliveBossIDList.append(bossID) if aliveBossIDList: Sync_CrossBossInfo(None, aliveBossIDList) return def Sync_CrossBossInfo(curPlayer=None, syncBOSSIDList=[]): ## ͬ²½bossÏà¹ØÐÅÏ¢ curTime = GameWorld.ChangeTimeStrToNum(GameWorld.GetCrossServerTimeStr()) 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) if len(bossInfo.BossInfoList) >= 250: break if not bossInfo.BossInfoList: return 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