mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: use custom RoleIdentification if Riot roles are badly identified
This commit is contained in:
parent
5cd9b7600f
commit
c16974fcfb
5 changed files with 84 additions and 24 deletions
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue