#!/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] = "<font color='red'>%s%s</font>" % (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 = "<br/>"
|
printStr += "%s:" % _(u"模块对应名")
|
for k, v in MFPNameDict.items():
|
if k % 10 == 0:
|
printStr += "<br/>"
|
printStr += "%s-%s;" % (k, v)
|
printStr += "<br/>"
|
printStr += "<br/>"
|
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 "找不到该玩家!<br/>%s<br/>" % 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 = "<center><p>%s</p></center>" % _(u"战力模块")
|
printStr += "%s: %s<br/>" % (_(u"玩家账号"), queryAccID)
|
if playerName:
|
printStr += "%s: %s<br/>" % (_(u"玩家名称"), playerName)
|
|
if startDate:
|
printStr += "%s: %s<br/>" % (_(u"开始日期"), startDate)
|
if endDate:
|
printStr += "%s: %s<br/>" % (_(u"结束日期"), endDate)
|
|
# 表格输出
|
printStr += "=== %s ===<br/>" % _(u"战力分析记录")
|
printStr += getMFPKVNameStr()
|
|
printStr += "%s: %s<br/>" % (_(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 = "<center><p>%s</p></center>" % _(u"战力排行")
|
printStr += "%s<br/>" % _(u"以下排行榜非实时数据")
|
printStr += "<br/>%s,<font color='red'>%s</font>:<br/>" % (_(u"所有角色战力排行"), _(u"包含合服后未登录的账号"))
|
tdList = ["Name", "AccID", "LV", "fightPower"]
|
printStr += CommFunc.editTableHtml(fightPowerList, tdList, _(u"排名"), styleInfo=styleInfo)
|
|
printStr += "<br/>--------------------------------------------------------------------------<br/>"
|
printStr += "<br/>%s,<font color='red'>%s</font>:<br/>" % (_(u"活跃角色战力排行"), _(u"仅包含合服后登录的账号"))
|
tdList = ["Name", "AccID", "fightPower"]
|
printStr += CommFunc.editTableHtml(billboard_FightPowerList, tdList, _(u"排名"), styleInfo=styleInfo)
|
|
printStr += "<br/>--------------------------------------------------------------------------<br/>"
|
printStr += getMFPKVNameStr()
|
|
printStr += "%s:<br/>" % _(u"查询时间范围内<font color='red'>有登录/登出流向</font>的账号战力明细排行")
|
if startDate:
|
printStr += "%s: %s<br/>" % (_(u"开始日期"), startDate)
|
if endDate:
|
printStr += "%s: %s<br/>" % (_(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 += "<br/>--------------------------------------------------------------------------<br/>"
|
|
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()
|