#!/usr/bin/python # -*- coding: utf-8 -*- # @todo: 战力分析 import CommFunc import ConfigParser import DBOperate import operator import logging import mylog cfg = ConfigParser.ConfigParser() cfg.read("../../InterfaceConfig.php") ServerPath = cfg.get("ServerInfo", "ServerPath") MFPNameDict = {} OtherMFPType = 99 # 兼容多版本,所有版本的战力流向最大模块默认设置为其他99 def initMFPTNameDict(): global MFPNameDict MFPNameDict = {0:_(u"角色"), 1:_(u"装备"), 2:_(u"强化"), 3:_(u"宝石"), 4:_(u"灵根"), 5:_(u"灵器"), 6:_(u"洗练"), 7:_(u"灵宠"), 8:_(u"坐骑"), 9:_(u"境界"), 10:_(u"神兵"), 11:_(u"称号"), 12:_(u"符印"), 13:_(u"升星"), 14:_(u"人族"), 15:_(u"丹药"), 16:_(u"魔族"), 17:_(u"仙族"), 18:_(u"灵宠魂石"), 19:_(u"坐骑魂石"), 20:_(u"法器"), 21:_(u"神兽"), 22:_(u"聚魂"), 23:_(u"王者法宝"), 24:_(u"时装"), 25:_(u"情缘"), 26:_(u"魅力"), 27:_(u"炼体"), 28:_(u"附魔"), 29:_(u"古宝"), 30:_(u"神通"), 31:_(u"阵法"), 32:_(u"聚魂新"), 33:_(u"头像"), 34:_(u"头像框"), 35:_(u"气泡框"), } addMFPTName(OtherMFPType, _(u"其他")) return def addMFPTName(mfpType, mfpName=None): if not mfpName: mfpName = _(u"未知") global MFPNameDict if mfpType not in MFPNameDict: MFPNameDict[mfpType] = "%s%s" % (mfpName, mfpType) return def parseUnknownMFP(drDict): '''处理未知战力模块,兼容不同游戏版本 如版本一: {1:1000, ..., 26:100} 此处26是其他战力模块 如版本二: {1:1000, ..., 26:200, 27:100} 此处26是魅力模块,27才是其他战力模块 总结: 流向中最大数字ID的为其他模块战力 ''' mfpTList = [] for k in drDict.keys(): mfpType = CommFunc.toInt(k, None) if mfpType != None: drDict[mfpType] = drDict.pop(k) mfpTList.append(mfpType) maxMFPType = max(mfpTList) # 添加未知模块 for mfpType in mfpTList: if mfpType != maxMFPType: addMFPTName(mfpType, _(u"未知")) else: drDict[OtherMFPType] = drDict.pop(mfpType) # 将此版本的真正其他战力模块设置为方便统一处理的其他战力模块 return def getMFPKVNameStr(): printStr = "
" printStr += "%s:" % _(u"模块对应名") for k, v in MFPNameDict.items(): if k % 10 == 0: printStr += "
" printStr += "%s-%s;" % (k, v) printStr += "
" printStr += "
" return printStr def queryAccIDMFPInfo(argvDict): ## 查询个人战力模块分布 startDate = argvDict.get("startDate", "") endDate = argvDict.get("endDate", "") queryType = argvDict.get("queryType", "") playerFind = argvDict.get("playerFind", "") # 查询中心备份的 if CommFunc.isQueryCenterbak(argvDict): queryAccIDMFPInfo_Centerbak(startDate, endDate, argvDict) return playerName = "" queryAccID = playerFind if queryType == "playerName": # 根据玩家名查找的,以db为准,找到对应的账号进行匹配,不然玩家改名将导致匹配结果错误 dboper = DBOperate.DBOper(ServerPath) findDBRet = dboper.findPlayerInfoByName([playerFind]) dboper.close() if not findDBRet or findDBRet.count() == 0: print "找不到该玩家!
%s
" % playerFind return dbPlayer = findDBRet[0] queryAccID = CommFunc.encode(dbPlayer["AccID"]) playerName = CommFunc.encode(dbPlayer["PlayerName"]) dateMFPDict = {} needQueryCenterbak = CommFunc.loopMainServerDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc_AccIDMFPInfo, parseLineFunc_AccIDMFPInfo, queryAccID, dateMFPDict) if needQueryCenterbak: argvDict["queryAccID"] = queryAccID bakDataList = CommFunc.queryBackupCenterDR(cfg, argvDict) if bakDataList == None: return bakMFPDict = bakDataList[0] bakMFPDict.update(dateMFPDict) dateMFPDict = bakMFPDict dateStrList = dateMFPDict.keys() dateStrList.sort(reverse=True) fightPower = None mfpDRList = [] for dateStr in dateStrList: mfpDict = dateMFPDict[dateStr] parseUnknownMFP(mfpDict) if fightPower == None: fightPower = mfpDict["fightPower"] mfpDict["dateStr"] = dateStr mfpDict["fightPower"] = CommFunc.transformNum(mfpDict["fightPower"]) mfpDRList.append(mfpDict) printStr = "

