feat: ugly working version: need to work with old matchLists too

This commit is contained in:
Kalane 2021-08-11 00:12:17 +02:00
parent 41d363b981
commit 5cd0837815
10 changed files with 145 additions and 120 deletions

View file

@ -180,7 +180,12 @@ export const actions = {
const gameIds = getters.filteredMatchList
.slice(state.overview.matchIndex, state.overview.matchIndex + 10)
.map(({ gameId }) => gameId)
.map((gameId) => {
if(typeof gameId == 'string') {
return gameId
}
return gameId.gameId.toString()
})
const resp = await axios(({
url: 'match',

View file

@ -40,7 +40,9 @@ export default class MatchesController {
if (!summonerDB) {
return response.json(null)
}
const matches = await MatchService.getMatches(puuid, accountId, region, gameIds, summonerDB)
const matchesId = /^\d/.test(gameIds[0]) ? gameIds.map(id => `${region.toUpperCase()}_${id}`) : gameIds
const matches = await MatchService.getMatches(puuid, accountId, region, matchesId, summonerDB)
await summonerDB.save()
@ -67,7 +69,8 @@ export default class MatchesController {
console.log('MATCH DETAILS ALREADY SAVED')
matchDetails = alreadySaved
} else {
const match = await Jax.Match.get(gameId, region)
const matchId = `${region.toUpperCase()}_${gameId}`
const match = await Jax.Match.get(matchId, region)
matchDetails = await DetailedMatchTransformer.transform(match)
await DetailedMatch.create(matchDetails)
}

View file

@ -1,5 +1,5 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import { getV5Region } from 'App/helpers'
import { getRiotRegion } from 'App/helpers'
import RiotRateLimiter from 'riot-ratelimiter'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
@ -423,7 +423,7 @@ export default class MatchEndpoint {
public get (matchID: string, region: string): Promise<MatchDto> {
return new JaxRequest(
getV5Region(region),
getRiotRegion(region),
this.config,
`match/v5/matches/${matchID}`,
this.limiter,

View file

@ -1,5 +1,5 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import { getV5Region } from 'App/helpers'
import { getRiotRegion } from 'App/helpers'
import RiotRateLimiter from 'riot-ratelimiter'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
@ -44,7 +44,7 @@ export default class MatchlistEndpoint {
public puuid (puuid: string, region: string, beginIndex = 0, count = 100): Promise<MatchlistDto> {
return new JaxRequest(
getV5Region(region),
getRiotRegion(region),
this.config,
`match/v5/matches/by-puuid/${puuid}/ids?start=${beginIndex}&count=${count}`,
this.limiter,

View file

@ -29,7 +29,7 @@ class MatchService {
matchList = [...matchList, ...newMatchList]
alreadyIn = newMatchList.length === 0 || stopFetching(newMatchList)
// If the match is made in another region : we stop fetching
// if (matchList[matchList.length - 1].platformId.toLowerCase() !== account.region) { // TODO: check this...
// if (matchList[matchList.length - 1].platformId.toLowerCase() !== account.region) { // TODO: check if region has changed
// alreadyIn = true
// }
index += 100
@ -92,11 +92,11 @@ class MatchService {
* @param gameIds
* @param summonerDB
*/
public async getMatches (puuid: string, accountId: string, region: string, matchIds: string[], summonerDB: SummonerModel) {
public async getMatches (puuid: string, accountId: string, region: string, matchIds: MatchlistDto, summonerDB: SummonerModel) {
console.time('getMatches')
let matchesDetails: MatchModel[] = []
const matchesToGetFromRiot: string[] = []
const matchesToGetFromRiot: MatchlistDto = []
for (let i = 0; i < matchIds.length; ++i) {
const matchSaved = await Match.findOne({
summoner_puuid: puuid,
@ -122,16 +122,14 @@ class MatchService {
})
// Transform raw matches data
// const transformedMatches = await BasicMatchTransformer.transform(matchesFromApi, { puuid, accountId })
const transformedMatches = await BasicMatchTransformer.transform(matchesFromApi, { puuid, accountId })
/* Save all matches from Riot Api in db */
// for (const match of transformedMatches) {
// // await Match.create(match)
// match.newMatch = true
// }
// matchesDetails = [...matchesDetails, ...transformedMatches]
matchesDetails = [...matchesDetails, ...matchesFromApi as unknown as MatchModel[]]
for (const match of transformedMatches) {
await Match.create(match)
match.newMatch = true
}
matchesDetails = [...matchesDetails, ...transformedMatches]
}
/* Sort matches */

View file

@ -13,13 +13,12 @@ class BasicMatchTransformer extends MatchTransformer {
// Global data about the match
const globalInfos = super.getGameInfos(match)
const identity = match.participantIdentities.find((p) => p.player.currentAccountId === accountId)
const player = match.participants[identity!.participantId - 1]
const player = match.info.participants.find(p => p.puuid === puuid)!
let win = match.teams.find((t) => t.teamId === player.teamId)!.win
let win = match.info.teams.find((t) => t.teamId === player.teamId)!.win ? 'Win' : 'Fail'
// Match less than 5min
if (match.gameDuration < 300) {
if (match.info.gameDuration < 300) {
win = 'Remake'
}
@ -29,16 +28,15 @@ class BasicMatchTransformer extends MatchTransformer {
// Teams data
const allyTeam: ParticipantBasic[] = []
const enemyTeam: ParticipantBasic[] = []
for (let summoner of match.participantIdentities) {
const allData = match.participants[summoner.participantId - 1]
for (let summoner of match.info.participants) {
const playerInfos = {
account_id: summoner.player.currentAccountId,
name: summoner.player.summonerName,
role: super.getRoleName(allData.timeline, match.queueId),
champion: super.getChampion(allData.championId),
account_id: summoner.puuid, // TODO: switch to puuid
name: summoner.summonerName,
role: super.getRoleName(summoner.teamPosition, match.info.queueId),
champion: super.getChampion(summoner.championId),
}
if (allData.teamId === player.teamId) {
if (summoner.teamId === player.teamId) {
allyTeam.push(playerInfos)
} else {
enemyTeam.push(playerInfos)
@ -49,9 +47,10 @@ class BasicMatchTransformer extends MatchTransformer {
super.getMatchRoles(match, allyTeam, enemyTeam, player.teamId, playerData)
return {
account_id: identity!.player.currentAccountId,
account_id: accountId,
summoner_puuid: puuid,
gameId: match.gameId,
gameId: match.info.gameId,
matchId: match.metadata.matchId,
result: win,
allyTeam,
enemyTeam,

View file

@ -1,5 +1,5 @@
import { Ban, DetailedMatchModel } from 'App/Models/DetailedMatch'
import { MatchDto, TeamStatsDto } from 'App/Services/Jax/src/Endpoints/MatchEndpoint'
import { MatchDto, TeamDto } from 'App/Services/Jax/src/Endpoints/MatchEndpoint'
import MatchTransformer from './MatchTransformer'
/**
@ -13,22 +13,22 @@ class DetailedMatchTransformer extends MatchTransformer {
* @param match raw match data from Riot API
* @param team raw team data from Riot API
*/
private getTeamData (match: MatchDto, team: TeamStatsDto) {
let win = team.win
if (match.gameDuration < 300) {
private getTeamData (match: MatchDto, team: TeamDto) {
let win = team.win ? 'Win' : 'Fail'
if (match.info.gameDuration < 300) {
win = 'Remake'
}
// Global stats of the team
const teamPlayers = match.participants.filter(p => p.teamId === team.teamId)
const teamPlayers = match.info.participants.filter(p => p.teamId === team.teamId)
const teamStats = teamPlayers.reduce((prev, cur) => {
prev.kills += cur.stats.kills
prev.deaths += cur.stats.deaths
prev.assists += cur.stats.assists
prev.gold += cur.stats.goldEarned
prev.dmgChamp += cur.stats.totalDamageDealtToChampions
prev.dmgObj += cur.stats.damageDealtToObjectives
prev.dmgTaken += cur.stats.totalDamageTaken
prev.kills += cur.kills
prev.deaths += cur.deaths
prev.assists += cur.assists
prev.gold += cur.goldEarned
prev.dmgChamp += cur.totalDamageDealtToChampions
prev.dmgObj += cur.damageDealtToObjectives
prev.dmgTaken += cur.totalDamageTaken
return prev
}, { kills: 0, deaths: 0, assists: 0, gold: 0, dmgChamp: 0, dmgObj: 0, dmgTaken: 0 })
@ -57,15 +57,15 @@ class DetailedMatchTransformer extends MatchTransformer {
return {
bans,
barons: team.baronKills,
barons: team.objectives.baron.kills,
color: team.teamId === 100 ? 'Blue' : 'Red',
dragons: team.dragonKills,
inhibitors: team.inhibitorKills,
dragons: team.objectives.dragon.kills,
inhibitors: team.objectives.inhibitor.kills,
players,
result: win,
riftHerald: team.riftHeraldKills,
riftHerald: team.objectives.riftHerald.kills,
teamStats,
towers: team.towerKills,
towers: team.objectives.tower.kills,
}
}
@ -80,14 +80,14 @@ class DetailedMatchTransformer extends MatchTransformer {
const globalInfos = super.getGameInfos(match)
// Teams
const firstTeam = this.getTeamData(match, match.teams[0])
const secondTeam = this.getTeamData(match, match.teams[1])
const firstTeam = this.getTeamData(match, match.info.teams[0])
const secondTeam = this.getTeamData(match, match.info.teams[1])
// Roles
super.getMatchRoles(match, firstTeam.players, secondTeam.players)
return {
gameId: match.gameId,
gameId: match.info.gameId,
blueTeam: firstTeam.color === 'Blue' ? firstTeam : secondTeam,
redTeam: firstTeam.color === 'Blue' ? secondTeam : firstTeam,
...globalInfos,

View file

@ -7,6 +7,7 @@ import { TeamStats } from 'App/Models/DetailedMatch'
import {
MatchDto,
ParticipantDto,
PerksDto,
} from 'App/Services/Jax/src/Endpoints/MatchEndpoint'
export interface PlayerRole {
@ -83,23 +84,22 @@ export default abstract class MatchTransformer {
* @param teamStats : if detailed, the teamStats argument is mandatory
*/
public getPlayerData (match: MatchDto, player: ParticipantDto, detailed: boolean, teamStats?: TeamStats) {
const identity = match.participantIdentities.find(p => p.participantId === player.participantId)
const name = identity!.player.summonerName
const name = player.summonerName
const champion = this.getChampion(player.championId)
const role = this.getRoleName(player.timeline, match.queueId)
const level = player.stats.champLevel
const role = this.getRoleName(player.teamPosition, match.info.queueId)
const level = player.champLevel
// Regular stats / Full match stats
const stats: Stats = {
kills: player.stats.kills,
deaths: player.stats.deaths,
assists: player.stats.assists,
minions: player.stats.totalMinionsKilled + player.stats.neutralMinionsKilled,
vision: player.stats.visionScore,
gold: player.stats.goldEarned,
dmgChamp: player.stats.totalDamageDealtToChampions,
dmgObj: player.stats.damageDealtToObjectives,
dmgTaken: player.stats.totalDamageTaken,
kills: player.kills,
deaths: player.deaths,
assists: player.assists,
minions: player.totalMinionsKilled + player.neutralMinionsKilled,
vision: player.visionScore,
gold: player.goldEarned,
dmgChamp: player.totalDamageDealtToChampions,
dmgObj: player.damageDealtToObjectives,
dmgTaken: player.totalDamageTaken,
kp: 0,
kda: 0,
realKda: 0,
@ -118,44 +118,48 @@ export default abstract class MatchTransformer {
if (detailed) {
teamStats = teamStats!
percentStats = {
minions: +(stats.minions / (match.gameDuration / 60)).toFixed(2),
vision: +(stats.vision / (match.gameDuration / 60)).toFixed(2),
gold: +(player.stats.goldEarned * 100 / teamStats.gold).toFixed(1) + '%',
dmgChamp: +(player.stats.totalDamageDealtToChampions * 100 / teamStats.dmgChamp).toFixed(1) + '%',
dmgObj: +(teamStats.dmgObj ? player.stats.damageDealtToObjectives * 100 / teamStats.dmgObj : 0).toFixed(1) + '%',
dmgTaken: +(player.stats.totalDamageTaken * 100 / teamStats.dmgTaken).toFixed(1) + '%',
minions: +(stats.minions / (match.info.gameDuration / 60)).toFixed(2),
vision: +(stats.vision / (match.info.gameDuration / 60)).toFixed(2),
gold: +(player.goldEarned * 100 / teamStats.gold).toFixed(1) + '%',
dmgChamp: +(player.totalDamageDealtToChampions * 100 / teamStats.dmgChamp).toFixed(1) + '%',
dmgObj: +(teamStats.dmgObj ? player.damageDealtToObjectives * 100 / teamStats.dmgObj : 0).toFixed(1) + '%',
dmgTaken: +(player.totalDamageTaken * 100 / teamStats.dmgTaken).toFixed(1) + '%',
}
stats.kp = teamStats.kills === 0 ? '0%' : +((stats.kills + stats.assists) * 100 / teamStats.kills).toFixed(1) + '%'
} else {
const totalKills = match.participants.reduce((prev, current) => {
const totalKills = match.info.participants.reduce((prev, current) => {
if (current.teamId !== player.teamId) {
return prev
}
return prev + current.stats.kills
return prev + current.kills
}, 0)
stats.criticalStrike = player.stats.largestCriticalStrike
stats.killingSpree = player.stats.largestKillingSpree
stats.doubleKills = player.stats.doubleKills
stats.tripleKills = player.stats.tripleKills
stats.quadraKills = player.stats.quadraKills
stats.pentaKills = player.stats.pentaKills
stats.heal = player.stats.totalHeal
stats.towers = player.stats.turretKills
stats.longestLiving = player.stats.longestTimeSpentLiving
stats.criticalStrike = player.largestCriticalStrike
stats.killingSpree = player.largestKillingSpree
stats.doubleKills = player.doubleKills
stats.tripleKills = player.tripleKills
stats.quadraKills = player.quadraKills
stats.pentaKills = player.pentaKills
stats.heal = player.totalHeal
stats.towers = player.turretKills
stats.longestLiving = player.longestTimeSpentLiving
stats.kp = totalKills === 0 ? 0 : +((stats.kills + stats.assists) * 100 / totalKills).toFixed(1)
}
let primaryRune: string | null = null
let secondaryRune: string | null = null
if (player.stats.perkPrimaryStyle) {
({ primaryRune, secondaryRune } = this.getPerksImages(player.stats.perk0, player.stats.perkSubStyle))
const primaryStyle = player.perks.styles.find(s => s.description === 'primaryStyle')
const subStyle = player.perks.styles.find(s => s.description === 'subStyle')
if (primaryStyle && subStyle && primaryStyle.selections.length) {
({ primaryRune, secondaryRune } = this.getPerksImages(primaryStyle.selections[0].perk, subStyle.style))
}
const items: (Item | null)[] = []
for (let i = 0; i < 6; i++) {
const id = player.stats['item' + i]
const id = player['item' + i]
if (id === 0) {
items.push(null)
continue
@ -182,7 +186,7 @@ export default abstract class MatchTransformer {
const playerData: ParticipantDetails = {
name,
summonerId: identity!.player.summonerId,
summonerId: player.summonerId,
champion,
role,
primaryRune,
@ -197,25 +201,25 @@ export default abstract class MatchTransformer {
playerData.percentStats = percentStats!
}
playerData.perks = this.getFullPerks(player.stats)
playerData.perks = this.getFullPerks(player.perks)
return playerData
}
public getFullPerks (stats: ParticipantStatsDto) {
public getFullPerks (perksDto: PerksDto) {
const perks: Perks = {
primaryStyle: stats.perkPrimaryStyle,
secondaryStyle: stats.perkSubStyle,
primaryStyle: perksDto.styles.find(s => s.description === 'primaryStyle')!.style,
secondaryStyle: perksDto.styles.find(s => s.description === 'subStyle')!.style,
selected: [],
}
for (let i = 0; i < 6; i++) {
perks.selected.push(stats[`perk${i}`])
for (const styles of perksDto.styles) {
for (const perk of styles.selections) {
perks.selected.push(perk.perk)
}
}
for (let i = 0; i < 3; i++) {
perks.selected.push(stats[`statPerk${i}`])
}
perks.selected.concat(Object.values(perksDto.statPerks))
return perks
}
@ -245,16 +249,16 @@ export default abstract class MatchTransformer {
* @param timeline from Riot Api
* @param gamemode of the match to check if a role is needed
*/
public getRoleName (timeline: ParticipantTimelineDto, gamemode: number) {
if (!queuesWithRole.includes(gamemode)) {
public getRoleName (teamPosition: string, gamemode: number) {
if (!queuesWithRole.includes(gamemode) || !teamPosition) {
return 'NONE'
}
if (timeline.lane === 'BOTTOM' && timeline.role.includes('SUPPORT')) {
if (teamPosition === 'UTILITY') {
return 'SUPPORT'
}
return timeline.lane
return teamPosition
}
/**
@ -317,11 +321,11 @@ export default abstract class MatchTransformer {
let allyChamps: PlayerRole[] = []
let enemyChamps: PlayerRole[] = []
match.participants.map(p => {
const items = [p.stats.item0, p.stats.item1, p.stats.item2, p.stats.item3, p.stats.item4, p.stats.item5]
match.info.participants.map(p => {
const items = [p.item0, p.item1, p.item2, p.item3, p.item4, p.item5]
const playerRole = {
champion: p.championId,
jungle: p.spell1Id === 11 || p.spell2Id === 11,
jungle: p.summoner1Id === 11 || p.summoner2Id === 11,
support: supportItems.some(suppItem => items.includes(suppItem)),
}
p.teamId === allyTeamId ? allyChamps.push(playerRole) : enemyChamps.push(playerRole)

View file

@ -29,7 +29,7 @@ export default class MatchesIndexValidator {
accountId: schema.string(),
region: schema.string(),
gameIds: schema.array().members(
schema.number()
schema.string()
),
season: schema.number.optional(),
})

View file

@ -3,34 +3,50 @@ import { ParticipantBasic, ParticipantDetails } from './Models/Match'
/**
* All League of Legends regions used in Riot API
*/
export type Region = 'br1' | 'eun1' | 'euw1' | 'jp1' | 'kr' | 'la1' | 'la2' | 'na1' | 'oc1' | 'tr1' | 'ru'
export enum LeagueRegion {
BRAZIL = 'br1',
EUROPE_NORTHEAST = 'eun1',
EUROPE_WEST = 'euw1',
KOREA = 'kr',
LATIN_AMERICA_NORTH = 'la1',
LATIN_AMERICA_SOUTH = 'la2',
NORTH_AMERICA = 'na1',
OCEANIA = 'oc1',
RUSSIA = 'ru',
TURKEY = 'tr1',
JAPAN = 'jp1',
}
/**
* New regions used in Riot API >= v5
*/
export type V5Region = 'americas' | 'asia' | 'europe'
export enum RiotRegion {
AMERICAS = 'americas',
ASIA = 'asia',
EUROPE = 'europe',
}
/**
* Map old Riot API regions to new ones
* @param region : old region
* @returns new region name
*/
export function getV5Region (region: string): V5Region {
switch (region as Region) { // TODO: remove cast when region is typed to "Region" everywhere instead of string
case 'na1':
case 'br1':
case 'la1':
case 'la2':
case 'oc1':
return 'americas'
case 'kr':
case 'jp1':
return 'asia'
case 'eun1':
case 'euw1':
case 'tr1':
case 'ru':
return 'europe'
export function getRiotRegion (region: string): RiotRegion {
switch (region as LeagueRegion) { // TODO: remove cast when region is typed to "Region" everywhere instead of string
case LeagueRegion.NORTH_AMERICA:
case LeagueRegion.BRAZIL:
case LeagueRegion.LATIN_AMERICA_NORTH:
case LeagueRegion.LATIN_AMERICA_SOUTH:
case LeagueRegion.OCEANIA:
return RiotRegion.AMERICAS
case LeagueRegion.KOREA:
case LeagueRegion.JAPAN:
return RiotRegion.ASIA
case LeagueRegion.EUROPE_NORTHEAST:
case LeagueRegion.EUROPE_WEST:
case LeagueRegion.TURKEY:
case LeagueRegion.RUSSIA:
return RiotRegion.EUROPE
}
}