@firestone-hs/bgs-global-stats 1.0.32 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-battlegrounds-hero-stats-new.d.ts +6 -0
- package/dist/build-battlegrounds-hero-stats-new.js +2 -2
- package/dist/build-battlegrounds-hero-stats-new.js.map +1 -1
- package/dist/stats-v2/bgs-hero-stat.d.ts +12 -0
- package/dist/stats-v2/bgs-hero-stat.js.map +1 -1
- package/dist/stats-v2/stats-buikder.js +26 -2
- package/dist/stats-v2/stats-buikder.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { S3 } from '@firestone-hs/aws-lambda-utils';
|
|
2
2
|
import { Context } from 'aws-lambda';
|
|
3
|
+
import { InternalBgsRow } from './internal-model';
|
|
3
4
|
export declare const s3: S3;
|
|
4
5
|
declare const _default: (event: any, context: Context) => Promise<any>;
|
|
5
6
|
export default _default;
|
|
@@ -7,3 +8,8 @@ export declare const handleNewStats: (event: any, context: Context) => Promise<{
|
|
|
7
8
|
statusCode: number;
|
|
8
9
|
body: any;
|
|
9
10
|
}>;
|
|
11
|
+
export declare const buildCombatWinrate: (rows: readonly InternalBgsRow[]) => readonly {
|
|
12
|
+
turn: number;
|
|
13
|
+
dataPoints: number;
|
|
14
|
+
totalWinrate: number;
|
|
15
|
+
}[];
|
|
@@ -276,7 +276,7 @@ const buildHeroStats = (rows) => {
|
|
|
276
276
|
const result = Object.values(grouped).map(groupedRows => {
|
|
277
277
|
const ref = groupedRows[0];
|
|
278
278
|
const placementDistribution = common_1.buildPlacementDistribution(groupedRows);
|
|
279
|
-
const combatWinrate = buildCombatWinrate(groupedRows);
|
|
279
|
+
const combatWinrate = exports.buildCombatWinrate(groupedRows);
|
|
280
280
|
const warbandStats = buildWarbandStats(groupedRows);
|
|
281
281
|
return {
|
|
282
282
|
cardId: util_functions_1.normalizeHeroCardId(ref.heroCardId, allCards),
|
|
@@ -320,7 +320,7 @@ const buildWarbandStats = (rows) => {
|
|
|
320
320
|
}));
|
|
321
321
|
return result;
|
|
322
322
|
};
|
|
323
|
-
|
|
323
|
+
exports.buildCombatWinrate = (rows) => {
|
|
324
324
|
var _a, _b, _c;
|
|
325
325
|
const ref = rows[0];
|
|
326
326
|
const debug = ref.heroCardId === 'BG21_HERO_000';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-battlegrounds-hero-stats-new.js","sourceRoot":"/","sources":["build-battlegrounds-hero-stats-new.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { getConnection, groupByFunction, http, logBeforeTimeout, logger, S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds, Race } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { ServerlessMysql } from 'serverless-mysql';\r\nimport { Readable } from 'stream';\r\nimport { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat2, BgsGlobalStats2, MmrPercentile } from './bgs-global-stats';\r\nimport { buildMmrPercentiles, buildPlacementDistribution, filterRowsForTimePeriod, PatchInfo } from './common';\r\nimport { InternalBgsRow } from './internal-model';\r\nimport { handleQuests } from './quests';\r\nimport { handleQuestsV2 } from './quests-v2/quests-v2';\r\nimport { handleStatsV2 } from './stats-v2/stats-v2';\r\nimport { formatDate, normalizeHeroCardId } from './utils/util-functions';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allTimePeriods: ('all-time' | 'past-three' | 'past-seven' | 'last-patch')[] = [\r\n\t'all-time',\r\n\t'past-three',\r\n\t'past-seven',\r\n\t'last-patch',\r\n];\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\tlogger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\tconst lastPatch = await getLastBattlegroundsPatch();\r\n\r\n\tif (event.quests) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuests(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.questsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuestsV2(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.statsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleStatsV2(timePeriod, rows, lastPatch, allCards);\r\n\t\t}\r\n\t} else if (event.permutation) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handlePermutation(event.permutation, timePeriod, event.allTribes, rows, lastPatch);\r\n\t\t}\r\n\t} else {\r\n\t\tconst mysql = await getConnection();\r\n\t\tconst rows: readonly InternalBgsRow[] = await loadRows(mysql);\r\n\t\tawait mysql.end();\r\n\t\tawait saveRowsOnS3(rows);\r\n\t\tawait dispatchNewLambdas(rows, context);\r\n\t\tawait dispatchQuestsLambda(rows, context);\r\n\t\tawait dispatchQuestsV2Lambda(rows, context);\r\n\t\tawait dispatchStatsV2Lambda(rows, context);\r\n\t}\r\n\r\n\tcleanup();\r\n\treturn { statusCode: 200, body: null };\r\n};\r\n\r\nconst dispatchQuestsLambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquests: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquestsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tstatsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchNewLambdas = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst allTribes = extractAllTribes(rows);\r\n\tlogger.log('all tribes', allTribes);\r\n\tconst tribePermutations: ('all' | Race[])[] = ['all', ...combine(allTribes, 5)];\r\n\tlogger.log('tribe permutations, should be 127 (126 + 1), because 9 tribes', tribePermutations.length);\r\n\tfor (const tribes of tribePermutations) {\r\n\t\tlogger.log('handling tribes', tribes, tribes !== 'all' && tribes.join('-'));\r\n\t\t// if (tribes !== 'all') {\r\n\t\t// \tcontinue;\r\n\t\t// }\r\n\t\tconst newEvent = {\r\n\t\t\tpermutation: tribes,\r\n\t\t\tallTribes: allTribes,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tlogger.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\tlogger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst handlePermutation = async (\r\n\ttribes: 'all' | readonly Race[],\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\tallTribes: readonly Race[],\r\n\trows: readonly InternalBgsRow[],\r\n\tlastPatch: PatchInfo,\r\n) => {\r\n\tconsole.log('total rows', rows.length);\r\n\tconst rowsForTimePeriod = filterRowsForTimePeriod(rows, timePeriod, lastPatch);\r\n\tconsole.log('rows for time period', rowsForTimePeriod.length);\r\n\tconst tribesStr = tribes === 'all' ? null : tribes.join(',');\r\n\tconst rowsWithTribes = !!tribesStr\r\n\t\t? rowsForTimePeriod.filter(row => !!row.tribes).filter(row => row.tribes === tribesStr)\r\n\t\t: rowsForTimePeriod;\r\n\tconsole.log('rowsWithTribes', rowsWithTribes.length);\r\n\tconst mmrPercentiles: readonly MmrPercentile[] = buildMmrPercentiles(rowsWithTribes);\r\n\tlogger.log('handling permutation', tribes, timePeriod, rows?.length, rowsWithTribes?.length);\r\n\tconst stats: readonly BgsGlobalHeroStat2[] = buildHeroes(rowsWithTribes, mmrPercentiles).map(stat => ({\r\n\t\t...stat,\r\n\t\ttribes: tribes === 'all' ? allTribes : tribes,\r\n\t\tdate: timePeriod,\r\n\t}));\r\n\tconst statsForTribes: BgsGlobalStats2 = {\r\n\t\tlastUpdateDate: formatDate(new Date()),\r\n\t\tmmrPercentiles: mmrPercentiles,\r\n\t\theroStats: stats,\r\n\t\tallTribes: allTribes,\r\n\t\ttotalMatches: stats.map(s => s.totalMatches).reduce((a, b) => a + b, 0),\r\n\t};\r\n\tlogger.log('\\tbuilt stats', statsForTribes.totalMatches, statsForTribes.heroStats?.length);\r\n\tconst tribesSuffix = tribes === 'all' ? 'all-tribes' : tribes.join('-');\r\n\tconst timeSuffix = timePeriod;\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(statsForTribes)),\r\n\t\t'static.zerotoheroes.com',\r\n\t\t`api/bgs/heroes/bgs-global-stats-${tribesSuffix}-${timeSuffix}.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n\r\nconst saveRowsOnS3 = async (rows: readonly InternalBgsRow[]) => {\r\n\tlogger.log('saving rows on s3', rows.length);\r\n\tawait s3.writeArrayAsMultipart(rows, 'static.zerotoheroes.com', `api/bgs/working-rows.json`, 'application/json');\r\n\tlogger.log('file saved');\r\n};\r\n\r\nconst readRowsFromS3 = async (): Promise<readonly InternalBgsRow[]> => {\r\n\treturn new Promise<readonly InternalBgsRow[]>((resolve, reject) => {\r\n\t\tlet parseErrors = 0;\r\n\t\tlet totalParsed = 0;\r\n\t\tconst stream: Readable = s3.readStream('static.zerotoheroes.com', `api/bgs/working-rows.json`);\r\n\t\tconst result: InternalBgsRow[] = [];\r\n\t\tlet previousString = '';\r\n\t\tstream\r\n\t\t\t.on('data', chunk => {\r\n\t\t\t\tconst str = Buffer.from(chunk).toString('utf-8');\r\n\t\t\t\tconst newStr = previousString + str;\r\n\t\t\t\tconst split = newStr.split('\\n');\r\n\t\t\t\tconst rows: readonly InternalBgsRow[] = split.slice(0, split.length - 1).map(row => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst result = JSON.parse(row);\r\n\t\t\t\t\t\ttotalParsed++;\r\n\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\t// logger.warn('could not parse row', row);\r\n\t\t\t\t\t\tparseErrors++;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tpreviousString = split[split.length - 1];\r\n\t\t\t\t// logger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresult.push(...rows);\r\n\t\t\t})\r\n\t\t\t.on('end', () => {\r\n\t\t\t\tconst finalResult = result.filter(row => !!row);\r\n\t\t\t\tlogger.log('stream end', result.length, finalResult.length);\r\n\t\t\t\tlogger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresolve(finalResult);\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\n// https://stackoverflow.com/a/47204248/548701\r\nconst combine = <T>(input: readonly T[], chooseN: number): T[][] => {\r\n\tconst finalResult: T[][] = [];\r\n\r\n\tconst intermediateResult = [];\r\n\tintermediateResult.length = chooseN;\r\n\tconst combineInternal = <T>(input: readonly T[], chooseN: number, start = 0): void => {\r\n\t\tif (chooseN === 0) {\r\n\t\t\tfinalResult.push([...intermediateResult].sort());\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let i = start; i <= input.length - chooseN; i++) {\r\n\t\t\tintermediateResult[intermediateResult.length - chooseN] = input[i];\r\n\t\t\tcombineInternal(input, chooseN - 1, i + 1);\r\n\t\t}\r\n\t};\r\n\tcombineInternal(input, chooseN, 0);\r\n\r\n\treturn finalResult;\r\n};\r\n\r\nconst extractAllTribes = (rows: readonly InternalBgsRow[]): readonly Race[] => {\r\n\treturn [\r\n\t\t...new Set(\r\n\t\t\trows\r\n\t\t\t\t.map(row => row.tribes)\r\n\t\t\t\t.filter(tribes => !!tribes?.length)\r\n\t\t\t\t.map(tribes => tribes.split(',').map(strTribe => parseInt(strTribe) as Race))\r\n\t\t\t\t.reduce((a, b) => [...new Set(a.concat(b))], []),\r\n\t\t),\r\n\t];\r\n};\r\n\r\nconst buildHeroes = (\r\n\trows: readonly InternalBgsRow[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n): readonly BgsGlobalHeroStat2[] => {\r\n\tconst mappedByMmr = mmrPercentiles.map(\r\n\t\tmmrPercentile =>\r\n\t\t\t[\r\n\t\t\t\tmmrPercentile,\r\n\t\t\t\t// So that we also include rows where data collection failed\r\n\t\t\t\trows.filter(row => mmrPercentile.percentile === 100 || row.rating >= mmrPercentile.mmr),\r\n\t\t\t] as [MmrPercentile, readonly InternalBgsRow[]],\r\n\t);\r\n\t// logger.log('mappedByMmr');\r\n\treturn mappedByMmr\r\n\t\t.map(([mmr, rows]) => {\r\n\t\t\tlogger.log('building heroes for mmr', mmr.percentile, rows.length);\r\n\t\t\treturn buildHeroStats(rows).map(stat => ({\r\n\t\t\t\t...stat,\r\n\t\t\t\tmmrPercentile: mmr.percentile,\r\n\t\t\t}));\r\n\t\t})\r\n\t\t.reduce((a, b) => [...a, ...b], []);\r\n};\r\n\r\nconst buildHeroStats = (rows: readonly InternalBgsRow[]): readonly BgsGlobalHeroStat2[] => {\r\n\tconst grouped: { [groupingKey: string]: readonly InternalBgsRow[] } = groupByFunction(\r\n\t\t// (row: InternalBgsRow) => `${row.heroCardId}-${row.darkmoonPrizes}`,\r\n\t\t(row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards),\r\n\t)(rows);\r\n\t// logger.log('grouped', Object.keys(grouped).length);\r\n\r\n\tconst result = Object.values(grouped).map(groupedRows => {\r\n\t\tconst ref = groupedRows[0];\r\n\t\tconst placementDistribution = buildPlacementDistribution(groupedRows);\r\n\t\tconst combatWinrate = buildCombatWinrate(groupedRows);\r\n\t\tconst warbandStats = buildWarbandStats(groupedRows);\r\n\t\treturn {\r\n\t\t\tcardId: normalizeHeroCardId(ref.heroCardId, allCards),\r\n\t\t\ttotalMatches: groupedRows.length,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\twarbandStats: warbandStats,\r\n\t\t} as BgsGlobalHeroStat2;\r\n\t});\r\n\t// logger.log('built result');\r\n\treturn result;\r\n};\r\n\r\nconst buildWarbandStats = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalStats: number }[] => {\r\n\tconst data: { [turn: string]: { dataPoints: number; totalStats: number } } = {};\r\n\t// Before that, there was an issue with disconnects, where the first turn after the\r\n\t// reconnect would be turn 0, leading to an inflation of early turn stats\r\n\tconst validRows = rows.filter(row => row.id > 5348374);\r\n\tfor (const row of validRows) {\r\n\t\tif (!row.warbandStats?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst parsed: readonly { turn: number; totalStats: number }[] = JSON.parse(row.warbandStats);\r\n\t\tif (!parsed?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.totalStats == null || isNaN(turnInfo.totalStats)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// To avoid polluting the stats with big Tarecgosa outliers\r\n\t\t\tif (turnInfo.totalStats > 20000) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalStats: 0 };\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalStats = existingInfo.totalStats + Math.round(turnInfo.totalStats);\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t}\r\n\t}\r\n\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalStats: data[turn].totalStats,\r\n\t}));\r\n\treturn result;\r\n};\r\n\r\nconst buildCombatWinrate = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalWinrate: number }[] => {\r\n\tconst ref = rows[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_000';\r\n\r\n\tconst data: { [turn: string]: { dataPoints: number; totalWinrate: number } } = {};\r\n\tfor (const row of rows) {\r\n\t\t// logger.debug('building combatWinrate', row);\r\n\t\tif (!row.combatWinrate?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tlet parsed: readonly { turn: number; winrate: number }[] = null;\r\n\t\ttry {\r\n\t\t\tparsed = JSON.parse(row.combatWinrate);\r\n\t\t\t// logger.debug('parsed', parsed);\r\n\t\t\tif (!parsed?.length) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t} catch (e) {\r\n\t\t\tlogger.error('Could not parse combat winrate', row.id, e);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// if (debug) {\r\n\t\t// \tlogger.log('handling combat winrate', parsed);\r\n\t\t// }\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.winrate == null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t turnInfo', turnInfo);\r\n\t\t\t// }\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalWinrate: 0 };\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo', existingInfo);\r\n\t\t\t// }\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalWinrate = existingInfo.totalWinrate + Math.round(turnInfo.winrate);\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo after', existingInfo);\r\n\t\t\t// }\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t data', data);\r\n\t\t\t// }\r\n\t\t}\r\n\t}\r\n\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t data', data);\r\n\t// }\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalWinrate: data[turn].totalWinrate,\r\n\t}));\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t result', result);\r\n\t// }\r\n\treturn result;\r\n};\r\n\r\nconst loadRows = async (mysql: ServerlessMysql): Promise<readonly InternalBgsRow[]> => {\r\n\t// We actually use all the fields\r\n\tconst query = `\r\n\t\tSELECT *\r\n\t\tFROM bgs_run_stats\r\n\t\tWHERE creationDate > DATE_SUB(NOW(), INTERVAL 30 DAY);\r\n\t`;\r\n\tlogger.log('running query', query);\r\n\tconst rows: readonly InternalBgsRow[] = await mysql.query(query);\r\n\tlogger.log('rows', rows?.length, rows[0]);\r\n\treturn rows\r\n\t\t.filter(row => row.heroCardId.startsWith('TB_BaconShop_') || row.heroCardId.startsWith('BG'))\r\n\t\t.filter(\r\n\t\t\trow =>\r\n\t\t\t\trow.heroCardId !== CardIds.ArannaStarseeker_ArannaUnleashedTokenBattlegrounds &&\r\n\t\t\t\trow.heroCardId !== CardIds.QueenAzshara_NagaQueenAzsharaToken,\r\n\t\t)\r\n\t\t.map(row => ({\r\n\t\t\t...row,\r\n\t\t\theroCardId: normalizeHeroCardId(row.heroCardId, allCards),\r\n\t\t}));\r\n};\r\n\r\nconst getLastBattlegroundsPatch = async (): Promise<PatchInfo> => {\r\n\tconst patchInfo = await http(`https://static.zerotoheroes.com/hearthstone/data/patches.json`);\r\n\tconst structuredPatch = JSON.parse(patchInfo);\r\n\tconst patchNumber = structuredPatch.currentBattlegroundsMetaPatch;\r\n\treturn structuredPatch.patches.find(patch => patch.number === patchNumber);\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"build-battlegrounds-hero-stats-new.js","sourceRoot":"/","sources":["build-battlegrounds-hero-stats-new.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { getConnection, groupByFunction, http, logBeforeTimeout, logger, S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds, Race } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { ServerlessMysql } from 'serverless-mysql';\r\nimport { Readable } from 'stream';\r\nimport { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat2, BgsGlobalStats2, MmrPercentile } from './bgs-global-stats';\r\nimport { buildMmrPercentiles, buildPlacementDistribution, filterRowsForTimePeriod, PatchInfo } from './common';\r\nimport { InternalBgsRow } from './internal-model';\r\nimport { handleQuests } from './quests';\r\nimport { handleQuestsV2 } from './quests-v2/quests-v2';\r\nimport { handleStatsV2 } from './stats-v2/stats-v2';\r\nimport { formatDate, normalizeHeroCardId } from './utils/util-functions';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allTimePeriods: ('all-time' | 'past-three' | 'past-seven' | 'last-patch')[] = [\r\n\t'all-time',\r\n\t'past-three',\r\n\t'past-seven',\r\n\t'last-patch',\r\n];\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\tlogger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\tconst lastPatch = await getLastBattlegroundsPatch();\r\n\r\n\tif (event.quests) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuests(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.questsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuestsV2(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.statsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleStatsV2(timePeriod, rows, lastPatch, allCards);\r\n\t\t}\r\n\t} else if (event.permutation) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handlePermutation(event.permutation, timePeriod, event.allTribes, rows, lastPatch);\r\n\t\t}\r\n\t} else {\r\n\t\tconst mysql = await getConnection();\r\n\t\tconst rows: readonly InternalBgsRow[] = await loadRows(mysql);\r\n\t\tawait mysql.end();\r\n\t\tawait saveRowsOnS3(rows);\r\n\t\tawait dispatchNewLambdas(rows, context);\r\n\t\tawait dispatchQuestsLambda(rows, context);\r\n\t\tawait dispatchQuestsV2Lambda(rows, context);\r\n\t\tawait dispatchStatsV2Lambda(rows, context);\r\n\t}\r\n\r\n\tcleanup();\r\n\treturn { statusCode: 200, body: null };\r\n};\r\n\r\nconst dispatchQuestsLambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquests: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquestsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tstatsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchNewLambdas = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst allTribes = extractAllTribes(rows);\r\n\tlogger.log('all tribes', allTribes);\r\n\tconst tribePermutations: ('all' | Race[])[] = ['all', ...combine(allTribes, 5)];\r\n\tlogger.log('tribe permutations, should be 127 (126 + 1), because 9 tribes', tribePermutations.length);\r\n\tfor (const tribes of tribePermutations) {\r\n\t\tlogger.log('handling tribes', tribes, tribes !== 'all' && tribes.join('-'));\r\n\t\t// if (tribes !== 'all') {\r\n\t\t// \tcontinue;\r\n\t\t// }\r\n\t\tconst newEvent = {\r\n\t\t\tpermutation: tribes,\r\n\t\t\tallTribes: allTribes,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tlogger.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\tlogger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst handlePermutation = async (\r\n\ttribes: 'all' | readonly Race[],\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\tallTribes: readonly Race[],\r\n\trows: readonly InternalBgsRow[],\r\n\tlastPatch: PatchInfo,\r\n) => {\r\n\tconsole.log('total rows', rows.length);\r\n\tconst rowsForTimePeriod = filterRowsForTimePeriod(rows, timePeriod, lastPatch);\r\n\tconsole.log('rows for time period', rowsForTimePeriod.length);\r\n\tconst tribesStr = tribes === 'all' ? null : tribes.join(',');\r\n\tconst rowsWithTribes = !!tribesStr\r\n\t\t? rowsForTimePeriod.filter(row => !!row.tribes).filter(row => row.tribes === tribesStr)\r\n\t\t: rowsForTimePeriod;\r\n\tconsole.log('rowsWithTribes', rowsWithTribes.length);\r\n\tconst mmrPercentiles: readonly MmrPercentile[] = buildMmrPercentiles(rowsWithTribes);\r\n\tlogger.log('handling permutation', tribes, timePeriod, rows?.length, rowsWithTribes?.length);\r\n\tconst stats: readonly BgsGlobalHeroStat2[] = buildHeroes(rowsWithTribes, mmrPercentiles).map(stat => ({\r\n\t\t...stat,\r\n\t\ttribes: tribes === 'all' ? allTribes : tribes,\r\n\t\tdate: timePeriod,\r\n\t}));\r\n\tconst statsForTribes: BgsGlobalStats2 = {\r\n\t\tlastUpdateDate: formatDate(new Date()),\r\n\t\tmmrPercentiles: mmrPercentiles,\r\n\t\theroStats: stats,\r\n\t\tallTribes: allTribes,\r\n\t\ttotalMatches: stats.map(s => s.totalMatches).reduce((a, b) => a + b, 0),\r\n\t};\r\n\tlogger.log('\\tbuilt stats', statsForTribes.totalMatches, statsForTribes.heroStats?.length);\r\n\tconst tribesSuffix = tribes === 'all' ? 'all-tribes' : tribes.join('-');\r\n\tconst timeSuffix = timePeriod;\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(statsForTribes)),\r\n\t\t'static.zerotoheroes.com',\r\n\t\t`api/bgs/heroes/bgs-global-stats-${tribesSuffix}-${timeSuffix}.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n\r\nconst saveRowsOnS3 = async (rows: readonly InternalBgsRow[]) => {\r\n\tlogger.log('saving rows on s3', rows.length);\r\n\tawait s3.writeArrayAsMultipart(rows, 'static.zerotoheroes.com', `api/bgs/working-rows.json`, 'application/json');\r\n\tlogger.log('file saved');\r\n};\r\n\r\nconst readRowsFromS3 = async (): Promise<readonly InternalBgsRow[]> => {\r\n\treturn new Promise<readonly InternalBgsRow[]>((resolve, reject) => {\r\n\t\tlet parseErrors = 0;\r\n\t\tlet totalParsed = 0;\r\n\t\tconst stream: Readable = s3.readStream('static.zerotoheroes.com', `api/bgs/working-rows.json`);\r\n\t\tconst result: InternalBgsRow[] = [];\r\n\t\tlet previousString = '';\r\n\t\tstream\r\n\t\t\t.on('data', chunk => {\r\n\t\t\t\tconst str = Buffer.from(chunk).toString('utf-8');\r\n\t\t\t\tconst newStr = previousString + str;\r\n\t\t\t\tconst split = newStr.split('\\n');\r\n\t\t\t\tconst rows: readonly InternalBgsRow[] = split.slice(0, split.length - 1).map(row => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst result = JSON.parse(row);\r\n\t\t\t\t\t\ttotalParsed++;\r\n\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\t// logger.warn('could not parse row', row);\r\n\t\t\t\t\t\tparseErrors++;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tpreviousString = split[split.length - 1];\r\n\t\t\t\t// logger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresult.push(...rows);\r\n\t\t\t})\r\n\t\t\t.on('end', () => {\r\n\t\t\t\tconst finalResult = result.filter(row => !!row);\r\n\t\t\t\tlogger.log('stream end', result.length, finalResult.length);\r\n\t\t\t\tlogger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresolve(finalResult);\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\n// https://stackoverflow.com/a/47204248/548701\r\nconst combine = <T>(input: readonly T[], chooseN: number): T[][] => {\r\n\tconst finalResult: T[][] = [];\r\n\r\n\tconst intermediateResult = [];\r\n\tintermediateResult.length = chooseN;\r\n\tconst combineInternal = <T>(input: readonly T[], chooseN: number, start = 0): void => {\r\n\t\tif (chooseN === 0) {\r\n\t\t\tfinalResult.push([...intermediateResult].sort());\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let i = start; i <= input.length - chooseN; i++) {\r\n\t\t\tintermediateResult[intermediateResult.length - chooseN] = input[i];\r\n\t\t\tcombineInternal(input, chooseN - 1, i + 1);\r\n\t\t}\r\n\t};\r\n\tcombineInternal(input, chooseN, 0);\r\n\r\n\treturn finalResult;\r\n};\r\n\r\nconst extractAllTribes = (rows: readonly InternalBgsRow[]): readonly Race[] => {\r\n\treturn [\r\n\t\t...new Set(\r\n\t\t\trows\r\n\t\t\t\t.map(row => row.tribes)\r\n\t\t\t\t.filter(tribes => !!tribes?.length)\r\n\t\t\t\t.map(tribes => tribes.split(',').map(strTribe => parseInt(strTribe) as Race))\r\n\t\t\t\t.reduce((a, b) => [...new Set(a.concat(b))], []),\r\n\t\t),\r\n\t];\r\n};\r\n\r\nconst buildHeroes = (\r\n\trows: readonly InternalBgsRow[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n): readonly BgsGlobalHeroStat2[] => {\r\n\tconst mappedByMmr = mmrPercentiles.map(\r\n\t\tmmrPercentile =>\r\n\t\t\t[\r\n\t\t\t\tmmrPercentile,\r\n\t\t\t\t// So that we also include rows where data collection failed\r\n\t\t\t\trows.filter(row => mmrPercentile.percentile === 100 || row.rating >= mmrPercentile.mmr),\r\n\t\t\t] as [MmrPercentile, readonly InternalBgsRow[]],\r\n\t);\r\n\t// logger.log('mappedByMmr');\r\n\treturn mappedByMmr\r\n\t\t.map(([mmr, rows]) => {\r\n\t\t\tlogger.log('building heroes for mmr', mmr.percentile, rows.length);\r\n\t\t\treturn buildHeroStats(rows).map(stat => ({\r\n\t\t\t\t...stat,\r\n\t\t\t\tmmrPercentile: mmr.percentile,\r\n\t\t\t}));\r\n\t\t})\r\n\t\t.reduce((a, b) => [...a, ...b], []);\r\n};\r\n\r\nconst buildHeroStats = (rows: readonly InternalBgsRow[]): readonly BgsGlobalHeroStat2[] => {\r\n\tconst grouped: { [groupingKey: string]: readonly InternalBgsRow[] } = groupByFunction(\r\n\t\t// (row: InternalBgsRow) => `${row.heroCardId}-${row.darkmoonPrizes}`,\r\n\t\t(row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards),\r\n\t)(rows);\r\n\t// logger.log('grouped', Object.keys(grouped).length);\r\n\r\n\tconst result = Object.values(grouped).map(groupedRows => {\r\n\t\tconst ref = groupedRows[0];\r\n\t\tconst placementDistribution = buildPlacementDistribution(groupedRows);\r\n\t\tconst combatWinrate = buildCombatWinrate(groupedRows);\r\n\t\tconst warbandStats = buildWarbandStats(groupedRows);\r\n\t\treturn {\r\n\t\t\tcardId: normalizeHeroCardId(ref.heroCardId, allCards),\r\n\t\t\ttotalMatches: groupedRows.length,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\twarbandStats: warbandStats,\r\n\t\t} as BgsGlobalHeroStat2;\r\n\t});\r\n\t// logger.log('built result');\r\n\treturn result;\r\n};\r\n\r\nconst buildWarbandStats = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalStats: number }[] => {\r\n\tconst data: { [turn: string]: { dataPoints: number; totalStats: number } } = {};\r\n\t// Before that, there was an issue with disconnects, where the first turn after the\r\n\t// reconnect would be turn 0, leading to an inflation of early turn stats\r\n\tconst validRows = rows.filter(row => row.id > 5348374);\r\n\tfor (const row of validRows) {\r\n\t\tif (!row.warbandStats?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst parsed: readonly { turn: number; totalStats: number }[] = JSON.parse(row.warbandStats);\r\n\t\tif (!parsed?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.totalStats == null || isNaN(turnInfo.totalStats)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// To avoid polluting the stats with big Tarecgosa outliers\r\n\t\t\tif (turnInfo.totalStats > 20000) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalStats: 0 };\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalStats = existingInfo.totalStats + Math.round(turnInfo.totalStats);\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t}\r\n\t}\r\n\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalStats: data[turn].totalStats,\r\n\t}));\r\n\treturn result;\r\n};\r\n\r\nexport const buildCombatWinrate = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalWinrate: number }[] => {\r\n\tconst ref = rows[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_000';\r\n\r\n\tconst data: { [turn: string]: { dataPoints: number; totalWinrate: number } } = {};\r\n\tfor (const row of rows) {\r\n\t\t// logger.debug('building combatWinrate', row);\r\n\t\tif (!row.combatWinrate?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tlet parsed: readonly { turn: number; winrate: number }[] = null;\r\n\t\ttry {\r\n\t\t\tparsed = JSON.parse(row.combatWinrate);\r\n\t\t\t// logger.debug('parsed', parsed);\r\n\t\t\tif (!parsed?.length) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t} catch (e) {\r\n\t\t\tlogger.error('Could not parse combat winrate', row.id, e);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// if (debug) {\r\n\t\t// \tlogger.log('handling combat winrate', parsed);\r\n\t\t// }\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.winrate == null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t turnInfo', turnInfo);\r\n\t\t\t// }\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalWinrate: 0 };\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo', existingInfo);\r\n\t\t\t// }\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalWinrate = existingInfo.totalWinrate + Math.round(turnInfo.winrate);\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo after', existingInfo);\r\n\t\t\t// }\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t data', data);\r\n\t\t\t// }\r\n\t\t}\r\n\t}\r\n\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t data', data);\r\n\t// }\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalWinrate: data[turn].totalWinrate,\r\n\t}));\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t result', result);\r\n\t// }\r\n\treturn result;\r\n};\r\n\r\nconst loadRows = async (mysql: ServerlessMysql): Promise<readonly InternalBgsRow[]> => {\r\n\t// We actually use all the fields\r\n\tconst query = `\r\n\t\tSELECT *\r\n\t\tFROM bgs_run_stats\r\n\t\tWHERE creationDate > DATE_SUB(NOW(), INTERVAL 30 DAY);\r\n\t`;\r\n\tlogger.log('running query', query);\r\n\tconst rows: readonly InternalBgsRow[] = await mysql.query(query);\r\n\tlogger.log('rows', rows?.length, rows[0]);\r\n\treturn rows\r\n\t\t.filter(row => row.heroCardId.startsWith('TB_BaconShop_') || row.heroCardId.startsWith('BG'))\r\n\t\t.filter(\r\n\t\t\trow =>\r\n\t\t\t\trow.heroCardId !== CardIds.ArannaStarseeker_ArannaUnleashedTokenBattlegrounds &&\r\n\t\t\t\trow.heroCardId !== CardIds.QueenAzshara_NagaQueenAzsharaToken,\r\n\t\t)\r\n\t\t.map(row => ({\r\n\t\t\t...row,\r\n\t\t\theroCardId: normalizeHeroCardId(row.heroCardId, allCards),\r\n\t\t}));\r\n};\r\n\r\nconst getLastBattlegroundsPatch = async (): Promise<PatchInfo> => {\r\n\tconst patchInfo = await http(`https://static.zerotoheroes.com/hearthstone/data/patches.json`);\r\n\tconst structuredPatch = JSON.parse(patchInfo);\r\n\tconst patchNumber = structuredPatch.currentBattlegroundsMetaPatch;\r\n\treturn structuredPatch.patches.find(patch => patch.number === patchNumber);\r\n};\r\n"]}
|
|
@@ -15,6 +15,10 @@ export interface BgsGlobalHeroStat {
|
|
|
15
15
|
rank: number;
|
|
16
16
|
percentage: number;
|
|
17
17
|
}[];
|
|
18
|
+
readonly combatWinrate: readonly {
|
|
19
|
+
turn: number;
|
|
20
|
+
winrate: number;
|
|
21
|
+
}[];
|
|
18
22
|
readonly tribeStats: readonly BgsHeroTribeStat[];
|
|
19
23
|
}
|
|
20
24
|
export interface BgsHeroTribeStat {
|
|
@@ -30,4 +34,12 @@ export interface BgsHeroTribeStat {
|
|
|
30
34
|
rank: number;
|
|
31
35
|
impact: number;
|
|
32
36
|
}[];
|
|
37
|
+
readonly combatWinrate: readonly {
|
|
38
|
+
turn: number;
|
|
39
|
+
winrate: number;
|
|
40
|
+
}[];
|
|
41
|
+
readonly impactCombatWinrate: readonly {
|
|
42
|
+
turn: number;
|
|
43
|
+
impact: number;
|
|
44
|
+
}[];
|
|
33
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bgs-hero-stat.js","sourceRoot":"/","sources":["stats-v2/bgs-hero-stat.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { MmrPercentile } from '../bgs-global-stats';\r\nimport { WithMmrAndTimePeriod } from '../quests-v2/charged-stat';\r\n\r\nexport interface BgsHeroStatsV2 {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly heroStats: readonly WithMmrAndTimePeriod<BgsGlobalHeroStat>[];\r\n}\r\n\r\nexport interface BgsGlobalHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\
|
|
1
|
+
{"version":3,"file":"bgs-hero-stat.js","sourceRoot":"/","sources":["stats-v2/bgs-hero-stat.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { MmrPercentile } from '../bgs-global-stats';\r\nimport { WithMmrAndTimePeriod } from '../quests-v2/charged-stat';\r\n\r\nexport interface BgsHeroStatsV2 {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly heroStats: readonly WithMmrAndTimePeriod<BgsGlobalHeroStat>[];\r\n}\r\n\r\nexport interface BgsGlobalHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\t// // Same\r\n\t// readonly warbandStats: readonly { turn: number; dataPoints: number; totalStats: number }[];\r\n\treadonly tribeStats: readonly BgsHeroTribeStat[];\r\n}\r\n\r\nexport interface BgsHeroTribeStat {\r\n\treadonly tribe: Race;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly impactAveragePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\treadonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n}\r\n"]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
|
|
4
4
|
const reference_data_1 = require("@firestone-hs/reference-data");
|
|
5
|
+
const build_battlegrounds_hero_stats_new_1 = require("../build-battlegrounds-hero-stats-new");
|
|
5
6
|
const common_1 = require("../common");
|
|
6
7
|
const util_functions_1 = require("../utils/util-functions");
|
|
7
8
|
exports.buildStats = (rows, allCards) => {
|
|
@@ -12,12 +13,18 @@ const buildStatsForSingleHero = (rows) => {
|
|
|
12
13
|
const ref = rows[0];
|
|
13
14
|
const averagePosition = average(rows.map(r => r.rank));
|
|
14
15
|
const placementDistribution = common_1.buildPlacementDistributionWithPercentages(rows);
|
|
16
|
+
const rawCombatWinrates = build_battlegrounds_hero_stats_new_1.buildCombatWinrate(rows);
|
|
17
|
+
const combatWinrate = rawCombatWinrates.map(info => ({
|
|
18
|
+
turn: info.turn,
|
|
19
|
+
winrate: info.totalWinrate / info.dataPoints,
|
|
20
|
+
}));
|
|
15
21
|
const result = {
|
|
16
22
|
heroCardId: ref.heroCardId,
|
|
17
23
|
dataPoints: rows.length,
|
|
18
24
|
averagePosition: averagePosition,
|
|
19
25
|
placementDistribution: placementDistribution,
|
|
20
|
-
|
|
26
|
+
combatWinrate: combatWinrate,
|
|
27
|
+
tribeStats: buildTribeStats(rows, averagePosition, placementDistribution, combatWinrate),
|
|
21
28
|
};
|
|
22
29
|
if (ref.heroCardId === "TB_BaconShop_HERO_18") {
|
|
23
30
|
console.debug('Patches sanity', result);
|
|
@@ -26,13 +33,18 @@ const buildStatsForSingleHero = (rows) => {
|
|
|
26
33
|
}
|
|
27
34
|
return result;
|
|
28
35
|
};
|
|
29
|
-
const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution) => {
|
|
36
|
+
const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution, refCombatWinrate) => {
|
|
30
37
|
const uniqueTribes = [...new Set(rows.flatMap(r => r.tribes.split(',')).map(r => parseInt(r)))];
|
|
31
38
|
return uniqueTribes.map(tribe => {
|
|
32
39
|
const rowsForTribe = rows.filter(r => r.tribes.split(',').includes('' + tribe));
|
|
33
40
|
const rowsWithoutTribe = rows.filter(r => !r.tribes.split(',').includes('' + tribe));
|
|
34
41
|
const averagePosition = average(rowsForTribe.map(r => r.rank));
|
|
35
42
|
const placementDistribution = common_1.buildPlacementDistributionWithPercentages(rowsForTribe);
|
|
43
|
+
const rawCombatWinrates = build_battlegrounds_hero_stats_new_1.buildCombatWinrate(rowsForTribe);
|
|
44
|
+
const combatWinrate = rawCombatWinrates.map(info => ({
|
|
45
|
+
turn: info.turn,
|
|
46
|
+
winrate: info.totalWinrate / info.dataPoints,
|
|
47
|
+
}));
|
|
36
48
|
return {
|
|
37
49
|
tribe: tribe,
|
|
38
50
|
dataPoints: rowsForTribe.length,
|
|
@@ -51,6 +63,18 @@ const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution) =>
|
|
|
51
63
|
impact: (_b = (_a = newPlacementInfo) === null || _a === void 0 ? void 0 : _a.percentage, (_b !== null && _b !== void 0 ? _b : 0)) - p.percentage,
|
|
52
64
|
};
|
|
53
65
|
}),
|
|
66
|
+
combatWinrate: combatWinrate,
|
|
67
|
+
impactCombatWinrate: refCombatWinrate.map(c => {
|
|
68
|
+
var _a, _b;
|
|
69
|
+
const newCombatWinrate = combatWinrate.find(c2 => c2.turn === c.turn);
|
|
70
|
+
if (!newCombatWinrate) {
|
|
71
|
+
console.debug('missing winrate info', combatWinrate);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
turn: c.turn,
|
|
75
|
+
impact: (_b = (_a = newCombatWinrate) === null || _a === void 0 ? void 0 : _a.winrate, (_b !== null && _b !== void 0 ? _b : 0)) - c.winrate,
|
|
76
|
+
};
|
|
77
|
+
}),
|
|
54
78
|
};
|
|
55
79
|
});
|
|
56
80
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats-buikder.js","sourceRoot":"/","sources":["stats-v2/stats-buikder.ts"],"names":[],"mappings":";;AAAA,qEAAiE;AACjE,iEAA8E;AAC9E,sCAAsE;AAEtE,4DAA8D;AAGjD,QAAA,UAAU,GAAG,CACzB,IAA+B,EAC/B,QAAyB,EACM,EAAE;IACjC,MAAM,aAAa,GAEf,kCAAe,CAAC,CAAC,GAAmB,EAAE,EAAE,CAAC,oCAAmB,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACpF,CAAC,CAAC;AAGF,MAAM,uBAAuB,GAAG,CAAC,IAA+B,EAAqB,EAAE;IACtF,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,MAAM,qBAAqB,GAAG,kDAAyC,CAAC,IAAI,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG;
|
|
1
|
+
{"version":3,"file":"stats-buikder.js","sourceRoot":"/","sources":["stats-v2/stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds, Race } from '@firestone-hs/reference-data';\r\nimport { buildCombatWinrate } from '../build-battlegrounds-hero-stats-new';\r\nimport { buildPlacementDistributionWithPercentages } from '../common';\r\nimport { InternalBgsRow } from '../internal-model';\r\nimport { normalizeHeroCardId } from '../utils/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from './bgs-hero-stat';\r\n\r\nexport const buildStats = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap(data => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map(r => r.rank));\r\n\tconst placementDistribution = buildPlacementDistributionWithPercentages(rows);\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\tconst combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map(info => ({\r\n\t\tturn: info.turn,\r\n\t\twinrate: info.totalWinrate / info.dataPoints,\r\n\t}));\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: averagePosition,\r\n\t\tplacementDistribution: placementDistribution,\r\n\t\tcombatWinrate: combatWinrate,\r\n\t\ttribeStats: buildTribeStats(rows, averagePosition, placementDistribution, combatWinrate),\r\n\t};\r\n\tif (ref.heroCardId === CardIds.PatchesThePirateBattlegrounds) {\r\n\t\tconsole.debug('Patches sanity', result);\r\n\t\tconsole.debug(\r\n\t\t\t'Patches sanity',\r\n\t\t\tresult.tribeStats.map(t => t.impactAveragePosition * t.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\t);\r\n\t\tconsole.debug(\r\n\t\t\t'Patches sanity',\r\n\t\t\trows.filter(r => !r.tribes.includes('' + Race.PIRATE)).length,\r\n\t\t\trows.filter(r => !r.tribes.includes('' + Race.PIRATE)),\r\n\t\t);\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (\r\n\trows: readonly InternalBgsRow[],\r\n\trefAveragePosition: number,\r\n\trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n\trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap(r => r.tribes.split(',')).map(r => parseInt(r)))];\r\n\treturn uniqueTribes.map(tribe => {\r\n\t\tconst rowsForTribe = rows.filter(r => r.tribes.split(',').includes('' + tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter(r => !r.tribes.split(',').includes('' + tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map(r => r.rank));\r\n\t\tconst placementDistribution = buildPlacementDistributionWithPercentages(rowsForTribe);\r\n\t\tconst rawCombatWinrates = buildCombatWinrate(rowsForTribe);\r\n\t\tconst combatWinrate = rawCombatWinrates.map(info => ({\r\n\t\t\tturn: info.turn,\r\n\t\t\twinrate: info.totalWinrate / info.dataPoints,\r\n\t\t}));\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\timpactPlacementDistribution: refPlacementDistribution.map(p => {\r\n\t\t\t\tconst newPlacementInfo = placementDistribution.find(p2 => p2.rank === p.rank);\r\n\t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n\t\t\t\tif (!newPlacementInfo) {\r\n\t\t\t\t\tconsole.log('missing placement info', placementDistribution, p);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\trank: p.rank,\r\n\t\t\t\t\timpact: (newPlacementInfo?.percentage ?? 0) - p.percentage,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\timpactCombatWinrate: refCombatWinrate.map(c => {\r\n\t\t\t\tconst newCombatWinrate = combatWinrate.find(c2 => c2.turn === c.turn);\r\n\t\t\t\tif (!newCombatWinrate) {\r\n\t\t\t\t\tconsole.debug('missing winrate info', combatWinrate);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\tturn: c.turn,\r\n\t\t\t\t\timpact: (newCombatWinrate?.winrate ?? 0) - c.winrate,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t};\r\n\t});\r\n};\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
|