feat: use custom RoleIdentification if Riot roles are badly identified

This commit is contained in:
Valentin Kaelin 2020-06-21 20:58:04 +02:00
parent 5cd9b7600f
commit c16974fcfb
5 changed files with 84 additions and 24 deletions

View file

@ -4,7 +4,7 @@ const got = require('got')
const Redis = use('Redis') const Redis = use('Redis')
class RoleIdentificationService { class RoleIdentificationService {
_getPermutations (array) { _getPermutations(array) {
const result = [] const result = []
for (let i = 0; i < array.length; i++) { for (let i = 0; i < array.length; i++) {
@ -21,13 +21,13 @@ class RoleIdentificationService {
return result return result
} }
_calculateMetric (championPositions, bestPositions) { _calculateMetric(championPositions, bestPositions) {
return Object.entries(bestPositions).reduce((agg, [position, champion]) => { return Object.entries(bestPositions).reduce((agg, [position, champion]) => {
return agg + (championPositions[champion][position] || 0) return agg + (championPositions[champion][position] || 0)
}, 0) / Object.keys(bestPositions).length }, 0) / Object.keys(bestPositions).length
} }
_getPositions (championPositions, composition, top, jungle, middle, adc, support) { _getPositions(championPositions, composition, top, jungle, middle, adc, support) {
// Set the initial guess to be the champion in the composition, order doesn't matter // Set the initial guess to be the champion in the composition, order doesn't matter
let bestPositions = { let bestPositions = {
'TOP': composition[0], 'TOP': composition[0],
@ -104,7 +104,7 @@ class RoleIdentificationService {
/** /**
* Get the CDN data of the champion playrates by role * Get the CDN data of the champion playrates by role
*/ */
async pullData () { async pullData() {
const url = 'http://cdn.merakianalytics.com/riot/lol/resources/latest/en-US/championrates.json' const url = 'http://cdn.merakianalytics.com/riot/lol/resources/latest/en-US/championrates.json'
// Check if cached // Check if cached
@ -144,13 +144,13 @@ class RoleIdentificationService {
* @param composition * @param composition
* @param jungle * @param jungle
*/ */
getRoles (championPositions, composition, jungle = null) { getRoles(championPositions, composition, jungle = null) {
const identified = {} const identified = {}
let positions = {} let positions = {}
let secondaryPositions = null let secondaryPositions = null
let secondaryMetric = -Infinity let secondaryMetric = -Infinity
if(jungle) { if (jungle) {
identified['JUNGLE'] = jungle identified['JUNGLE'] = jungle
} }
@ -193,7 +193,13 @@ class RoleIdentificationService {
identified[best[0]] = best[1] identified[best[0]] = best[1]
} }
return positions // Rename UTILITY to SUPPORT
const {
UTILITY: SUPPORT,
...rest
} = positions
return { ...rest, SUPPORT }
} }
} }

View file

@ -1,6 +1,7 @@
'use strict' 'use strict'
const MatchTransformer = use('App/Transformers/MatchTransformer') const MatchTransformer = use('App/Transformers/MatchTransformer')
const { queuesWithRole } = use('App/helpers')
/** /**
* BasicMatchTransformer class * BasicMatchTransformer class
@ -65,8 +66,9 @@ class BasicMatchTransformer extends MatchTransformer {
enemyTeam.push(playerInfos) enemyTeam.push(playerInfos)
} }
} }
allyTeam.sort(this.sortTeamByRole)
enemyTeam.sort(this.sortTeamByRole) // Roles
super.getMatchRoles(match, allyTeam, enemyTeam, player.teamId, playerData)
return { return {
account_id: identity.player.currentAccountId, account_id: identity.player.currentAccountId,

View file

@ -23,6 +23,9 @@ class DetailedMatchTransformer extends MatchTransformer {
const firstTeam = this.getTeamData(match, match.teams[0]) const firstTeam = this.getTeamData(match, match.teams[0])
const secondTeam = this.getTeamData(match, match.teams[1]) const secondTeam = this.getTeamData(match, match.teams[1])
// Roles
super.getMatchRoles(match, firstTeam.players, secondTeam.players)
return { return {
gameId: match.gameId, gameId: match.gameId,
season: match.seasonId, season: match.seasonId,

View file

@ -1,7 +1,6 @@
'use strict' 'use strict'
const MatchTransformer = use('App/Transformers/MatchTransformer') const MatchTransformer = use('App/Transformers/MatchTransformer')
const RoleIdentificationService = use('App/Services/RoleIdentificationService')
const SummonerService = use('App/Services/SummonerService') const SummonerService = use('App/Services/SummonerService')
const { queuesWithRole } = use('App/helpers') const { queuesWithRole } = use('App/helpers')
@ -24,13 +23,6 @@ class LiveMatchTransformer extends MatchTransformer {
return participant return participant
} }
_getTeamRoles(team) {
const teamJunglers = team.filter(p => p.jungle)
const jungle = teamJunglers.length === 1 ? teamJunglers[0].champion : null
return RoleIdentificationService.getRoles(this.championRoles, team.map(p => p.champion), jungle)
}
/** /**
* Transform raw data from Riot API * Transform raw data from Riot API
* @param match data from Riot API, one live match * @param match data from Riot API, one live match
@ -50,8 +42,8 @@ class LiveMatchTransformer extends MatchTransformer {
p.teamId === 100 ? blueTeam.push(playerRole) : redTeam.push(playerRole) p.teamId === 100 ? blueTeam.push(playerRole) : redTeam.push(playerRole)
}) })
blueRoles = this._getTeamRoles(blueTeam) blueRoles = super.getTeamRoles(blueTeam)
redRoles = this._getTeamRoles(redTeam) redRoles = super.getTeamRoles(redTeam)
} }
for (const participant of match.participants) { for (const participant of match.participants) {
@ -62,9 +54,6 @@ class LiveMatchTransformer extends MatchTransformer {
if (needsRole) { if (needsRole) {
const roles = participant.teamId === 100 ? blueRoles : redRoles const roles = participant.teamId === 100 ? blueRoles : redRoles
participant.role = Object.entries(roles).find(([, champion]) => participant.championId === champion)[0] participant.role = Object.entries(roles).find(([, champion]) => participant.championId === champion)[0]
if (participant.role === 'UTILITY') {
participant.role = 'SUPPORT'
}
} }
} }

View file

@ -19,7 +19,7 @@ class MatchTransformer {
const perks = await Jax.CDragon.perks() const perks = await Jax.CDragon.perks()
const perkstyles = await Jax.CDragon.perkstyles() const perkstyles = await Jax.CDragon.perkstyles()
const summonerSpells = await Jax.CDragon.summonerSpells() const summonerSpells = await Jax.CDragon.summonerSpells()
const championRoles = await RoleIdentificationService.pullData().catch(() => {}) const championRoles = await RoleIdentificationService.pullData().catch(() => { })
this.champions = champions this.champions = champions
this.items = items this.items = items
@ -196,7 +196,7 @@ class MatchTransformer {
* @param gamemode of the match to check if a role is needed * @param gamemode of the match to check if a role is needed
*/ */
getRoleName(timeline, gamemode) { getRoleName(timeline, gamemode) {
if(!queuesWithRole.includes(gamemode)) { if (!queuesWithRole.includes(gamemode)) {
return 'NONE' return 'NONE'
} }
@ -207,6 +207,66 @@ class MatchTransformer {
return timeline.lane return timeline.lane
} }
/**
* Return the 5 roles of a team based on champions
* @param team 5 champions + smite from a team
*/
getTeamRoles(team) {
const teamJunglers = team.filter(p => p.jungle)
const jungle = teamJunglers.length === 1 ? teamJunglers[0].champion : null
return RoleIdentificationService.getRoles(this.championRoles, team.map(p => p.champion), jungle)
}
/**
* Update roles for a team if Riot's ones are badly identified
* @param {Object} team 5 players data of the team
* @param {Array} champs 5 champions + smite from the team
* @param {Object} playerData data of the searched player, only for basic matches
*/
updateTeamRoles(team, champs, playerData = null) {
const actualRoles = [...new Set(team.map(p => p.role))]
if (actualRoles.length === 5) {
return
}
champs = this.getTeamRoles(champs)
for (const summoner of team) {
summoner.role = Object.entries(champs).find(([, champion]) => summoner.champion.id === champion)[0]
if (playerData && summoner.champion.id === playerData.champion.id) {
playerData.role = summoner.role
}
}
}
/**
*
* @param {Object} match from Riot Api
* @param {Array} allyTeam 5 players of the first team
* @param {Array} enemyTeam 5 players of the second team
* @param {Number} allyTeamId team id of the searched player, only for basic matches
* @param {Object} playerData data of the searched player, only for basic matches
*/
getMatchRoles(match, allyTeam, enemyTeam, allyTeamId = 100, playerData = null) {
if (!this.championRoles || !queuesWithRole.includes(match.queueId)) {
return
}
let allyChamps = []
let enemyChamps = []
match.participants.map(p => {
const playerRole = { champion: p.championId, jungle: p.spell1Id === 11 || p.spell2Id === 11 }
p.teamId === allyTeamId ? allyChamps.push(playerRole) : enemyChamps.push(playerRole)
})
this.updateTeamRoles(allyTeam, allyChamps, playerData)
this.updateTeamRoles(enemyTeam, enemyChamps)
allyTeam.sort(this.sortTeamByRole)
enemyTeam.sort(this.sortTeamByRole)
}
/** /**
* Get Summoner Spell Data from CDragon * Get Summoner Spell Data from CDragon
* @param id of the summonerSpell * @param id of the summonerSpell