%s

" % _(u"战力模块") printStr += "%s: %s
" % (_(u"玩家账号"), queryAccID) if playerName: printStr += "%s: %s
" % (_(u"玩家名称"), playerName) if startDate: printStr += "%s: %s
" % (_(u"开始日期"), startDate) if endDate: printStr += "%s: %s
" % (_(u"结束日期"), endDate) # 表格输出 printStr += "=== %s ===
" % _(u"战力分析记录") printStr += getMFPKVNameStr() printStr += "%s: %s
" % (_(u"最近记录总战力"), fightPower) mfpTypeList = MFPNameDict.keys() mfpTypeList.sort() tdList = ["dateStr", "fightPower", "LV"] + mfpTypeList styleInfo = {} for mfpType in mfpTypeList: mfpTitle = MFPNameDict[mfpType] styleInfo[mfpType] = {"title":mfpTitle} styleInfo.update({"dateStr":{"title":_(u"日期")}, "fightPower":{"title":_(u"总战力")}}) printStr += CommFunc.editTableHtml(mfpDRList, tdList, styleInfo=styleInfo) # 只会返回最后一个print的内容 print printStr return def queryAccIDMFPInfo_Centerbak(startDate, endDate, argvDict): queryAccID = argvDict.get("queryAccID") if not queryAccID: return CommFunc.queryBackupCenterError("queryAccID is none") dateMFPDict = {} if not CommFunc.loopCenterbakRarDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc_AccIDMFPInfo, parseLineFunc_AccIDMFPInfo, queryAccID, dateMFPDict): return return CommFunc.queryBackupCenterOK([dateMFPDict]) def checkDrFileNeedParseFunc_AccIDMFPInfo(drFileName, *parseArgs, **kv): ''' 检查流向是否需要处理 @param drFileName: 流向文件名 xxx_日期.txt @param *parseArgs: 自定义参数 @return: isNeed, checkNeedParseRetInfo ''' isNeed = drFileName.startswith("LogInOut_") return isNeed, None def parseLineFunc_AccIDMFPInfo(drName, dateStr, checkNeedParseRetInfo, line, *parseArgs, **kv): ''' 解析流向行内容 @param drName: 流向名 @param dateStr: 对应日期字符串 @param checkNeedParseRetInfo: checkDrFileNeedParseFunc 返回的内容 @param line: 本行内容 @param *parseArgs: 自定义参数 ''' queryAccID, dateMFPDict = parseArgs if queryAccID not in line: return drDict = eval(line) if queryAccID != drDict["AccID"]: return fightPower = drDict["fightPower"] if dateStr in dateMFPDict: infoDict = dateMFPDict[dateStr] if infoDict["fightPower"] >= fightPower: # 每日只保留最高战力记录 return infoDict = drDict["MFPFightPower"] infoDict["fightPower"] = fightPower infoDict["LV"] = drDict["LV"] dateMFPDict[dateStr] = infoDict return ## --------------------------------------------------------------------------- def getMFPBillboard(argvDict): ## 查询战力排行榜 startDate = argvDict.get("startDate", "") endDate = argvDict.get("endDate", "") topOrderCount = CommFunc.toInt(argvDict.get("maxOrder"), 10) # 查询中心备份的 if CommFunc.isQueryCenterbak(argvDict): getMFPBillboard_Centerbak(startDate, endDate, argvDict) return # 以下榜单数据有一定延迟,非实时排行数据,存档时间5分钟 # 1. 合并数据 - 战力榜 dboper = DBOperate.DBOper(ServerPath) col = dboper.db["tagDBPlayer"] spec = {} fields = {'_id':0, "FightPower":1, "FightPowerEx":1, "PlayerName":1, "AccID":1, "LV":1} fightPowerRet = col.find(spec, fields).sort([("FightPowerEx", -1), ("FightPower", -1)]).limit(topOrderCount) fightPowerList = [] for dataInfo in fightPowerRet: dataDict = {k:v for k, v in dataInfo.items()} dataDict["Name"] = dataInfo.pop("PlayerName", "") dataDict["fightPower"] = CommFunc.transformNum(dataInfo.pop("FightPowerEx", 0) * 100000000 + dataInfo.pop("FightPower", 0)) fightPowerList.append(dataDict) # 2. 实际排行 - 战力 col = dboper.db["tagDBBillboard"] spec = {"Type":0} fields = {'_id':0, "CmpValue":1, "CmpValue2":1, "Name1":1, "Name2":1} billboard_FightPowerRet = col.find(spec, fields).sort([("CmpValue", -1), ("CmpValue2", -1)]).limit(topOrderCount) billboard_FightPowerList = [] for dataInfo in billboard_FightPowerRet: dataDict = {k:v for k, v in dataInfo.items()} dataDict["Name"] = dataInfo.pop("Name1", "") dataDict["AccID"] = dataInfo.pop("Name2", "") dataDict["fightPower"] = CommFunc.transformNum(dataInfo.pop("CmpValue", 0) * 100000000 + dataInfo.pop("CmpValue2", 0)) billboard_FightPowerList.append(dataDict) # 关闭 dboper.close() # 3. 流向战力排名 accIDMFPDict = {} needQueryCenterbak = CommFunc.loopMainServerDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc_getMFPBillboard, parseLineFunc_getMFPBillboard, accIDMFPDict) if needQueryCenterbak: bakDataList = CommFunc.queryBackupCenterDR(cfg, argvDict) if bakDataList == None: return bakAccIDMFPDict = bakDataList[0] for accID, infoDict in bakAccIDMFPDict.items(): if accID not in accIDMFPDict: accIDMFPDict[accID] = infoDict # 备档正常情况下战力肯定比当前服流向记录的低,就不做高低验证,仅添加当前服流向没有的账号 accIDFPInfoList = accIDMFPDict.values() accIDFPInfoList.sort(key=operator.itemgetter("fightPower"), reverse=True) accIDFPInfoList = accIDFPInfoList[:topOrderCount] for mfpDict in accIDFPInfoList: parseUnknownMFP(mfpDict) mfpDict["fightPower"] = CommFunc.transformNum(mfpDict["fightPower"]) # 战力 styleInfo = {"Name":{"title":_(u"玩家")}, "AccID":{"align":"right", "title":_(u"账号")}, "LV":{"title":_(u"等级")}, "fightPower":{"align":"right", "title":_(u"战斗力")}} printStr = "

%s

" % _(u"战力排行") printStr += "%s
" % _(u"以下排行榜非实时数据") printStr += "
%s,%s:
" % (_(u"所有角色战力排行"), _(u"包含合服后未登录的账号")) tdList = ["Name", "AccID", "LV", "fightPower"] printStr += CommFunc.editTableHtml(fightPowerList, tdList, _(u"排名"), styleInfo=styleInfo) printStr += "
--------------------------------------------------------------------------
" printStr += "
%s,%s:
" % (_(u"活跃角色战力排行"), _(u"仅包含合服后登录的账号")) tdList = ["Name", "AccID", "fightPower"] printStr += CommFunc.editTableHtml(billboard_FightPowerList, tdList, _(u"排名"), styleInfo=styleInfo) printStr += "
--------------------------------------------------------------------------
" printStr += getMFPKVNameStr() printStr += "%s:
" % _(u"查询时间范围内有登录/登出流向的账号战力明细排行") if startDate: printStr += "%s: %s
" % (_(u"开始日期"), startDate) if endDate: printStr += "%s: %s
" % (_(u"结束日期"), endDate) mfpTypeList = MFPNameDict.keys() mfpTypeList.sort() tdList = ["Name", "AccID", "LV", "fightPower"] + mfpTypeList for mfpType in mfpTypeList: mfpTitle = MFPNameDict[mfpType] styleInfo[mfpType] = {"align":"right", "title":mfpTitle} printStr += CommFunc.editTableHtml(accIDFPInfoList, tdList, _(u"排名"), styleInfo=styleInfo) printStr += "
--------------------------------------------------------------------------
" print printStr return def getMFPBillboard_Centerbak(startDate, endDate, argvDict): accIDMFPDict = {} if not CommFunc.loopCenterbakRarDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc_getMFPBillboard, parseLineFunc_getMFPBillboard, accIDMFPDict): return return CommFunc.queryBackupCenterOK([accIDMFPDict]) def checkDrFileNeedParseFunc_getMFPBillboard(drFileName, *parseArgs, **kv): ''' 检查流向是否需要处理 @param drFileName: 流向文件名 xxx_日期.txt @param *parseArgs: 自定义参数 @return: isNeed, checkNeedParseRetInfo ''' isNeed = drFileName.startswith("LogInOut_") return isNeed, None def parseLineFunc_getMFPBillboard(drName, dateStr, checkNeedParseRetInfo, line, *parseArgs, **kv): ''' 解析流向行内容 @param drName: 流向名 @param dateStr: 对应日期字符串 @param checkNeedParseRetInfo: checkDrFileNeedParseFunc 返回的内容 @param line: 本行内容 @param *parseArgs: 自定义参数 ''' accIDMFPDict = parseArgs[0] drDict = eval(line) accID = drDict["AccID"] fightPower = drDict["fightPower"] if accID in accIDMFPDict: infoDict = accIDMFPDict[accID] if infoDict["fightPower"] >= fightPower: # 排名只保留每个账号的最高战力记录 return infoDict = drDict["MFPFightPower"] infoDict["fightPower"] = fightPower infoDict["AccID"] = accID infoDict["Name"] = drDict["Name"] infoDict["LV"] = drDict["LV"] accIDMFPDict[accID] = infoDict return def main(): CommFunc.setdefaultencoding() argvDict = CommFunc.parse_args() mylog.InitMyLog(argvDict.get("eventType", "")) CommFunc.gettextInstall(argvDict.get("lang", "")) initMFPTNameDict() playerFind = argvDict.get("playerFind", "") if playerFind != "": queryAccIDMFPInfo(argvDict) else: getMFPBillboard(argvDict) return if __name__ == "__main__": try: main() except: CommFunc.printExceptionError()