#!/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()