diff --git a/package-lock.json b/package-lock.json index 2cce4e6..795accf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -214,11 +214,11 @@ } }, "@firestone-hs/hs-replay-xml-parser": { - "version": "0.0.55", - "resolved": "https://registry.npmjs.org/@firestone-hs/hs-replay-xml-parser/-/hs-replay-xml-parser-0.0.55.tgz", - "integrity": "sha512-UafKRK3MFxuvwOstCBEPlALXllgqveyBjhWK21MasZCsf8jLxdP6OBs/JRmnUt6rPofmfdm38u+1fGgw5gIRVQ==", + "version": "0.0.78", + "resolved": "https://registry.npmjs.org/@firestone-hs/hs-replay-xml-parser/-/hs-replay-xml-parser-0.0.78.tgz", + "integrity": "sha512-Y1fN8T2k3IloGRW8uqVvlhBK3xUZM4vT2MFIVSmjhPkxuJ+ISyUBo3blFWB8EopyplSigZrOgXZcUU0vCdPsmQ==", "requires": { - "@firestone-hs/reference-data": "^0.1.34", + "@firestone-hs/reference-data": "^0.1.92", "@types/elementtree": "^0.1.0", "big-integer": "^1.6.48", "elementtree": "^0.1.7", @@ -226,9 +226,9 @@ } }, "@firestone-hs/reference-data": { - "version": "0.1.136", - "resolved": "https://registry.npmjs.org/@firestone-hs/reference-data/-/reference-data-0.1.136.tgz", - "integrity": "sha512-JRU1ABceaOLgqWSXbCvNLfp1lXxMmCQkBEHRLc0Q2146A444oV5p4f5BQa1jB8zEhbGXiEvj6sUg2attN0aZVg==", + "version": "0.1.140", + "resolved": "https://registry.npmjs.org/@firestone-hs/reference-data/-/reference-data-0.1.140.tgz", + "integrity": "sha512-EnUwsYHGO0y+UgbASqcxySVOns0HM15SvAlXhykKKRc8XxubbzdAuzkyKZXgCR9Bwr57uvoDZfm8LU2E2o77tA==", "requires": { "cross-fetch": "^3.0.4", "rxjs": "~6.6.7", @@ -3103,8 +3103,7 @@ }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "resolved": "", "dev": true, "optional": true }, diff --git a/package.json b/package.json index 95864f6..0242cfb 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "dist/**/*" ], "dependencies": { - "@firestone-hs/hs-replay-xml-parser": "0.0.55", - "@firestone-hs/reference-data": "^0.1.136", + "@firestone-hs/hs-replay-xml-parser": "0.0.78", + "@firestone-hs/reference-data": "^0.1.140", "@types/elementtree": "^0.1.0", "aws-sdk": "^2.524.0", "elementtree": "^0.1.7", diff --git a/src/build-battlegrounds-hero-stats.ts b/src/build-battlegrounds-hero-stats.ts index 4e465c8..a328831 100644 --- a/src/build-battlegrounds-hero-stats.ts +++ b/src/build-battlegrounds-hero-stats.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ +import { AllCardsService } from '@firestone-hs/reference-data'; import { ServerlessMysql } from 'serverless-mysql'; import { gzipSync } from 'zlib'; import { BgsGlobalHeroStat, BgsHeroTier } from './bgs-global-stats'; @@ -6,21 +7,23 @@ import { getConnection as getConnectionStats } from './db/rds'; import { getConnection as getConnectionBgs } from './db/rds-bgs'; import { S3 } from './db/s3'; import { loadStats } from './retrieve-bgs-global-stats'; -import { http } from './utils/util-functions'; +import { http, normalizeHeroCardId } from './utils/util-functions'; const s3 = new S3(); +const allCards = new AllCardsService(); // This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use // the more traditional callback-style handler. // [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/ export default async (event): Promise => { + await allCards.initializeCardsDb(); + const lastBattlegroundsPatch = await getLastBattlegroundsPatch(); + const mysql = await getConnectionStats(); const mysqlBgs = await getConnectionBgs(); - const lastBattlegroundsPatch = await getLastBattlegroundsPatch(); - - await updateAggregatedStats(mysqlBgs, mysql, lastBattlegroundsPatch); - await updateLastPeriodStats(mysqlBgs, mysql, lastBattlegroundsPatch); + await updateAggregatedStats(mysqlBgs, mysql, lastBattlegroundsPatch, allCards); + await updateLastPeriodStats(mysqlBgs, mysql, lastBattlegroundsPatch, allCards); const stats = await loadStats(mysql, mysqlBgs); const stringResults = JSON.stringify(stats); @@ -45,19 +48,29 @@ const getLastBattlegroundsPatch = async (): Promise => { return structuredPatch.currentBattlegroundsMetaPatch; }; -const updateAggregatedStats = async (mysqlBgs: ServerlessMysql, mysqlStats: ServerlessMysql, buildNumber: number) => { +const updateAggregatedStats = async ( + mysqlBgs: ServerlessMysql, + mysqlStats: ServerlessMysql, + buildNumber: number, + allCards: AllCardsService, +) => { // This won't be fully accurate, as not all update will be installed simulatenously, but it's good enough const now = Date.now(); const earliestStartDate = new Date(now - 10 * 24 * 60 * 60 * 1000).toISOString(); - await updateStats(mysqlBgs, mysqlStats, earliestStartDate, buildNumber, false); + await updateStats(mysqlBgs, mysqlStats, earliestStartDate, buildNumber, false, allCards); }; // TODO: remove this lastperiod stuff, add a new column with the last update Date, and do a query on that last update date -const updateLastPeriodStats = async (mysqlBgs: ServerlessMysql, mysqlStats: ServerlessMysql, buildNumber: number) => { +const updateLastPeriodStats = async ( + mysqlBgs: ServerlessMysql, + mysqlStats: ServerlessMysql, + buildNumber: number, + allCards: AllCardsService, +) => { // Get all the reviews from the last day const now = Date.now(); const earliestStartDate = new Date(now - 24 * 60 * 60 * 1000).toISOString(); - await updateStats(mysqlBgs, mysqlStats, earliestStartDate, buildNumber, true); + await updateStats(mysqlBgs, mysqlStats, earliestStartDate, buildNumber, true, allCards); }; const updateStats = async ( @@ -66,6 +79,7 @@ const updateStats = async ( creationDate: string, buildNumber: number, insertCreationDate: boolean, + allCards: AllCardsService, ) => { const allHeroesQuery = ` SELECT distinct playerCardId @@ -77,8 +91,8 @@ const updateStats = async ( `; const allHeroesResult: readonly any[] = await mysqlStats.query(allHeroesQuery); const allHeroes: readonly string[] = allHeroesResult - .map(result => result.playerCardId) - .filter(playerCardId => playerCardId !== 'TB_BaconShop_HERO_59t'); + .filter(playerCardId => playerCardId !== 'TB_BaconShop_HERO_59t') + .map(result => normalizeHeroCardId(result.playerCardId, allCards)); const heroStatsQuery = ` SELECT playerCardId, additionalResult, count(*) as count, max(creationDate) as lastPlayedDate @@ -91,12 +105,13 @@ const updateStats = async ( GROUP BY playerCardId, additionalResult `; const heroStatsResults: readonly any[] = ((await mysqlStats.query(heroStatsQuery)) as any[]) + .filter(result => result.playerCardId !== 'TB_BaconShop_HERO_59t') .map(result => ({ ...result, + playerCardId: normalizeHeroCardId(result.playerCardId, allCards), additionalResult: parseInt(result.additionalResult), })) - .filter(result => result.additionalResult > 0) - .filter(result => result.playerCardId !== 'TB_BaconShop_HERO_59t'); + .filter(result => result.additionalResult > 0); const stats: BgsGlobalHeroStat[] = allHeroes.map(heroCardId => buildHeroInfo(heroCardId, heroStatsResults)); diff --git a/src/utils/util-functions.ts b/src/utils/util-functions.ts index ec67e25..cf1c158 100644 --- a/src/utils/util-functions.ts +++ b/src/utils/util-functions.ts @@ -1,5 +1,4 @@ -import { AllCardsService } from '@firestone-hs/reference-data'; -import { ReferenceCard } from '@firestone-hs/reference-data/lib/models/reference-cards/reference-card'; +import { AllCardsService, ReferenceCard } from '@firestone-hs/reference-data'; import fetch, { RequestInfo } from 'node-fetch'; function partitionArray(array: readonly T[], partitionSize: number): readonly T[][] { @@ -60,3 +59,32 @@ export const getCardFromCardId = (cardId: number | string, cards: AllCardsServic }; export { partitionArray, http, sleep }; + +export const normalizeHeroCardId = (heroCardId: string, allCards: AllCardsService = null): string => { + if (!heroCardId) { + return heroCardId; + } + + if (allCards) { + const heroCard = allCards.getCard(heroCardId); + if (!!heroCard?.battlegroundsHeroParentDbfId) { + const parentCard = allCards.getCardFromDbfId(heroCard.battlegroundsHeroParentDbfId); + if (!!parentCard) { + return parentCard.id; + } + } + } + // Fallback to regex + const bgHeroSkinMatch = heroCardId.match(/(.*)_SKIN_.*/); + console.debug('normalizing', heroCardId, bgHeroSkinMatch); + if (bgHeroSkinMatch) { + return bgHeroSkinMatch[1]; + } + + switch (heroCardId) { + case 'TB_BaconShop_HERO_59t': + return 'TB_BaconShop_HERO_59'; + default: + return heroCardId; + } +};