From 9201d19b26f7c8d905461b59fd89b29e770af425 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:03:22 +0900 Subject: [PATCH 01/38] add overall player perf to match page --- lua/wikis/leagueoflegends/MatchPage.lua | 136 ++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index a7581aa1d20..d0e11362838 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -22,6 +22,8 @@ local Div = HtmlWidgets.Div local GeneralCollapsible = Lua.import('Module:Widget/GeneralCollapsible/Default') local IconFa = Lua.import('Module:Widget/Image/Icon/Fontawesome') local IconImage = Lua.import('Module:Widget/Image/Icon/Image') +local Link = Lua.import('Module:Widget/Basic/Link') +local MatchSummaryCharacters = Lua.import('Module:Widget/Match/Summary/Characters') local PlayerStat = Lua.import('Module:Widget/Match/Page/PlayerStat') local PlayerDisplay = Lua.import('Module:Widget/Match/Page/PlayerDisplay') local StatsList = Lua.import('Module:Widget/Match/Page/StatsList') @@ -165,6 +167,140 @@ function MatchPage:populateGames() end) end +---@return string|Html|Widget? +function MatchPage:renderOverallStats() + if self:isBestOfOne() then + return + end + + ---@type table + local allPlayersStats = {} + + Array.forEach(self.games, function(game) + if game.status ~= BaseMatchPage.NOT_PLAYED then + mw.logObject(game.length, "game.length") + mw.logObject(Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), "parsed") + local parsedGameLength = Array.map( + Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) + ---Directly using tonumber as arg to Array.map causes base out of range error + return tonumber(element) + end + ) + local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) + Array.forEach(game.opponents, function(team, teamIdx) + Array.forEach(team.players or {}, function(player) + local playerId = player.player + if not playerId then return end + + if not allPlayersStats[playerId] then + allPlayersStats[playerId] = { + displayName = player.displayName or player.player, + playerName = player.player, + teamIndex = teamIdx, + champions = {}, + role = player.role, + stats = { + damage = {}, + gold = {}, + gameLength = 0, + kills = 0, + deaths = 0, + assists = 0, + } + } + end + + local data = allPlayersStats[playerId] + if player.character then + table.insert(data.champions, player.character) + end + + local stats = data.stats + if player.damagedone then table.insert(stats.damage, player.damagedone) end + if player.gold then table.insert(stats.gold, player.gold) end + stats.gameLength = stats.gameLength + gameLength + stats.kills = stats.kills + (player.kills or 0) + stats.deaths = stats.deaths + (player.deaths or 0) + stats.assists = stats.assists + (player.assists or 0) + end) + end) + end + end) + + local ungroupedPlayers = Array.sortBy(Array.extractValues(allPlayersStats), function(player) + return ROLE_ORDER[player.role] + end) + local players = Array.map(Array.range(1, 2), function (teamIdx) + return Array.filter(ungroupedPlayers, function (player) + return player.teamIndex == teamIdx + end) + end) + + local function renderPlayerOverallPerformance(player) + return Div{ + classes = {'match-bm-players-player match-bm-players-player--col-2'}, + children = { + Div{ + classes = {'match-bm-players-player-name'}, + children = { + Link{link = player.playerName, children = player.displayName}, + MatchSummaryCharacters{characters = player.champions}, + } + }, + Div{ + classes = {'match-bm-players-player-stats match-bm-players-player-stats--col-4'}, + children = { + PlayerStat{ + title = {KDA_ICON, 'KDA'}, + data = Array.interleave({ + player.stats.kills, + player.stats.deaths, + player.stats.assists + }, SPAN_SLASH) + }, + PlayerStat{ + title = {GOLD_ICON, 'GPM'}, + data = player.stats.gameLength > 0 and string.format('%.2f', + Array.reduce(player.stats.gold, Operator.add) / player.stats.gameLength * 60 + ) or nil + }, + PlayerStat{ + title = { + IconFa{iconName = 'damage', additionalClasses = {'fa-flip-both'}}, + 'DPM' + }, + data = player.stats.gameLength > 0 and string.format('%.2f', + Array.reduce(player.stats.damage, Operator.add) / player.stats.gameLength * 60 + ) or nil + } + } + } + } + } + end + + return HtmlWidgets.Fragment{ + children = WidgetUtil.collect( + HtmlWidgets.H3{children = 'Overall Player Performance'}, + Div{ + classes = {'match-bm-players-wrapper'}, + children = Array.map(self.opponents, function (opponent, teamIndex) + return Div{ + classes = {'match-bm-players-team'}, + children = WidgetUtil.collect( + Div{ + classes = {'match-bm-players-team-header'}, + children = opponent.iconDisplay + }, + Array.map(players[teamIndex], renderPlayerOverallPerformance) + ) + } + end) + } + ) + } +end + ---@param game LoLMatchPageGame ---@return Widget function MatchPage:renderGame(game) From d64202c78b4667449b5523e1aa305fbdfb044542 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:16:29 +0900 Subject: [PATCH 02/38] add CSM --- lua/wikis/leagueoflegends/MatchPage.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index d0e11362838..ebced0e4edc 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -202,6 +202,7 @@ function MatchPage:renderOverallStats() stats = { damage = {}, gold = {}, + creepscore = {}, gameLength = 0, kills = 0, deaths = 0, @@ -218,6 +219,7 @@ function MatchPage:renderOverallStats() local stats = data.stats if player.damagedone then table.insert(stats.damage, player.damagedone) end if player.gold then table.insert(stats.gold, player.gold) end + if player.creepscore then table.insert(stats.creepscore, player.creepscore) end stats.gameLength = stats.gameLength + gameLength stats.kills = stats.kills + (player.kills or 0) stats.deaths = stats.deaths + (player.deaths or 0) @@ -258,6 +260,19 @@ function MatchPage:renderOverallStats() player.stats.assists }, SPAN_SLASH) }, + PlayerStat{ + title = { + IconImage{ + imageLight = 'Lol stat icon cs.png', + caption = 'CSM', + link = '' + }, + 'CS' + }, + data = player.stats.gameLength > 0 and string.format('%.2f', + Array.reduce(player.stats.creepscore, Operator.add) / player.stats.gameLength * 60 + ) or nil + }, PlayerStat{ title = {GOLD_ICON, 'GPM'}, data = player.stats.gameLength > 0 and string.format('%.2f', From 4e9803f7308889e9960a8c228e47812c3c85fad7 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:16:39 +0900 Subject: [PATCH 03/38] adjust captions --- lua/wikis/leagueoflegends/MatchPage.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index ebced0e4edc..37092758244 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -264,10 +264,10 @@ function MatchPage:renderOverallStats() title = { IconImage{ imageLight = 'Lol stat icon cs.png', - caption = 'CSM', + caption = 'CS per minute', link = '' }, - 'CS' + 'CSM' }, data = player.stats.gameLength > 0 and string.format('%.2f', Array.reduce(player.stats.creepscore, Operator.add) / player.stats.gameLength * 60 @@ -281,7 +281,11 @@ function MatchPage:renderOverallStats() }, PlayerStat{ title = { - IconFa{iconName = 'damage', additionalClasses = {'fa-flip-both'}}, + IconFa{ + iconName = 'damage', + additionalClasses = {'fa-flip-both'}, + hover = 'Damage per minute' + }, 'DPM' }, data = player.stats.gameLength > 0 and string.format('%.2f', From 253fb88385fa86a0db256c3735b585fc80502707 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:42:12 +0900 Subject: [PATCH 04/38] add overall team stats --- lua/wikis/leagueoflegends/MatchPage.lua | 129 +++++++++++++++++++++++- 1 file changed, 126 insertions(+), 3 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 37092758244..e2bff0c996f 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -33,6 +33,7 @@ local WidgetUtil = Lua.import('Module:Widget/Util') ---@class LoLMatchPageGame: MatchPageGame ---@field vetoGroups {type: 'ban'|'pick', team: integer, character: string, vetoNumber: integer}[][][] +---@field opponents {players: table[], score: number?, status: string?, [any]: any}[] ---@class LoLMatchPage: BaseMatchPage ---@field games LoLMatchPageGame[] @@ -175,6 +176,30 @@ function MatchPage:renderOverallStats() ---@type table local allPlayersStats = {} + local allTeamsStats = { + { + kills = 0, + deaths = 0, + assists = 0, + towers = 0, + inhibitors = 0, + dragons = 0, + atakhans = 0, + heralds = 0, + barons = 0, + }, + { + kills = 0, + deaths = 0, + assists = 0, + towers = 0, + inhibitors = 0, + dragons = 0, + atakhans = 0, + heralds = 0, + barons = 0, + } + } Array.forEach(self.games, function(game) if game.status ~= BaseMatchPage.NOT_PLAYED then @@ -187,7 +212,17 @@ function MatchPage:renderOverallStats() end ) local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - Array.forEach(game.opponents, function(team, teamIdx) + + Array.forEach(game.teams, function(team, teamIdx) + allTeamsStats[teamIdx].kills = allTeamsStats[teamIdx].kills + (team.kills or 0) + allTeamsStats[teamIdx].deaths = allTeamsStats[teamIdx].deaths + (team.deaths or 0) + allTeamsStats[teamIdx].assists = allTeamsStats[teamIdx].assists + (team.assists or 0) + allTeamsStats[teamIdx].towers = allTeamsStats[teamIdx].towers + (team.objectives.towers or 0) + allTeamsStats[teamIdx].inhibitors = allTeamsStats[teamIdx].inhibitors + (team.objectives.inhibitors or 0) + allTeamsStats[teamIdx].dragons = allTeamsStats[teamIdx].dragons + (team.objectives.dragons or 0) + allTeamsStats[teamIdx].atakhans = allTeamsStats[teamIdx].atakhans + (team.objectives.atakhans or 0) + allTeamsStats[teamIdx].heralds = allTeamsStats[teamIdx].heralds + (team.objectives.heralds or 0) + allTeamsStats[teamIdx].barons = allTeamsStats[teamIdx].barons + (team.objectives.barons or 0) Array.forEach(team.players or {}, function(player) local playerId = player.player if not playerId then return end @@ -238,10 +273,97 @@ function MatchPage:renderOverallStats() end) end) + local function renderOverallTeamStats() + return { + HtmlWidgets.H3{children = 'Overall Team Stats'}, + Div{ + classes = {'match-bm-team-stats'}, + children = { + Div{ + classes = {'match-bm-lol-team-stats-header'}, + children = { + Div{ + classes = {'match-bm-lol-team-stats-header-team'}, + children = self.opponents[1].iconDisplay + }, + Div{ + classes = {'match-bm-team-stats-list-cell'}, + children = IconImage{ + imageLight = self:getMatchContext().icon, + imageDark = self:getMatchContext().icondark, + size = 'x32px', + } + }, + Div{ + classes = {'match-bm-lol-team-stats-header-team'}, + children = self.opponents[2].iconDisplay + } + } + }, + StatsList{ + finished = true, + data = { + { + icon = KDA_ICON, + name = 'KDA', + team1Value = Array.interleave({ + allTeamsStats[1].kills, + allTeamsStats[1].deaths, + allTeamsStats[1].assists + }, SPAN_SLASH), + team2Value = Array.interleave({ + allTeamsStats[2].kills, + allTeamsStats[2].deaths, + allTeamsStats[2].assists + }, SPAN_SLASH) + }, + { + icon = IconImage{imageLight = 'Lol stat icon tower.png', link = ''}, + name = 'Towers', + team1Value = allTeamsStats[1].towers, + team2Value = allTeamsStats[2].towers + }, + { + icon = IconImage{imageLight = 'Lol stat icon inhibitor.png', link = ''}, + name = 'Inhibitors', + team1Value = allTeamsStats[1].inhibitors, + team2Value = allTeamsStats[2].inhibitors + }, + { + icon = IconImage{imageLight = 'Lol stat icon herald.png', link = ''}, + name = 'Rift Heralds', + team1Value = allTeamsStats[1].heralds, + team2Value = allTeamsStats[2].heralds + }, + { + icon = IconImage{imageLight = 'Lol stat icon atakhan.png', link = ''}, + name = 'Atakhan', + team1Value = allTeamsStats[1].atakhans, + team2Value = allTeamsStats[2].atakhans + }, + { + icon = IconImage{imageLight = 'Lol stat icon dragon.png', link = ''}, + name = 'Dragons', + team1Value = allTeamsStats[1].dragons, + team2Value = allTeamsStats[2].dragons + }, + { + icon = IconImage{imageLight = 'Lol stat icon baron.png', link = ''}, + name = 'Barons', + team1Value = allTeamsStats[1].barons, + team2Value = allTeamsStats[2].barons + }, + } + } + } + } + } + end + local function renderPlayerOverallPerformance(player) return Div{ classes = {'match-bm-players-player match-bm-players-player--col-2'}, - children = { + children = WidgetUtil.collect( Div{ classes = {'match-bm-players-player-name'}, children = { @@ -294,12 +416,13 @@ function MatchPage:renderOverallStats() } } } - } + ) } end return HtmlWidgets.Fragment{ children = WidgetUtil.collect( + renderOverallTeamStats(), HtmlWidgets.H3{children = 'Overall Player Performance'}, Div{ classes = {'match-bm-players-wrapper'}, From c8b36920140be3adfe3b6e6f47f153065a001f20 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:43:02 +0900 Subject: [PATCH 05/38] plural --- lua/wikis/leagueoflegends/MatchPage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index e2bff0c996f..502caf60d2e 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -337,7 +337,7 @@ function MatchPage:renderOverallStats() }, { icon = IconImage{imageLight = 'Lol stat icon atakhan.png', link = ''}, - name = 'Atakhan', + name = 'Atakhans', team1Value = allTeamsStats[1].atakhans, team2Value = allTeamsStats[2].atakhans }, From 2505c1bd7d02a4b7a5b5f0846b5b3b773ad37207 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:45:24 +0900 Subject: [PATCH 06/38] pass in date --- lua/wikis/leagueoflegends/MatchPage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 502caf60d2e..bde10e63cbf 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -368,7 +368,7 @@ function MatchPage:renderOverallStats() classes = {'match-bm-players-player-name'}, children = { Link{link = player.playerName, children = player.displayName}, - MatchSummaryCharacters{characters = player.champions}, + MatchSummaryCharacters{characters = player.champions, date = self.matchData.date}, } }, Div{ From 509a8d8be7d024695a515e8262cb2bb2d5677c74 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:55:33 +0900 Subject: [PATCH 07/38] refactor + lint --- lua/wikis/leagueoflegends/MatchPage.lua | 37 ++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index bde10e63cbf..b4000b55712 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -174,7 +174,8 @@ function MatchPage:renderOverallStats() return end - ---@type table + ---@type table}> local allPlayersStats = {} local allTeamsStats = { { @@ -235,9 +236,9 @@ function MatchPage:renderOverallStats() champions = {}, role = player.role, stats = { - damage = {}, - gold = {}, - creepscore = {}, + damage = 0, + gold = 0, + creepscore = 0, gameLength = 0, kills = 0, deaths = 0, @@ -252,9 +253,9 @@ function MatchPage:renderOverallStats() end local stats = data.stats - if player.damagedone then table.insert(stats.damage, player.damagedone) end - if player.gold then table.insert(stats.gold, player.gold) end - if player.creepscore then table.insert(stats.creepscore, player.creepscore) end + stats.damage = stats.damage + (player.damagedone or 0) + stats.gold = stats.gold + (player.gold or 0) + stats.creepscore = stats.creepscore + (player.creepscore or 0) stats.gameLength = stats.gameLength + gameLength stats.kills = stats.kills + (player.kills or 0) stats.deaths = stats.deaths + (player.deaths or 0) @@ -360,6 +361,16 @@ function MatchPage:renderOverallStats() } end + ---@param stat integer + ---@param gameLength integer + ---@return string? + local function calculateStatPerMinute(stat, gameLength) + if gameLength <= 0 then + return + end + return string.format('%.2f', stat / gameLength * 60) + end + local function renderPlayerOverallPerformance(player) return Div{ classes = {'match-bm-players-player match-bm-players-player--col-2'}, @@ -391,15 +402,11 @@ function MatchPage:renderOverallStats() }, 'CSM' }, - data = player.stats.gameLength > 0 and string.format('%.2f', - Array.reduce(player.stats.creepscore, Operator.add) / player.stats.gameLength * 60 - ) or nil + data = calculateStatPerMinute(player.stats.creepscore, player.stats.gameLength) }, PlayerStat{ title = {GOLD_ICON, 'GPM'}, - data = player.stats.gameLength > 0 and string.format('%.2f', - Array.reduce(player.stats.gold, Operator.add) / player.stats.gameLength * 60 - ) or nil + data = calculateStatPerMinute(player.stats.gold, player.stats.gameLength) }, PlayerStat{ title = { @@ -410,9 +417,7 @@ function MatchPage:renderOverallStats() }, 'DPM' }, - data = player.stats.gameLength > 0 and string.format('%.2f', - Array.reduce(player.stats.damage, Operator.add) / player.stats.gameLength * 60 - ) or nil + data = calculateStatPerMinute(player.stats.damage, player.stats.gameLength) } } } From 3d8571a473163e3777385b59714688c24b2167d1 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:57:02 +0900 Subject: [PATCH 08/38] type anno --- lua/wikis/leagueoflegends/MatchPage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index b4000b55712..4527f2f1bce 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -168,7 +168,7 @@ function MatchPage:populateGames() end) end ----@return string|Html|Widget? +---@return Widget? function MatchPage:renderOverallStats() if self:isBestOfOne() then return From 2456cf6c046416ad298afa8c46e0a120f028c9d2 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:04:02 +0900 Subject: [PATCH 09/38] kick logging points --- lua/wikis/leagueoflegends/MatchPage.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 4527f2f1bce..a00062b89e5 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -204,8 +204,6 @@ function MatchPage:renderOverallStats() Array.forEach(self.games, function(game) if game.status ~= BaseMatchPage.NOT_PLAYED then - mw.logObject(game.length, "game.length") - mw.logObject(Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), "parsed") local parsedGameLength = Array.map( Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) ---Directly using tonumber as arg to Array.map causes base out of range error From 7c220549bc50db98b8bc226ae84e06691a94268e Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:04:58 +0900 Subject: [PATCH 10/38] reduce indentation level --- lua/wikis/leagueoflegends/MatchPage.lua | 113 ++++++++++++------------ 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index a00062b89e5..9b52aebf9c5 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -203,64 +203,65 @@ function MatchPage:renderOverallStats() } Array.forEach(self.games, function(game) - if game.status ~= BaseMatchPage.NOT_PLAYED then - local parsedGameLength = Array.map( - Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) - ---Directly using tonumber as arg to Array.map causes base out of range error - return tonumber(element) - end - ) - local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - - Array.forEach(game.teams, function(team, teamIdx) - allTeamsStats[teamIdx].kills = allTeamsStats[teamIdx].kills + (team.kills or 0) - allTeamsStats[teamIdx].deaths = allTeamsStats[teamIdx].deaths + (team.deaths or 0) - allTeamsStats[teamIdx].assists = allTeamsStats[teamIdx].assists + (team.assists or 0) - allTeamsStats[teamIdx].towers = allTeamsStats[teamIdx].towers + (team.objectives.towers or 0) - allTeamsStats[teamIdx].inhibitors = allTeamsStats[teamIdx].inhibitors + (team.objectives.inhibitors or 0) - allTeamsStats[teamIdx].dragons = allTeamsStats[teamIdx].dragons + (team.objectives.dragons or 0) - allTeamsStats[teamIdx].atakhans = allTeamsStats[teamIdx].atakhans + (team.objectives.atakhans or 0) - allTeamsStats[teamIdx].heralds = allTeamsStats[teamIdx].heralds + (team.objectives.heralds or 0) - allTeamsStats[teamIdx].barons = allTeamsStats[teamIdx].barons + (team.objectives.barons or 0) - Array.forEach(team.players or {}, function(player) - local playerId = player.player - if not playerId then return end - - if not allPlayersStats[playerId] then - allPlayersStats[playerId] = { - displayName = player.displayName or player.player, - playerName = player.player, - teamIndex = teamIdx, - champions = {}, - role = player.role, - stats = { - damage = 0, - gold = 0, - creepscore = 0, - gameLength = 0, - kills = 0, - deaths = 0, - assists = 0, - } + if game.status == BaseMatchPage.NOT_PLAYED then + return + end + local parsedGameLength = Array.map( + Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) + ---Directly using tonumber as arg to Array.map causes base out of range error + return tonumber(element) + end + ) + local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) + + Array.forEach(game.teams, function(team, teamIdx) + allTeamsStats[teamIdx].kills = allTeamsStats[teamIdx].kills + (team.kills or 0) + allTeamsStats[teamIdx].deaths = allTeamsStats[teamIdx].deaths + (team.deaths or 0) + allTeamsStats[teamIdx].assists = allTeamsStats[teamIdx].assists + (team.assists or 0) + allTeamsStats[teamIdx].towers = allTeamsStats[teamIdx].towers + (team.objectives.towers or 0) + allTeamsStats[teamIdx].inhibitors = allTeamsStats[teamIdx].inhibitors + (team.objectives.inhibitors or 0) + allTeamsStats[teamIdx].dragons = allTeamsStats[teamIdx].dragons + (team.objectives.dragons or 0) + allTeamsStats[teamIdx].atakhans = allTeamsStats[teamIdx].atakhans + (team.objectives.atakhans or 0) + allTeamsStats[teamIdx].heralds = allTeamsStats[teamIdx].heralds + (team.objectives.heralds or 0) + allTeamsStats[teamIdx].barons = allTeamsStats[teamIdx].barons + (team.objectives.barons or 0) + Array.forEach(team.players or {}, function(player) + local playerId = player.player + if not playerId then return end + + if not allPlayersStats[playerId] then + allPlayersStats[playerId] = { + displayName = player.displayName or player.player, + playerName = player.player, + teamIndex = teamIdx, + champions = {}, + role = player.role, + stats = { + damage = 0, + gold = 0, + creepscore = 0, + gameLength = 0, + kills = 0, + deaths = 0, + assists = 0, } - end - - local data = allPlayersStats[playerId] - if player.character then - table.insert(data.champions, player.character) - end - - local stats = data.stats - stats.damage = stats.damage + (player.damagedone or 0) - stats.gold = stats.gold + (player.gold or 0) - stats.creepscore = stats.creepscore + (player.creepscore or 0) - stats.gameLength = stats.gameLength + gameLength - stats.kills = stats.kills + (player.kills or 0) - stats.deaths = stats.deaths + (player.deaths or 0) - stats.assists = stats.assists + (player.assists or 0) - end) + } + end + + local data = allPlayersStats[playerId] + if player.character then + table.insert(data.champions, player.character) + end + + local stats = data.stats + stats.damage = stats.damage + (player.damagedone or 0) + stats.gold = stats.gold + (player.gold or 0) + stats.creepscore = stats.creepscore + (player.creepscore or 0) + stats.gameLength = stats.gameLength + gameLength + stats.kills = stats.kills + (player.kills or 0) + stats.deaths = stats.deaths + (player.deaths or 0) + stats.assists = stats.assists + (player.assists or 0) end) - end + end) end) local ungroupedPlayers = Array.sortBy(Array.extractValues(allPlayersStats), function(player) From 4d56af82ef0277a96c5504b97fe64c418074f2da Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:06:08 +0900 Subject: [PATCH 11/38] adjust type anno --- lua/wikis/leagueoflegends/MatchPage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 9b52aebf9c5..67426c9581d 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -33,7 +33,7 @@ local WidgetUtil = Lua.import('Module:Widget/Util') ---@class LoLMatchPageGame: MatchPageGame ---@field vetoGroups {type: 'ban'|'pick', team: integer, character: string, vetoNumber: integer}[][][] ----@field opponents {players: table[], score: number?, status: string?, [any]: any}[] +---@field teams {players: table[], score: number?, status: string?, [any]: any}[] ---@class LoLMatchPage: BaseMatchPage ---@field games LoLMatchPageGame[] From d88a7f661592946a19e16b95c5323f04a0e80497 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 26 Sep 2025 20:53:30 +0900 Subject: [PATCH 12/38] code style Co-authored-by: hjpalpha <75081997+hjpalpha@users.noreply.github.com> --- lua/wikis/commons/MatchPage/Base.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/MatchPage/Base.lua b/lua/wikis/commons/MatchPage/Base.lua index 2bd430f8d1d..ebee5f749d3 100644 --- a/lua/wikis/commons/MatchPage/Base.lua +++ b/lua/wikis/commons/MatchPage/Base.lua @@ -286,8 +286,8 @@ function BaseMatchPage:renderGames() local hasOverallStats = Logic.isNotEmpty(overallStats) if hasOverallStats then - tabs['name1'] = 'Overall Statistics' - tabs['content1'] = overallStats + tabs.name1 = 'Overall Statistics' + tabs.content1 = overallStats end Array.forEach(games, function(game, idx) From 07a4383942095b410f5fb98d8914ab42cb38b6a2 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 4 Oct 2025 09:46:38 +0900 Subject: [PATCH 13/38] add nil filter for stats list --- lua/wikis/commons/Widget/Match/Page/StatsList.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Widget/Match/Page/StatsList.lua b/lua/wikis/commons/Widget/Match/Page/StatsList.lua index 123d699f523..588c5b677c7 100644 --- a/lua/wikis/commons/Widget/Match/Page/StatsList.lua +++ b/lua/wikis/commons/Widget/Match/Page/StatsList.lua @@ -36,9 +36,14 @@ function MatchPageStatsList:render() if Logic.isEmpty(self.props.data) then return end return Div{ classes = {'match-bm-team-stats-list'}, - children = Array.map(self.props.data, function (dataElement) - return self:_renderStat(dataElement) - end) + children = Array.map( + Array.filter(self.props.data, function (element) + return element.team1Value ~= nil or element.team2Value ~= nil + end), + function (dataElement) + return self:_renderStat(dataElement) + end + ) } end From e7d0c48ad6bbe0bf2456e951adeb651d9925a81b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 4 Oct 2025 09:59:13 +0900 Subject: [PATCH 14/38] refactor team stats display --- lua/wikis/leagueoflegends/MatchPage.lua | 210 +++++++++++------------- 1 file changed, 92 insertions(+), 118 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 67426c9581d..9c721de40cd 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -300,60 +300,9 @@ function MatchPage:renderOverallStats() } } }, - StatsList{ + MatchPage._buildTeamStatsList{ finished = true, - data = { - { - icon = KDA_ICON, - name = 'KDA', - team1Value = Array.interleave({ - allTeamsStats[1].kills, - allTeamsStats[1].deaths, - allTeamsStats[1].assists - }, SPAN_SLASH), - team2Value = Array.interleave({ - allTeamsStats[2].kills, - allTeamsStats[2].deaths, - allTeamsStats[2].assists - }, SPAN_SLASH) - }, - { - icon = IconImage{imageLight = 'Lol stat icon tower.png', link = ''}, - name = 'Towers', - team1Value = allTeamsStats[1].towers, - team2Value = allTeamsStats[2].towers - }, - { - icon = IconImage{imageLight = 'Lol stat icon inhibitor.png', link = ''}, - name = 'Inhibitors', - team1Value = allTeamsStats[1].inhibitors, - team2Value = allTeamsStats[2].inhibitors - }, - { - icon = IconImage{imageLight = 'Lol stat icon herald.png', link = ''}, - name = 'Rift Heralds', - team1Value = allTeamsStats[1].heralds, - team2Value = allTeamsStats[2].heralds - }, - { - icon = IconImage{imageLight = 'Lol stat icon atakhan.png', link = ''}, - name = 'Atakhans', - team1Value = allTeamsStats[1].atakhans, - team2Value = allTeamsStats[2].atakhans - }, - { - icon = IconImage{imageLight = 'Lol stat icon dragon.png', link = ''}, - name = 'Dragons', - team1Value = allTeamsStats[1].dragons, - team2Value = allTeamsStats[2].dragons - }, - { - icon = IconImage{imageLight = 'Lol stat icon baron.png', link = ''}, - name = 'Barons', - team1Value = allTeamsStats[1].barons, - team2Value = allTeamsStats[2].barons - }, - } + data = allTeamsStats } } } @@ -447,6 +396,81 @@ function MatchPage:renderOverallStats() } end +---@private +---@param props {finished: boolean, data: {kills: integer, deaths: integer, assists: integer, gold: string, +---towers: integer, inhibitors: integer, grubs: integer?, heralds: integer?, atakhans: integer?, dragons: integer?, +---barons: integer?}[]} +---@return MatchPageStatsList +function MatchPage._buildTeamStatsList(props) + return StatsList{ + finished = props.finished, + data = { + { + icon = KDA_ICON, + name = 'KDA', + team1Value = Array.interleave({ + props.data[1].kills, + props.data[1].deaths, + props.data[1].assists + }, SPAN_SLASH), + team2Value = Array.interleave({ + props.data[2].kills, + props.data[2].deaths, + props.data[2].assists + }, SPAN_SLASH) + }, + { + icon = GOLD_ICON, + name = 'Gold', + team1Value = props.data[1].gold, + team2Value = props.data[2].gold + }, + { + icon = IconImage{imageLight = 'Lol stat icon tower.png', link = ''}, + name = 'Towers', + team1Value = props.data[1].towers, + team2Value = props.data[2].towers + }, + { + icon = IconImage{imageLight = 'Lol stat icon inhibitor.png', link = ''}, + name = 'Inhibitors', + team1Value = props.data[1].inhibitors, + team2Value = props.data[2].inhibitors + }, + { + icon = IconImage{imageLight = 'Lol stat icon grub.png', link = ''}, + name = 'Void Grubs', + team1Value = props.data[1].grubs, + team2Value = props.data[2].grubs + }, + { + icon = IconImage{imageLight = 'Lol stat icon herald.png', link = ''}, + name = 'Rift Heralds', + team1Value = props.data[1].heralds, + team2Value = props.data[2].heralds + }, + { + icon = IconImage{imageLight = 'Lol stat icon atakhan.png', link = ''}, + name = 'Atakhan', + team1Value = props.data[1].atakhans, + team2Value = props.data[2].atakhans + }, + { + icon = IconImage{imageLight = 'Lol stat icon dragon.png', link = ''}, + name = 'Dragons', + team1Value = props.data[1].dragons, + team2Value = props.data[2].dragons + }, + { + icon = IconImage{imageLight = 'Lol stat icon baron.png', link = ''}, + name = 'Barons', + team1Value = props.data[1].barons, + team2Value = props.data[2].barons + }, + } + } +end + ---@param game LoLMatchPageGame ---@return Widget function MatchPage:renderGame(game) @@ -656,72 +680,22 @@ function MatchPage:_renderTeamStats(game) } } }, - StatsList{ + MatchPage._buildTeamStatsList{ finished = game.finished, - data = { - { - icon = KDA_ICON, - name = 'KDA', - team1Value = Array.interleave({ - game.teams[1].kills, - game.teams[1].deaths, - game.teams[1].assists - }, SPAN_SLASH), - team2Value = Array.interleave({ - game.teams[2].kills, - game.teams[2].deaths, - game.teams[2].assists - }, SPAN_SLASH) - }, - { - icon = GOLD_ICON, - name = 'Gold', - team1Value = game.teams[1].gold, - team2Value = game.teams[2].gold - }, - { - icon = IconImage{imageLight = 'Lol stat icon tower.png', link = ''}, - name = 'Towers', - team1Value = game.teams[1].objectives.towers, - team2Value = game.teams[2].objectives.towers - }, - { - icon = IconImage{imageLight = 'Lol stat icon inhibitor.png', link = ''}, - name = 'Inhibitors', - team1Value = game.teams[1].objectives.inhibitors, - team2Value = game.teams[2].objectives.inhibitors - }, - { - icon = IconImage{imageLight = 'Lol stat icon grub.png', link = ''}, - name = 'Void Grubs', - team1Value = game.teams[1].objectives.grubs, - team2Value = game.teams[2].objectives.grubs - }, - { - icon = IconImage{imageLight = 'Lol stat icon herald.png', link = ''}, - name = 'Rift Heralds', - team1Value = game.teams[1].objectives.heralds, - team2Value = game.teams[2].objectives.heralds - }, - { - icon = IconImage{imageLight = 'Lol stat icon atakhan.png', link = ''}, - name = 'Atakhan', - team1Value = game.teams[1].objectives.atakhans, - team2Value = game.teams[2].objectives.atakhans - }, - { - icon = IconImage{imageLight = 'Lol stat icon dragon.png', link = ''}, - name = 'Dragons', - team1Value = game.teams[1].objectives.dragons, - team2Value = game.teams[2].objectives.dragons - }, - { - icon = IconImage{imageLight = 'Lol stat icon baron.png', link = ''}, - name = 'Barons', - team1Value = game.teams[1].objectives.barons, - team2Value = game.teams[2].objectives.barons - }, - } + data = Array.map(game.teams, function (team) + return { + kills = team.kills, + deaths = team.deaths, + assists = team.assists, + gold = team.gold, + inhibitors = team.objectives.inhibitors, + grubs = team.objectives.grubs, + heralds = team.objectives.heralds, + atakhans = team.objectives.atakhans, + dragons = team.objectives.dragons, + barons = team.objectives.barons + } + end) } } } From 0bcec18260d4a815dc69a61510e377c9dc846746 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 17:58:31 +0900 Subject: [PATCH 15/38] move calculation to parser --- .../MatchGroup/Input/Custom.lua | 2 + .../MatchGroup/Input/Custom/MatchPage.lua | 36 +++++++++++++ lua/wikis/leagueoflegends/MatchPage.lua | 54 +++++-------------- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 884ee75bac7..2a374d458e0 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -37,6 +37,7 @@ MatchFunctions.getBestOf = MatchGroupInputUtil.getBestOf ---@field getHeroBans fun(map: table, opponentIndex: integer): string[]? ---@field getParticipants fun(map: table, opponentIndex: integer): table[]? ---@field getVetoPhase fun(map: table): table? +---@field extendMapOpponent? fun(map: table, opponentIndex: integer): table ---@param match table ---@param options? {isMatchPage: boolean?} @@ -75,6 +76,7 @@ function MatchFunctions.extractMaps(match, opponents, MapParser) getMap = MapParser.getMap, getLength = MapParser.getLength, getPlayersOfMapOpponent = FnUtil.curry(MapFunctions.getPlayersOfMapOpponent, MapParser), + extendMapOpponent = MapParser.extendMapOpponent } local maps = MatchGroupInputUtil.standardProcessMaps(match, opponents, mapParserWrapper) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua index 5c89fb8a29e..9faf4e0e3ef 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua @@ -121,4 +121,40 @@ function CustomMatchGroupInputMatchPage.getObjectives(map, opponentIndex) } end +function CustomMatchGroupInputMatchPage.extendMapOpponent(map, opponentIndex) + local participants = CustomMatchGroupInputMatchPage.getParticipants(map, opponentIndex) + + if Logic.isEmpty(participants) then + return {} + end + + ---@param a number? + ---@param b number? + ---@return number? + local function nilSafeAdd(a, b) + if not a then + return b + elseif not b then + return a + end + return a + b + end + + local function sumItem(arr, item) + return Array.reduce(Array.map(arr, Operator.property(item)), nilSafeAdd, 0) + end + + return { + stats = Table.merge( + { + gold = sumItem(participants, 'gold'), + kills = sumItem(participants, 'kills'), + deaths = sumItem(participants, 'deaths'), + assists = sumItem(participants, 'assists') + }, + CustomMatchGroupInputMatchPage.getObjectives(map, opponentIndex) + ) + } +end + return CustomMatchGroupInputMatchPage diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 9c721de40cd..dd367aba681 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -128,19 +128,6 @@ function MatchPage:populateGames() end ) - if game.finished then - -- Aggregate stats - team.gold = MatchPage.abbreviateNumber(MatchPage.sumItem(team.players, 'gold')) - team.kills = MatchPage.sumItem(team.players, 'kills') - team.deaths = MatchPage.sumItem(team.players, 'deaths') - team.assists = MatchPage.sumItem(team.players, 'assists') - - -- Set fields - team.objectives = game.extradata['team' .. teamIdx .. 'objectives'] or {} - else - team.objectives = {} - end - team.picks = Array.map(team.players, Operator.property('character')) team.pickOrder = Array.filter(game.extradata.vetophase or {}, function(veto) return veto.type == 'pick' and veto.team == teamIdx @@ -214,16 +201,16 @@ function MatchPage:renderOverallStats() ) local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - Array.forEach(game.teams, function(team, teamIdx) - allTeamsStats[teamIdx].kills = allTeamsStats[teamIdx].kills + (team.kills or 0) - allTeamsStats[teamIdx].deaths = allTeamsStats[teamIdx].deaths + (team.deaths or 0) - allTeamsStats[teamIdx].assists = allTeamsStats[teamIdx].assists + (team.assists or 0) - allTeamsStats[teamIdx].towers = allTeamsStats[teamIdx].towers + (team.objectives.towers or 0) - allTeamsStats[teamIdx].inhibitors = allTeamsStats[teamIdx].inhibitors + (team.objectives.inhibitors or 0) - allTeamsStats[teamIdx].dragons = allTeamsStats[teamIdx].dragons + (team.objectives.dragons or 0) - allTeamsStats[teamIdx].atakhans = allTeamsStats[teamIdx].atakhans + (team.objectives.atakhans or 0) - allTeamsStats[teamIdx].heralds = allTeamsStats[teamIdx].heralds + (team.objectives.heralds or 0) - allTeamsStats[teamIdx].barons = allTeamsStats[teamIdx].barons + (team.objectives.barons or 0) + Array.forEach(game.opponents, function(team, teamIdx) + allTeamsStats[teamIdx].kills = allTeamsStats[teamIdx].kills + (team.stats.kills or 0) + allTeamsStats[teamIdx].deaths = allTeamsStats[teamIdx].deaths + (team.stats.deaths or 0) + allTeamsStats[teamIdx].assists = allTeamsStats[teamIdx].assists + (team.stats.assists or 0) + allTeamsStats[teamIdx].towers = allTeamsStats[teamIdx].towers + (team.stats.towers or 0) + allTeamsStats[teamIdx].inhibitors = allTeamsStats[teamIdx].inhibitors + (team.stats.inhibitors or 0) + allTeamsStats[teamIdx].dragons = allTeamsStats[teamIdx].dragons + (team.stats.dragons or 0) + allTeamsStats[teamIdx].atakhans = allTeamsStats[teamIdx].atakhans + (team.stats.atakhans or 0) + allTeamsStats[teamIdx].heralds = allTeamsStats[teamIdx].heralds + (team.stats.heralds or 0) + allTeamsStats[teamIdx].barons = allTeamsStats[teamIdx].barons + (team.stats.barons or 0) Array.forEach(team.players or {}, function(player) local playerId = player.player if not playerId then return end @@ -397,7 +384,7 @@ function MatchPage:renderOverallStats() end ---@private ----@param props {finished: boolean, data: {kills: integer, deaths: integer, assists: integer, gold: string, +---@param props {finished: boolean, data: {kills: integer, deaths: integer, assists: integer, gold: number?, ---towers: integer, inhibitors: integer, grubs: integer?, heralds: integer?, atakhans: integer?, dragons: integer?, ---barons: integer?}[]} ---@return MatchPageStatsList @@ -422,8 +409,8 @@ function MatchPage._buildTeamStatsList(props) { icon = GOLD_ICON, name = 'Gold', - team1Value = props.data[1].gold, - team2Value = props.data[2].gold + team1Value = MatchPage.abbreviateNumber(props.data[1].gold), + team2Value = MatchPage.abbreviateNumber(props.data[2].gold) }, { icon = IconImage{imageLight = 'Lol stat icon tower.png', link = ''}, @@ -682,20 +669,7 @@ function MatchPage:_renderTeamStats(game) }, MatchPage._buildTeamStatsList{ finished = game.finished, - data = Array.map(game.teams, function (team) - return { - kills = team.kills, - deaths = team.deaths, - assists = team.assists, - gold = team.gold, - inhibitors = team.objectives.inhibitors, - grubs = team.objectives.grubs, - heralds = team.objectives.heralds, - atakhans = team.objectives.atakhans, - dragons = team.objectives.dragons, - barons = team.objectives.barons - } - end) + data = Array.map(game.opponents, Operator.property('stats')) } } } From cae20e25edf80deee12f01d347db3101dccea0cf Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 18:47:56 +0900 Subject: [PATCH 16/38] move more calculation to MGI --- .../MatchGroup/Input/Custom/MatchPage.lua | 8 ++++++- lua/wikis/leagueoflegends/MatchPage.lua | 22 +++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua index 9faf4e0e3ef..05ff36cf88b 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua @@ -125,8 +125,9 @@ function CustomMatchGroupInputMatchPage.extendMapOpponent(map, opponentIndex) local participants = CustomMatchGroupInputMatchPage.getParticipants(map, opponentIndex) if Logic.isEmpty(participants) then - return {} + return end + ---@cast participants -nil ---@param a number? ---@param b number? @@ -140,11 +141,16 @@ function CustomMatchGroupInputMatchPage.extendMapOpponent(map, opponentIndex) return a + b end + ---@param arr table[] + ---@param item string + ---@return number? local function sumItem(arr, item) return Array.reduce(Array.map(arr, Operator.property(item)), nilSafeAdd, 0) end return { + side = CustomMatchGroupInputMatchPage.getSide(map, opponentIndex), + picks = Array.map(participants, Operator.property('character')), stats = Table.merge( { gold = sumItem(participants, 'gold'), diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index dd367aba681..fafa9ab3e56 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -33,7 +33,7 @@ local WidgetUtil = Lua.import('Module:Widget/Util') ---@class LoLMatchPageGame: MatchPageGame ---@field vetoGroups {type: 'ban'|'pick', team: integer, character: string, vetoNumber: integer}[][][] ----@field teams {players: table[], score: number?, status: string?, [any]: any}[] +---@field opponents {players: table[], score: number?, status: string?, [string]: any}[] ---@class LoLMatchPage: BaseMatchPage ---@field games LoLMatchPageGame[] @@ -104,14 +104,12 @@ end function MatchPage:populateGames() Array.forEach(self.games, function(game) + local vetoPhase = game.extradata.vetophase or {} game.finished = game.winner ~= nil and game.winner ~= -1 game.teams = Array.map(game.opponents, function(opponent, teamIdx) - local team = {} + opponent.scoreDisplay = game.winner == teamIdx and 'W' or game.finished and 'L' or '-' - team.scoreDisplay = game.winner == teamIdx and 'W' or game.finished and 'L' or '-' - team.side = String.nilIfEmpty(game.extradata['team' .. teamIdx ..'side']) - - team.players = Array.map( + opponent.players = Array.map( Array.sortBy(Array.filter(opponent.players, Logic.isNotEmpty), function(player) return ROLE_ORDER[player.role] end), @@ -127,19 +125,19 @@ function MatchPage:populateGames() }) end ) - - team.picks = Array.map(team.players, Operator.property('character')) - team.pickOrder = Array.filter(game.extradata.vetophase or {}, function(veto) + opponent.stats = opponent.stats or {} + opponent.picks = opponent.picks or {} + opponent.pickOrder = Array.filter(vetoPhase, function(veto) return veto.type == 'pick' and veto.team == teamIdx end) - team.bans = Array.filter(game.extradata.vetophase or {}, function(veto) + opponent.bans = Array.filter(vetoPhase, function(veto) return veto.type == 'ban' and veto.team == teamIdx end) - return team + return opponent end) - local _, vetoByTeam = Array.groupBy(game.extradata.vetophase or {}, Operator.property('team')) + local _, vetoByTeam = Array.groupBy(vetoPhase, Operator.property('team')) game.vetoGroups = {} Array.forEach(vetoByTeam, function(team, teamIndex) From 091b6f9f4fdfbb2d47a79207d1c2e77a33e8e173 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:23:36 +0900 Subject: [PATCH 17/38] nil catch --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua | 2 +- lua/wikis/leagueoflegends/MatchPage.lua | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua index 05ff36cf88b..9c292bdfa80 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua @@ -125,7 +125,7 @@ function CustomMatchGroupInputMatchPage.extendMapOpponent(map, opponentIndex) local participants = CustomMatchGroupInputMatchPage.getParticipants(map, opponentIndex) if Logic.isEmpty(participants) then - return + return {picks = {}, stats = {}} end ---@cast participants -nil diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index fafa9ab3e56..7b97f70b522 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -125,8 +125,6 @@ function MatchPage:populateGames() }) end ) - opponent.stats = opponent.stats or {} - opponent.picks = opponent.picks or {} opponent.pickOrder = Array.filter(vetoPhase, function(veto) return veto.type == 'pick' and veto.team == teamIdx end) From 1cbf385983a980f94e3f382d2aa3049ae2777865 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:28:18 +0900 Subject: [PATCH 18/38] move aggregated team stats calculation to MGI --- .../MatchGroup/Input/Custom.lua | 72 +++++++++++++++++++ lua/wikis/leagueoflegends/MatchPage.lua | 34 +-------- 2 files changed, 73 insertions(+), 33 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 2a374d458e0..55cb2b7987d 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -101,6 +101,78 @@ end ---@param opponents table[] ---@return table function MatchFunctions.getExtraData(match, games, opponents) + ---@param a number? + ---@param b number? + ---@return number? + local function nilSafeAdd(a, b) + if not a then + return b + elseif not b then + return a + end + return a + b + end + + if games[1] and games[1].opponents[1].stats then + Array.forEach(opponents, function (opponent, opponentIndex) + opponent.extradata = { + kills = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).kills + end), + nilSafeAdd + ), + deaths = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).deaths + end), + nilSafeAdd + ), + assists = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).assists + end), + nilSafeAdd + ), + towers = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).towers + end), + nilSafeAdd + ), + inhibitors = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).inhibitors + end), + nilSafeAdd + ), + dragons = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).dragons + end), + nilSafeAdd + ), + atakhans = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).atakhans + end), + nilSafeAdd + ), + heralds = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).heralds + end), + nilSafeAdd + ), + barons = Array.reduce( + Array.map(games, function (game) + return (game.opponents[opponentIndex].stats or {}).barons + end), + nilSafeAdd + ) + } + end) + end return { mvp = MatchGroupInputUtil.readMvp(match, opponents), } diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 7b97f70b522..79009ca9190 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -160,30 +160,7 @@ function MatchPage:renderOverallStats() ---@type table}> local allPlayersStats = {} - local allTeamsStats = { - { - kills = 0, - deaths = 0, - assists = 0, - towers = 0, - inhibitors = 0, - dragons = 0, - atakhans = 0, - heralds = 0, - barons = 0, - }, - { - kills = 0, - deaths = 0, - assists = 0, - towers = 0, - inhibitors = 0, - dragons = 0, - atakhans = 0, - heralds = 0, - barons = 0, - } - } + local allTeamsStats = Array.map(self.matchData.opponents, Operator.property('extradata')) Array.forEach(self.games, function(game) if game.status == BaseMatchPage.NOT_PLAYED then @@ -198,15 +175,6 @@ function MatchPage:renderOverallStats() local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) Array.forEach(game.opponents, function(team, teamIdx) - allTeamsStats[teamIdx].kills = allTeamsStats[teamIdx].kills + (team.stats.kills or 0) - allTeamsStats[teamIdx].deaths = allTeamsStats[teamIdx].deaths + (team.stats.deaths or 0) - allTeamsStats[teamIdx].assists = allTeamsStats[teamIdx].assists + (team.stats.assists or 0) - allTeamsStats[teamIdx].towers = allTeamsStats[teamIdx].towers + (team.stats.towers or 0) - allTeamsStats[teamIdx].inhibitors = allTeamsStats[teamIdx].inhibitors + (team.stats.inhibitors or 0) - allTeamsStats[teamIdx].dragons = allTeamsStats[teamIdx].dragons + (team.stats.dragons or 0) - allTeamsStats[teamIdx].atakhans = allTeamsStats[teamIdx].atakhans + (team.stats.atakhans or 0) - allTeamsStats[teamIdx].heralds = allTeamsStats[teamIdx].heralds + (team.stats.heralds or 0) - allTeamsStats[teamIdx].barons = allTeamsStats[teamIdx].barons + (team.stats.barons or 0) Array.forEach(team.players or {}, function(player) local playerId = player.player if not playerId then return end From 4277327e1971bdaef994f5c64cef3ffd9b05d25a Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:40:12 +0900 Subject: [PATCH 19/38] use getTournamentIcon --- lua/wikis/leagueoflegends/MatchPage.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 79009ca9190..8e30a8c9e5d 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -239,11 +239,7 @@ function MatchPage:renderOverallStats() }, Div{ classes = {'match-bm-team-stats-list-cell'}, - children = IconImage{ - imageLight = self:getMatchContext().icon, - imageDark = self:getMatchContext().icondark, - size = 'x32px', - } + children = self:getTournamentIcon() }, Div{ classes = {'match-bm-lol-team-stats-header-team'}, From 005c6a9b8ab80f489474bc8c4511009eb0db2be1 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 21:52:57 +0900 Subject: [PATCH 20/38] add nilSafeAdd to Module:Operator --- lua/wikis/commons/Operator.lua | 13 ++++++++ .../MatchGroup/Input/Custom.lua | 31 ++++++------------- .../MatchGroup/Input/Custom/MatchPage.lua | 14 +-------- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/lua/wikis/commons/Operator.lua b/lua/wikis/commons/Operator.lua index 308ae4037fc..a851e7d217a 100644 --- a/lua/wikis/commons/Operator.lua +++ b/lua/wikis/commons/Operator.lua @@ -19,6 +19,19 @@ function Operator.add(a, b) return a + b end +---A `nil`-safe version of `Operator.add` +---@param a number? +---@param b number? +---@return number? +function Operator.nilSafeAdd(a, b) + if not a then + return b + elseif not b then + return a + end + return a + b + end + ---Uses the __sub metamethod (a - b) ---@param a number ---@param b number diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 55cb2b7987d..f3c94e25796 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -10,6 +10,7 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local FnUtil = Lua.import('Module:FnUtil') local HeroNames = Lua.import('Module:ChampionNames', {loadData = true}) +local Operator = Lua.import('Module:Operator') local String = Lua.import('Module:StringUtils') local Table = Lua.import('Module:Table') @@ -101,18 +102,6 @@ end ---@param opponents table[] ---@return table function MatchFunctions.getExtraData(match, games, opponents) - ---@param a number? - ---@param b number? - ---@return number? - local function nilSafeAdd(a, b) - if not a then - return b - elseif not b then - return a - end - return a + b - end - if games[1] and games[1].opponents[1].stats then Array.forEach(opponents, function (opponent, opponentIndex) opponent.extradata = { @@ -120,55 +109,55 @@ function MatchFunctions.getExtraData(match, games, opponents) Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).kills end), - nilSafeAdd + Operator.nilSafeAdd ), deaths = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).deaths end), - nilSafeAdd + Operator.nilSafeAdd ), assists = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).assists end), - nilSafeAdd + Operator.nilSafeAdd ), towers = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).towers end), - nilSafeAdd + Operator.nilSafeAdd ), inhibitors = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).inhibitors end), - nilSafeAdd + Operator.nilSafeAdd ), dragons = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).dragons end), - nilSafeAdd + Operator.nilSafeAdd ), atakhans = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).atakhans end), - nilSafeAdd + Operator.nilSafeAdd ), heralds = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).heralds end), - nilSafeAdd + Operator.nilSafeAdd ), barons = Array.reduce( Array.map(games, function (game) return (game.opponents[opponentIndex].stats or {}).barons end), - nilSafeAdd + Operator.nilSafeAdd ) } end) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua index 9c292bdfa80..a1f8315c948 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom/MatchPage.lua @@ -129,23 +129,11 @@ function CustomMatchGroupInputMatchPage.extendMapOpponent(map, opponentIndex) end ---@cast participants -nil - ---@param a number? - ---@param b number? - ---@return number? - local function nilSafeAdd(a, b) - if not a then - return b - elseif not b then - return a - end - return a + b - end - ---@param arr table[] ---@param item string ---@return number? local function sumItem(arr, item) - return Array.reduce(Array.map(arr, Operator.property(item)), nilSafeAdd, 0) + return Array.reduce(Array.map(arr, Operator.property(item)), Operator.nilSafeAdd, 0) end return { From da44c42f386b9fe90a269df38ca2174346d73183 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 21:58:17 +0900 Subject: [PATCH 21/38] more refactoring --- .../MatchGroup/Input/Custom.lua | 65 ++++--------------- 1 file changed, 14 insertions(+), 51 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index f3c94e25796..3091dfd47bb 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -104,61 +104,24 @@ end function MatchFunctions.getExtraData(match, games, opponents) if games[1] and games[1].opponents[1].stats then Array.forEach(opponents, function (opponent, opponentIndex) - opponent.extradata = { - kills = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).kills - end), - Operator.nilSafeAdd - ), - deaths = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).deaths - end), - Operator.nilSafeAdd - ), - assists = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).assists - end), - Operator.nilSafeAdd - ), - towers = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).towers - end), - Operator.nilSafeAdd - ), - inhibitors = Array.reduce( + local function aggregateStats(name) + return Array.reduce( Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).inhibitors - end), - Operator.nilSafeAdd - ), - dragons = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).dragons - end), - Operator.nilSafeAdd - ), - atakhans = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).atakhans - end), - Operator.nilSafeAdd - ), - heralds = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).heralds - end), - Operator.nilSafeAdd - ), - barons = Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {}).barons + return (game.opponents[opponentIndex].stats or {})[name] end), Operator.nilSafeAdd ) + end + opponent.extradata = { + kills = aggregateStats('kills'), + deaths = aggregateStats('deaths'), + assists = aggregateStats('assists'), + towers = aggregateStats('towers'), + inhibitors = aggregateStats('inhibitors'), + dragons = aggregateStats('dragons'), + atakhans = aggregateStats('atakhans'), + heralds = aggregateStats('heralds'), + barons = aggregateStats('barons') } end) end From 9c33ef65a2d815d2a2a5c41d5d63df2a64b015c4 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 21:59:25 +0900 Subject: [PATCH 22/38] type annotation --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 3091dfd47bb..a9504cc5bd5 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -104,6 +104,8 @@ end function MatchFunctions.getExtraData(match, games, opponents) if games[1] and games[1].opponents[1].stats then Array.forEach(opponents, function (opponent, opponentIndex) + ---@param name string + ---@return number? local function aggregateStats(name) return Array.reduce( Array.map(games, function (game) From ffe54124d8c3d607ec6b87f22162306e4ad9938f Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:00:22 +0900 Subject: [PATCH 23/38] fix indentation --- lua/wikis/commons/Operator.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lua/wikis/commons/Operator.lua b/lua/wikis/commons/Operator.lua index a851e7d217a..cd617a128cd 100644 --- a/lua/wikis/commons/Operator.lua +++ b/lua/wikis/commons/Operator.lua @@ -24,13 +24,13 @@ end ---@param b number? ---@return number? function Operator.nilSafeAdd(a, b) - if not a then - return b - elseif not b then - return a - end - return a + b + if not a then + return b + elseif not b then + return a end + return a + b +end ---Uses the __sub metamethod (a - b) ---@param a number From e2d0f3d1c2aaf64fa3e0b853a476ea13f5479024 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:18:43 +0900 Subject: [PATCH 24/38] start accumulating player stats Co-authored-by: hjpalpha <75081997+hjpalpha@users.noreply.github.com> --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index a9504cc5bd5..fe8df32e30f 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -125,8 +125,18 @@ function MatchFunctions.getExtraData(match, games, opponents) heralds = aggregateStats('heralds'), barons = aggregateStats('barons') } + Array.forEach(games, function (game) + opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) + player.extradata = {} + player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, game.opponents[opponentIndex].players[playerIndex].damage) + return player + end) + end) end) end + + opponents = Table.deepCopy(opponents) + return { mvp = MatchGroupInputUtil.readMvp(match, opponents), } From 775f2651dcdd0cef1213fcda4c924bb84b8b5c99 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:33:41 +0900 Subject: [PATCH 25/38] finish accumulating stats --- .../MatchGroup/Input/Custom.lua | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index fe8df32e30f..29b9640894f 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -10,6 +10,7 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local FnUtil = Lua.import('Module:FnUtil') local HeroNames = Lua.import('Module:ChampionNames', {loadData = true}) +local Logic = Lua.import('Module:Logic') local Operator = Lua.import('Module:Operator') local String = Lua.import('Module:StringUtils') local Table = Lua.import('Module:Table') @@ -126,17 +127,38 @@ function MatchFunctions.getExtraData(match, games, opponents) barons = aggregateStats('barons') } Array.forEach(games, function (game) + if game.status == 'notplayed' then + return + end opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) - player.extradata = {} - player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, game.opponents[opponentIndex].players[playerIndex].damage) + local gamePlayerData = game.opponents[opponentIndex].players[playerIndex] + if Logic.isEmpty(gamePlayerData) then + return player + end + local parsedGameLength = Array.map( + Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) + ---Directly using tonumber as arg to Array.map causes base out of range error + return tonumber(element) + end + ) + local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) + player.extradata = player.extradata or {} + player.extradata.role = player.extradata.role or gamePlayerData.role + player.extradata.characters = Array.extend(player.extradata.characters, gamePlayerData.character) + player.extradata.kills = Operator.nilSafeAdd(player.extradata.kills, gamePlayerData.kills) + player.extradata.deaths = Operator.nilSafeAdd(player.extradata.deaths, gamePlayerData.deaths) + player.extradata.assists = Operator.nilSafeAdd(player.extradata.assists, gamePlayerData.assists) + player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, gamePlayerData.damagedone) + player.extradata.creepscore = Operator.nilSafeAdd(player.extradata.creepscore, gamePlayerData.creepscore) + player.extradata.gold = Operator.nilSafeAdd(player.extradata.gold, gamePlayerData.gold) + player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) return player end) end) end) + opponents = Table.deepCopy(opponents) end - opponents = Table.deepCopy(opponents) - return { mvp = MatchGroupInputUtil.readMvp(match, opponents), } From 8b9b9b1ce3c9d90d366787d55af233f7986a1a44 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:41:50 +0900 Subject: [PATCH 26/38] adjust matchpage display to read from extradata --- lua/wikis/leagueoflegends/MatchPage.lua | 94 +++++-------------------- 1 file changed, 16 insertions(+), 78 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index 8e30a8c9e5d..b0671c61a30 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -157,73 +157,6 @@ function MatchPage:renderOverallStats() return end - ---@type table}> - local allPlayersStats = {} - local allTeamsStats = Array.map(self.matchData.opponents, Operator.property('extradata')) - - Array.forEach(self.games, function(game) - if game.status == BaseMatchPage.NOT_PLAYED then - return - end - local parsedGameLength = Array.map( - Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) - ---Directly using tonumber as arg to Array.map causes base out of range error - return tonumber(element) - end - ) - local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - - Array.forEach(game.opponents, function(team, teamIdx) - Array.forEach(team.players or {}, function(player) - local playerId = player.player - if not playerId then return end - - if not allPlayersStats[playerId] then - allPlayersStats[playerId] = { - displayName = player.displayName or player.player, - playerName = player.player, - teamIndex = teamIdx, - champions = {}, - role = player.role, - stats = { - damage = 0, - gold = 0, - creepscore = 0, - gameLength = 0, - kills = 0, - deaths = 0, - assists = 0, - } - } - end - - local data = allPlayersStats[playerId] - if player.character then - table.insert(data.champions, player.character) - end - - local stats = data.stats - stats.damage = stats.damage + (player.damagedone or 0) - stats.gold = stats.gold + (player.gold or 0) - stats.creepscore = stats.creepscore + (player.creepscore or 0) - stats.gameLength = stats.gameLength + gameLength - stats.kills = stats.kills + (player.kills or 0) - stats.deaths = stats.deaths + (player.deaths or 0) - stats.assists = stats.assists + (player.assists or 0) - end) - end) - end) - - local ungroupedPlayers = Array.sortBy(Array.extractValues(allPlayersStats), function(player) - return ROLE_ORDER[player.role] - end) - local players = Array.map(Array.range(1, 2), function (teamIdx) - return Array.filter(ungroupedPlayers, function (player) - return player.teamIndex == teamIdx - end) - end) - local function renderOverallTeamStats() return { HtmlWidgets.H3{children = 'Overall Team Stats'}, @@ -249,7 +182,7 @@ function MatchPage:renderOverallStats() }, MatchPage._buildTeamStatsList{ finished = true, - data = allTeamsStats + data = Array.map(self.matchData.opponents, Operator.property('extradata')) } } } @@ -266,15 +199,20 @@ function MatchPage:renderOverallStats() return string.format('%.2f', stat / gameLength * 60) end + ---@param player standardPlayer + ---@return Widget? local function renderPlayerOverallPerformance(player) + if Logic.isEmpty(player.extradata) then + return + end return Div{ classes = {'match-bm-players-player match-bm-players-player--col-2'}, children = WidgetUtil.collect( Div{ classes = {'match-bm-players-player-name'}, children = { - Link{link = player.playerName, children = player.displayName}, - MatchSummaryCharacters{characters = player.champions, date = self.matchData.date}, + Link{link = player.pageName, children = player.displayName}, + MatchSummaryCharacters{characters = player.extradata.characters, date = self.matchData.date}, } }, Div{ @@ -283,9 +221,9 @@ function MatchPage:renderOverallStats() PlayerStat{ title = {KDA_ICON, 'KDA'}, data = Array.interleave({ - player.stats.kills, - player.stats.deaths, - player.stats.assists + player.extradata.kills, + player.extradata.deaths, + player.extradata.assists }, SPAN_SLASH) }, PlayerStat{ @@ -297,11 +235,11 @@ function MatchPage:renderOverallStats() }, 'CSM' }, - data = calculateStatPerMinute(player.stats.creepscore, player.stats.gameLength) + data = calculateStatPerMinute(player.extradata.creepscore, player.extradata.gameLength) }, PlayerStat{ title = {GOLD_ICON, 'GPM'}, - data = calculateStatPerMinute(player.stats.gold, player.stats.gameLength) + data = calculateStatPerMinute(player.extradata.gold, player.extradata.gameLength) }, PlayerStat{ title = { @@ -312,7 +250,7 @@ function MatchPage:renderOverallStats() }, 'DPM' }, - data = calculateStatPerMinute(player.stats.damage, player.stats.gameLength) + data = calculateStatPerMinute(player.extradata.damage, player.extradata.gameLength) } } } @@ -326,7 +264,7 @@ function MatchPage:renderOverallStats() HtmlWidgets.H3{children = 'Overall Player Performance'}, Div{ classes = {'match-bm-players-wrapper'}, - children = Array.map(self.opponents, function (opponent, teamIndex) + children = Array.map(self.opponents, function (opponent) return Div{ classes = {'match-bm-players-team'}, children = WidgetUtil.collect( @@ -334,7 +272,7 @@ function MatchPage:renderOverallStats() classes = {'match-bm-players-team-header'}, children = opponent.iconDisplay }, - Array.map(players[teamIndex], renderPlayerOverallPerformance) + Array.map(opponent.players, renderPlayerOverallPerformance) ) } end) From 32e685391139a03f49a1fdeb59da13a1392df3bb Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:43:45 +0900 Subject: [PATCH 27/38] comment to explain deepCopy --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 29b9640894f..fe7b18386b6 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -156,6 +156,7 @@ function MatchFunctions.getExtraData(match, games, opponents) end) end) end) + ---Deep copy here to work around circular reference error from LPDB storage opponents = Table.deepCopy(opponents) end From 21644e4c38fad6e60b21827ebbabf75742cb7e7d Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:50:48 +0900 Subject: [PATCH 28/38] type annotation --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index fe7b18386b6..9600814d0cf 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -67,7 +67,7 @@ function CustomMatchGroupInput.processMatch(match, options) end ---@param match table ----@param opponents table[] +---@param opponents MGIParsedOpponent[] ---@param MapParser LeagueOfLegendsMapParserInterface ---@return table[] function MatchFunctions.extractMaps(match, opponents, MapParser) @@ -100,7 +100,7 @@ end ---@param match table ---@param games table[] ----@param opponents table[] +---@param opponents MGIParsedOpponent[] ---@return table function MatchFunctions.getExtraData(match, games, opponents) if games[1] and games[1].opponents[1].stats then @@ -168,7 +168,7 @@ end ---@param MapParser LeagueOfLegendsMapParserInterface ---@param match table ---@param map table ----@param opponents table[] +---@param opponents MGIParsedOpponent[] ---@return table function MapFunctions.getExtraData(MapParser, match, map, opponents) local extraData = {} @@ -207,7 +207,7 @@ end ---@param MapParser LeagueOfLegendsMapParserInterface ---@param map table ----@param opponent table +---@param opponent MGIParsedOpponent ---@param opponentIndex integer ---@return table[] function MapFunctions.getPlayersOfMapOpponent(MapParser, map, opponent, opponentIndex) From 495284939ffe622bb4e32597a5545ffeeeeb191e Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 18:59:42 +0900 Subject: [PATCH 29/38] add constant for notplayed --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 9600814d0cf..917dca34479 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -30,6 +30,8 @@ MatchFunctions.OPPONENT_CONFIG = { MatchFunctions.DEFAULT_MODE = 'team' MatchFunctions.getBestOf = MatchGroupInputUtil.getBestOf +local NOT_PLAYED = 'notplayed' + ---@class LeagueOfLegendsMapParserInterface ---@field getMap fun(mapInput: table): table ---@field getLength fun(map: table): string? @@ -127,7 +129,7 @@ function MatchFunctions.getExtraData(match, games, opponents) barons = aggregateStats('barons') } Array.forEach(games, function (game) - if game.status == 'notplayed' then + if game.status == NOT_PLAYED then return end opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) From 98788171bd764da95d043127051141db30c55963 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 19:00:57 +0900 Subject: [PATCH 30/38] cleanup formatting --- .../MatchGroup/Input/Custom.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 917dca34479..2474fee56e3 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -19,16 +19,16 @@ local MatchGroupInputUtil = Lua.import('Module:MatchGroup/Input/Util') local MatchGroupUtil = Lua.import('Module:MatchGroup/Util/Custom') local CustomMatchGroupInput = {} -local MatchFunctions = {} -local MapFunctions = {} - -MatchFunctions.OPPONENT_CONFIG = { - resolveRedirect = true, - pagifyTeamNames = false, - maxNumPlayers = 15, +local MatchFunctions = { + OPPONENT_CONFIG = { + resolveRedirect = true, + pagifyTeamNames = false, + maxNumPlayers = 15, + }, + DEFAULT_MODE = 'team', + getBestOf = MatchGroupInputUtil.getBestOf } -MatchFunctions.DEFAULT_MODE = 'team' -MatchFunctions.getBestOf = MatchGroupInputUtil.getBestOf +local MapFunctions = {} local NOT_PLAYED = 'notplayed' From 869ba6bd51a721010e8a49fe7aa90f8394784b9b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 19:31:54 +0900 Subject: [PATCH 31/38] use existing constant --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 2474fee56e3..405a8ad604b 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -30,8 +30,6 @@ local MatchFunctions = { } local MapFunctions = {} -local NOT_PLAYED = 'notplayed' - ---@class LeagueOfLegendsMapParserInterface ---@field getMap fun(mapInput: table): table ---@field getLength fun(map: table): string? @@ -129,7 +127,7 @@ function MatchFunctions.getExtraData(match, games, opponents) barons = aggregateStats('barons') } Array.forEach(games, function (game) - if game.status == NOT_PLAYED then + if game.status == MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED then return end opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) From 2dd23dc3a926989d2c13b5f7ed6bbfd9b71c814e Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 19:47:29 +0900 Subject: [PATCH 32/38] use Array.forEach --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 405a8ad604b..9d77f303033 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -130,10 +130,10 @@ function MatchFunctions.getExtraData(match, games, opponents) if game.status == MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED then return end - opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) + Array.forEach(opponent.match2players, function (player, playerIndex) local gamePlayerData = game.opponents[opponentIndex].players[playerIndex] if Logic.isEmpty(gamePlayerData) then - return player + return end local parsedGameLength = Array.map( Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) @@ -152,7 +152,6 @@ function MatchFunctions.getExtraData(match, games, opponents) player.extradata.creepscore = Operator.nilSafeAdd(player.extradata.creepscore, gamePlayerData.creepscore) player.extradata.gold = Operator.nilSafeAdd(player.extradata.gold, gamePlayerData.gold) player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) - return player end) end) end) From 7d98cf495cd7429d08f9427aa3dbb49c2ac327a5 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 20:30:20 +0900 Subject: [PATCH 33/38] switch looping order --- .../MatchGroup/Input/Custom.lua | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 9d77f303033..21c6d247b5a 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -126,33 +126,35 @@ function MatchFunctions.getExtraData(match, games, opponents) heralds = aggregateStats('heralds'), barons = aggregateStats('barons') } - Array.forEach(games, function (game) - if game.status == MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED then - return - end - Array.forEach(opponent.match2players, function (player, playerIndex) - local gamePlayerData = game.opponents[opponentIndex].players[playerIndex] - if Logic.isEmpty(gamePlayerData) then - return - end - local parsedGameLength = Array.map( - Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) - ---Directly using tonumber as arg to Array.map causes base out of range error - return tonumber(element) + Array.forEach(opponent.match2players, function (player, playerIndex) + Array.forEach( + Array.filter(games, function (game) + return game.status ~= MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED + end), + function (game) + local gamePlayerData = game.opponents[opponentIndex].players[playerIndex] + if Logic.isEmpty(gamePlayerData) then + return end - ) - local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - player.extradata = player.extradata or {} - player.extradata.role = player.extradata.role or gamePlayerData.role - player.extradata.characters = Array.extend(player.extradata.characters, gamePlayerData.character) - player.extradata.kills = Operator.nilSafeAdd(player.extradata.kills, gamePlayerData.kills) - player.extradata.deaths = Operator.nilSafeAdd(player.extradata.deaths, gamePlayerData.deaths) - player.extradata.assists = Operator.nilSafeAdd(player.extradata.assists, gamePlayerData.assists) - player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, gamePlayerData.damagedone) - player.extradata.creepscore = Operator.nilSafeAdd(player.extradata.creepscore, gamePlayerData.creepscore) - player.extradata.gold = Operator.nilSafeAdd(player.extradata.gold, gamePlayerData.gold) - player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) - end) + local parsedGameLength = Array.map( + Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) + ---Directly using tonumber as arg to Array.map causes base out of range error + return tonumber(element) + end + ) + local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) + player.extradata = player.extradata or {} + player.extradata.role = player.extradata.role or gamePlayerData.role + player.extradata.characters = Array.extend(player.extradata.characters, gamePlayerData.character) + player.extradata.kills = Operator.nilSafeAdd(player.extradata.kills, gamePlayerData.kills) + player.extradata.deaths = Operator.nilSafeAdd(player.extradata.deaths, gamePlayerData.deaths) + player.extradata.assists = Operator.nilSafeAdd(player.extradata.assists, gamePlayerData.assists) + player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, gamePlayerData.damagedone) + player.extradata.creepscore = Operator.nilSafeAdd(player.extradata.creepscore, gamePlayerData.creepscore) + player.extradata.gold = Operator.nilSafeAdd(player.extradata.gold, gamePlayerData.gold) + player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) + end + ) end) end) ---Deep copy here to work around circular reference error from LPDB storage From cae614f4c1873cffbecc6c2b7d1e72ba6924b9b5 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 20:52:42 +0900 Subject: [PATCH 34/38] start copy cleaning --- lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 21c6d247b5a..e5cc993dc2c 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -126,7 +126,9 @@ function MatchFunctions.getExtraData(match, games, opponents) heralds = aggregateStats('heralds'), barons = aggregateStats('barons') } - Array.forEach(opponent.match2players, function (player, playerIndex) + opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) + player = Table.copy(player) + player.extradata = {characters = {}} Array.forEach( Array.filter(games, function (game) return game.status ~= MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED @@ -143,7 +145,6 @@ function MatchFunctions.getExtraData(match, games, opponents) end ) local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - player.extradata = player.extradata or {} player.extradata.role = player.extradata.role or gamePlayerData.role player.extradata.characters = Array.extend(player.extradata.characters, gamePlayerData.character) player.extradata.kills = Operator.nilSafeAdd(player.extradata.kills, gamePlayerData.kills) @@ -155,6 +156,8 @@ function MatchFunctions.getExtraData(match, games, opponents) player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) end ) + player.extradata.characters = Logic.nilIfEmpty(player.extradata.characters) + return player end) end) ---Deep copy here to work around circular reference error from LPDB storage From 36d76cc5a7147ffd18c013e201a77f004468b436 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 20:52:56 +0900 Subject: [PATCH 35/38] sort players in overall stats --- lua/wikis/leagueoflegends/MatchPage.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lua/wikis/leagueoflegends/MatchPage.lua b/lua/wikis/leagueoflegends/MatchPage.lua index b0671c61a30..5273ff1a0f5 100644 --- a/lua/wikis/leagueoflegends/MatchPage.lua +++ b/lua/wikis/leagueoflegends/MatchPage.lua @@ -37,6 +37,7 @@ local WidgetUtil = Lua.import('Module:Widget/Util') ---@class LoLMatchPage: BaseMatchPage ---@field games LoLMatchPageGame[] +---@operator call(MatchGroupUtilMatch): BaseMatchPage local MatchPage = Class.new(BaseMatchPage) local KEYSTONES = Table.map({ @@ -272,7 +273,12 @@ function MatchPage:renderOverallStats() classes = {'match-bm-players-team-header'}, children = opponent.iconDisplay }, - Array.map(opponent.players, renderPlayerOverallPerformance) + Array.map( + Array.sortBy(opponent.players, function (player) + return ROLE_ORDER[player.extradata.role] or -1 + end), + renderPlayerOverallPerformance + ) ) } end) From bb3ec45978d91a1b4114842da7518bb23f2ee0fa Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 21:06:40 +0900 Subject: [PATCH 36/38] optimize copying --- .../MatchGroup/Input/Custom.lua | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index e5cc993dc2c..055d76370c9 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -104,7 +104,8 @@ end ---@return table function MatchFunctions.getExtraData(match, games, opponents) if games[1] and games[1].opponents[1].stats then - Array.forEach(opponents, function (opponent, opponentIndex) + opponents = Array.map(opponents, function (opponent, opponentIndex) + opponent = Table.copy(opponent) ---@param name string ---@return number? local function aggregateStats(name) @@ -127,8 +128,7 @@ function MatchFunctions.getExtraData(match, games, opponents) barons = aggregateStats('barons') } opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) - player = Table.copy(player) - player.extradata = {characters = {}} + local extradata = {characters = {}} Array.forEach( Array.filter(games, function (game) return game.status ~= MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED @@ -145,23 +145,22 @@ function MatchFunctions.getExtraData(match, games, opponents) end ) local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - player.extradata.role = player.extradata.role or gamePlayerData.role - player.extradata.characters = Array.extend(player.extradata.characters, gamePlayerData.character) - player.extradata.kills = Operator.nilSafeAdd(player.extradata.kills, gamePlayerData.kills) - player.extradata.deaths = Operator.nilSafeAdd(player.extradata.deaths, gamePlayerData.deaths) - player.extradata.assists = Operator.nilSafeAdd(player.extradata.assists, gamePlayerData.assists) - player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, gamePlayerData.damagedone) - player.extradata.creepscore = Operator.nilSafeAdd(player.extradata.creepscore, gamePlayerData.creepscore) - player.extradata.gold = Operator.nilSafeAdd(player.extradata.gold, gamePlayerData.gold) - player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) + extradata.role = extradata.role or gamePlayerData.role + extradata.characters = Array.extend(extradata.characters, gamePlayerData.character) + extradata.kills = Operator.nilSafeAdd(extradata.kills, gamePlayerData.kills) + extradata.deaths = Operator.nilSafeAdd(extradata.deaths, gamePlayerData.deaths) + extradata.assists = Operator.nilSafeAdd(extradata.assists, gamePlayerData.assists) + extradata.damage = Operator.nilSafeAdd(extradata.damage, gamePlayerData.damagedone) + extradata.creepscore = Operator.nilSafeAdd(extradata.creepscore, gamePlayerData.creepscore) + extradata.gold = Operator.nilSafeAdd(extradata.gold, gamePlayerData.gold) + extradata.gameLength = Operator.nilSafeAdd(extradata.gameLength, gameLength) end ) - player.extradata.characters = Logic.nilIfEmpty(player.extradata.characters) - return player + extradata.characters = Logic.nilIfEmpty(extradata.characters) + player.extradata = extradata + return Table.deepCopy(player) end) end) - ---Deep copy here to work around circular reference error from LPDB storage - opponents = Table.deepCopy(opponents) end return { From 383222ab1e58f63dcdac22c8e0f8515445b7d082 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 21:16:46 +0900 Subject: [PATCH 37/38] restore everything else --- .../MatchGroup/Input/Custom.lua | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 055d76370c9..4883396f785 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -105,7 +105,6 @@ end function MatchFunctions.getExtraData(match, games, opponents) if games[1] and games[1].opponents[1].stats then opponents = Array.map(opponents, function (opponent, opponentIndex) - opponent = Table.copy(opponent) ---@param name string ---@return number? local function aggregateStats(name) @@ -116,7 +115,7 @@ function MatchFunctions.getExtraData(match, games, opponents) Operator.nilSafeAdd ) end - opponent.extradata = { + opponent.extradata = Table.merge(opponent.extradata, { kills = aggregateStats('kills'), deaths = aggregateStats('deaths'), assists = aggregateStats('assists'), @@ -126,9 +125,9 @@ function MatchFunctions.getExtraData(match, games, opponents) atakhans = aggregateStats('atakhans'), heralds = aggregateStats('heralds'), barons = aggregateStats('barons') - } - opponent.match2players = Array.map(opponent.match2players, function (player, playerIndex) - local extradata = {characters = {}} + }) + Array.forEach(opponent.match2players, function (player, playerIndex) + local playerExtradata = {characters = {}} Array.forEach( Array.filter(games, function (game) return game.status ~= MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED @@ -145,21 +144,21 @@ function MatchFunctions.getExtraData(match, games, opponents) end ) local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - extradata.role = extradata.role or gamePlayerData.role - extradata.characters = Array.extend(extradata.characters, gamePlayerData.character) - extradata.kills = Operator.nilSafeAdd(extradata.kills, gamePlayerData.kills) - extradata.deaths = Operator.nilSafeAdd(extradata.deaths, gamePlayerData.deaths) - extradata.assists = Operator.nilSafeAdd(extradata.assists, gamePlayerData.assists) - extradata.damage = Operator.nilSafeAdd(extradata.damage, gamePlayerData.damagedone) - extradata.creepscore = Operator.nilSafeAdd(extradata.creepscore, gamePlayerData.creepscore) - extradata.gold = Operator.nilSafeAdd(extradata.gold, gamePlayerData.gold) - extradata.gameLength = Operator.nilSafeAdd(extradata.gameLength, gameLength) + playerExtradata.role = playerExtradata.role or gamePlayerData.role + playerExtradata.characters = Array.extend(playerExtradata.characters, gamePlayerData.character) + playerExtradata.kills = Operator.nilSafeAdd(playerExtradata.kills, gamePlayerData.kills) + playerExtradata.deaths = Operator.nilSafeAdd(playerExtradata.deaths, gamePlayerData.deaths) + playerExtradata.assists = Operator.nilSafeAdd(playerExtradata.assists, gamePlayerData.assists) + playerExtradata.damage = Operator.nilSafeAdd(playerExtradata.damage, gamePlayerData.damagedone) + playerExtradata.creepscore = Operator.nilSafeAdd(playerExtradata.creepscore, gamePlayerData.creepscore) + playerExtradata.gold = Operator.nilSafeAdd(playerExtradata.gold, gamePlayerData.gold) + playerExtradata.gameLength = Operator.nilSafeAdd(playerExtradata.gameLength, gameLength) end ) - extradata.characters = Logic.nilIfEmpty(extradata.characters) - player.extradata = extradata - return Table.deepCopy(player) + playerExtradata.characters = Logic.nilIfEmpty(playerExtradata.characters) + player.extradata = playerExtradata end) + return Table.deepCopy(opponent) end) end From 7a878b750d1194ee763af5481bb23d3c5165d44d Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Tue, 7 Oct 2025 21:30:52 +0900 Subject: [PATCH 38/38] extract aggregating step --- .../MatchGroup/Input/Custom.lua | 124 +++++++++--------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua index 4883396f785..d49b9b5155b 100644 --- a/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua +++ b/lua/wikis/leagueoflegends/MatchGroup/Input/Custom.lua @@ -63,7 +63,70 @@ function CustomMatchGroupInput.processMatch(match, options) MapParser = Lua.import('Module:MatchGroup/Input/Custom/Normal') end - return MatchGroupInputUtil.standardProcessMatch(match, MatchFunctions, nil, MapParser) + local processedMatch = MatchGroupInputUtil.standardProcessMatch(match, MatchFunctions, nil, MapParser) + + if options.isMatchPage then + CustomMatchGroupInput.aggregateStats(processedMatch) + end + return processedMatch +end + +---@param match {opponents: MGIParsedOpponent[], games: table[]} +function CustomMatchGroupInput.aggregateStats(match) + Array.forEach(match.opponents, function (opponent, opponentIndex) + ---@param name string + ---@return number? + local function aggregateStats(name) + return Array.reduce( + Array.map(match.games, function (game) + return (game.opponents[opponentIndex].stats or {})[name] + end), + Operator.nilSafeAdd + ) + end + opponent.extradata = Table.merge(opponent.extradata, { + kills = aggregateStats('kills'), + deaths = aggregateStats('deaths'), + assists = aggregateStats('assists'), + towers = aggregateStats('towers'), + inhibitors = aggregateStats('inhibitors'), + dragons = aggregateStats('dragons'), + atakhans = aggregateStats('atakhans'), + heralds = aggregateStats('heralds'), + barons = aggregateStats('barons') + }) + Array.forEach(opponent.match2players, function (player, playerIndex) + player.extradata = {characters = {}} + Array.forEach( + Array.filter(match.games, function (game) + return game.status ~= MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED + end), + function (game) + local gamePlayerData = game.opponents[opponentIndex].players[playerIndex] + if Logic.isEmpty(gamePlayerData) then + return + end + local parsedGameLength = Array.map( + Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) + ---Directly using tonumber as arg to Array.map causes base out of range error + return tonumber(element) + end + ) + local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) + player.extradata.role = player.extradata.role or gamePlayerData.role + player.extradata.characters = Array.extend(player.extradata.characters, gamePlayerData.character) + player.extradata.kills = Operator.nilSafeAdd(player.extradata.kills, gamePlayerData.kills) + player.extradata.deaths = Operator.nilSafeAdd(player.extradata.deaths, gamePlayerData.deaths) + player.extradata.assists = Operator.nilSafeAdd(player.extradata.assists, gamePlayerData.assists) + player.extradata.damage = Operator.nilSafeAdd(player.extradata.damage, gamePlayerData.damagedone) + player.extradata.creepscore = Operator.nilSafeAdd(player.extradata.creepscore, gamePlayerData.creepscore) + player.extradata.gold = Operator.nilSafeAdd(player.extradata.gold, gamePlayerData.gold) + player.extradata.gameLength = Operator.nilSafeAdd(player.extradata.gameLength, gameLength) + end + ) + player.extradata.characters = Logic.nilIfEmpty(player.extradata.characters) + end) + end) end ---@param match table @@ -103,65 +166,6 @@ end ---@param opponents MGIParsedOpponent[] ---@return table function MatchFunctions.getExtraData(match, games, opponents) - if games[1] and games[1].opponents[1].stats then - opponents = Array.map(opponents, function (opponent, opponentIndex) - ---@param name string - ---@return number? - local function aggregateStats(name) - return Array.reduce( - Array.map(games, function (game) - return (game.opponents[opponentIndex].stats or {})[name] - end), - Operator.nilSafeAdd - ) - end - opponent.extradata = Table.merge(opponent.extradata, { - kills = aggregateStats('kills'), - deaths = aggregateStats('deaths'), - assists = aggregateStats('assists'), - towers = aggregateStats('towers'), - inhibitors = aggregateStats('inhibitors'), - dragons = aggregateStats('dragons'), - atakhans = aggregateStats('atakhans'), - heralds = aggregateStats('heralds'), - barons = aggregateStats('barons') - }) - Array.forEach(opponent.match2players, function (player, playerIndex) - local playerExtradata = {characters = {}} - Array.forEach( - Array.filter(games, function (game) - return game.status ~= MatchGroupInputUtil.MATCH_STATUS.NOT_PLAYED - end), - function (game) - local gamePlayerData = game.opponents[opponentIndex].players[playerIndex] - if Logic.isEmpty(gamePlayerData) then - return - end - local parsedGameLength = Array.map( - Array.parseCommaSeparatedString(game.length --[[@as string]], ':'), function (element) - ---Directly using tonumber as arg to Array.map causes base out of range error - return tonumber(element) - end - ) - local gameLength = (parsedGameLength[1] or 0) * 60 + (parsedGameLength[2] or 0) - playerExtradata.role = playerExtradata.role or gamePlayerData.role - playerExtradata.characters = Array.extend(playerExtradata.characters, gamePlayerData.character) - playerExtradata.kills = Operator.nilSafeAdd(playerExtradata.kills, gamePlayerData.kills) - playerExtradata.deaths = Operator.nilSafeAdd(playerExtradata.deaths, gamePlayerData.deaths) - playerExtradata.assists = Operator.nilSafeAdd(playerExtradata.assists, gamePlayerData.assists) - playerExtradata.damage = Operator.nilSafeAdd(playerExtradata.damage, gamePlayerData.damagedone) - playerExtradata.creepscore = Operator.nilSafeAdd(playerExtradata.creepscore, gamePlayerData.creepscore) - playerExtradata.gold = Operator.nilSafeAdd(playerExtradata.gold, gamePlayerData.gold) - playerExtradata.gameLength = Operator.nilSafeAdd(playerExtradata.gameLength, gameLength) - end - ) - playerExtradata.characters = Logic.nilIfEmpty(playerExtradata.characters) - player.extradata = playerExtradata - end) - return Table.deepCopy(opponent) - end) - end - return { mvp = MatchGroupInputUtil.readMvp(match, opponents), }