Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(match2): dota2's match page into widget #4897

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/match2/commons/match_group_display_helper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ function DisplayHelper.DefaultMatchSummaryContainer(props)
end

---@param props table
---@return Html
---@return Widget
function DisplayHelper.DefaultMatchPageContainer(props)
local MatchPageModule = Lua.import('Module:MatchPage')

Expand Down
261 changes: 155 additions & 106 deletions components/match2/wikis/dota2/match_page.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ local Operator = require('Module:Operator')
local String = require('Module:StringUtils')
local Table = require('Module:Table')
local Tabs = require('Module:Tabs')
local TemplateEngine = require('Module:TemplateEngine')
local VodLink = require('Module:VodLink')

local DisplayHelper = Lua.import('Module:MatchGroup/Display/Helper')
local MatchGroupUtil = Lua.import('Module:MatchGroup/Util')
local Display = Lua.import('Module:MatchPage/Template')

local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local MatchPageWidgets = Lua.import('Module:Widget/Match/Page/All')

local MatchPage = {}

Expand Down Expand Up @@ -50,115 +51,39 @@ end
---@field seriesDots string[]

---@param props {match: MatchGroupUtilMatch}
---@return Html
---@return Widget
function MatchPage.getByMatchId(props)
---@class Dota2MatchPageViewModel: MatchGroupUtilMatch
---@field games Dota2MatchPageViewModelGame[]
---@field opponents Dota2MatchPageViewModelOpponent[]
local viewModel = props.match

viewModel.isBestOfOne = #viewModel.games == 1
viewModel.dateCountdown = viewModel.timestamp ~= DateExt.defaultTimestamp and
DisplayHelper.MatchCountdownBlock(viewModel) or nil

local phase = MatchGroupUtil.computeMatchPhase(props.match)
viewModel.statusText = phase == 'ongoing' and 'live' or phase

local function makeItemDisplay(item)
if String.isEmpty(item.name) then
return '[[File:EmptyIcon itemicon dota2 gameasset.png|64px|Empty|link=]]'
end
return '[[File:'.. item.image ..'|64px|'.. item.name ..'|link=]]'
end

-- Update the view model with game and team data
Array.forEach(viewModel.games, function(game)
game.finished = game.winner ~= nil and game.winner ~= -1
game.teams = Array.map(Array.range(1, 2), function(teamIdx)
local team = {players = {}}

team.scoreDisplay = game.winner == teamIdx and 'winner' or game.finished and 'loser' or '-'
team.side = String.nilIfEmpty(game.extradata['team' .. teamIdx ..'side'])
local team = {
players = {},
scoreDisplay = game.winner == teamIdx and 'winner' or game.finished and 'loser' or '-',
side = String.nilIfEmpty(game.extradata['team' .. teamIdx ..'side']),
objectives = game.extradata['team' .. teamIdx .. 'objectives'],
template = viewModel.opponents[teamIdx].template,
}

for _, player in Table.iter.pairsByPrefix(game.participants, teamIdx .. '_') do
local newPlayer = Table.mergeInto(player, {
displayName = player.name or player.player,
link = player.player,
items = Array.map(player.items or {}, makeItemDisplay),
backpackitems = Array.map(player.backpackitems or {}, makeItemDisplay),
neutralitem = makeItemDisplay(player.neutralitem or {}),
items = player.items or {},
backpackitems = player.backpackitems or {},
neutralitem = player.neutralitem or {},
})

newPlayer.displayDamageDone = MatchPage._abbreviateNumber(player.damagedone)
newPlayer.displayGold = MatchPage._abbreviateNumber(player.gold)

table.insert(team.players, newPlayer)
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']
end

team.picks = Array.filter(game.extradata.vetophase or {}, function(veto)
return veto.type == 'pick' and veto.team == teamIdx
end)
team.bans = Array.filter(game.extradata.vetophase or {}, function(veto)
return veto.type == 'ban' and veto.team == teamIdx
end)

return team
end)
if game.finished and viewModel.opponents[game.winner] then
game.winnerName = viewModel.opponents[game.winner].name
end
end)

-- Add more opponent data field
Array.forEach(viewModel.opponents, function(opponent, index)
opponent.opponentIndex = index

local teamTemplate = opponent.template and mw.ext.TeamTemplate.raw(opponent.template)
if not teamTemplate then
return
end

opponent.iconDisplay = mw.ext.TeamTemplate.teamicon(opponent.template)
opponent.shortname = teamTemplate.shortname
opponent.page = teamTemplate.page
opponent.name = teamTemplate.name

opponent.seriesDots = Array.map(viewModel.games, function(game)
return game.teams[index].scoreDisplay
end)
end)

viewModel.vods = Array.map(viewModel.games, function(game, gameIdx)
return game.vod and VodLink.display{
gamenum = gameIdx,
vod = game.vod,
} or ''
end)

-- Create an object array for links
local function processLink(site, link)
return Table.mergeInto({link = link}, MatchLinks[site])
end

viewModel.links = Array.flatMap(Table.entries(viewModel.links), function(linkData)
local site, link = unpack(linkData)
if type(link) == 'table' then
return Array.map(link, function(sublink)
return processLink(site, sublink)
end)
end
return {processLink(site, link)}
end)

viewModel.heroIcon = function(c)
Expand All @@ -176,7 +101,13 @@ function MatchPage.getByMatchId(props)
local displayTitle = MatchPage.makeDisplayTitle(viewModel)
mw.getCurrentFrame():preprocess(table.concat{'{{DISPLAYTITLE:', displayTitle, '}}'})

return MatchPage.render(viewModel)
return HtmlWidgets.Div{
children = {
MatchPage.header(viewModel),
MatchPage.games(viewModel),
MatchPage.footer(viewModel)
}
}
end

---@param viewModel table
Expand Down Expand Up @@ -214,28 +145,44 @@ function MatchPage._abbreviateNumber(number)
end

---@param model table
---@return Html
function MatchPage.render(model)
return mw.html.create('div')
:wikitext(MatchPage.header(model))
:node(MatchPage.games(model))
:wikitext(MatchPage.footer(model))
end

---@param model table
---@return string
---@return Widget
function MatchPage.header(model)
return TemplateEngine():render(Display.header, model)
local phase = MatchGroupUtil.computeMatchPhase(model)
local phaseDisplay = phase == 'ongoing' and 'live' or phase

local opponents = Array.map(model.opponents, function(opponent, index)
local teamTemplate = opponent.template and mw.ext.TeamTemplate.raw(opponent.template)
if not teamTemplate then
return {}
end

return {
icon = mw.ext.TeamTemplate.teamicon(opponent.template),
name = teamTemplate.name,
shortname = teamTemplate.shortname,
page = teamTemplate.page,
seriesDots = Array.map(model.games, function(game)
return game.teams[index].scoreDisplay
end),
}
end)

return MatchPageWidgets.header{
opponents = opponents,
matchPhase = phaseDisplay,
parent = model.parent,
tournament = model.tournament,
dateCountdown = model.timestamp ~= DateExt.defaultTimestamp and DisplayHelper.MatchCountdownBlock(model) or nil,
mvp = model.extradata.mvp,
}
end

---@param model table
---@return string
function MatchPage.games(model)
local games = Array.map(Array.filter(model.games, function(game)
return game.resultType ~= NOT_PLAYED
end), function(game)
return TemplateEngine():render(Display.game, Table.merge(model, game))
end)
end), MatchPage.game)

if #games < 2 then
return tostring(games[1])
Expand All @@ -255,10 +202,112 @@ function MatchPage.games(model)
return tostring(Tabs.dynamic(tabs))
end

---@param game table
---@return Widget
function MatchPage.game(game)
return HtmlWidgets.Fragment{
children = {
MatchPageWidgets.MatchPageGameDraft{
draft = game.extradata.vetophase,
opponents = Array.map(game.teams, function(opponent)
return {
template = opponent.template,
side = opponent.side,
}
end),
},
MatchPageWidgets.MatchPageGameStats{
opponents = Array.map(game.teams, function(opponent)
return {
template = opponent.template,
side = opponent.side,
score = opponent.scoreDisplay,
kills = MatchPage._sumItem(opponent.players, 'kills'),
deaths = MatchPage._sumItem(opponent.players, 'deaths'),
assists = MatchPage._sumItem(opponent.players, 'assists'),
gold = MatchPage._sumItem(opponent.players, 'gold'),
towers = opponent.objectives.towers,
barracks = opponent.objectives.barracks,
roshans = opponent.objectives.roshans,
}
end),
length = game.length,
winner = (game.teams[game.winner] or {}).name,
children = {
{
render = function(team)
if not team.kills or not team.deaths or not team.assists then
return ''
end
return team.kills .. '/' .. team.deaths .. '/' .. team.assists
end,
icon = '<i class="fas fa-skull-crossbones"></i>',
text = 'KDA',
},
{
render = function(team) return MatchPage._abbreviateNumber(team.gold) end,
icon = '<i class="fas fa-coins"></i>',
text = 'Gold',
},
{
render = function(team) return team.towers end,
icon = '<i class="fas fa-chess-rook"></i>',
text = 'Towers',
},
{
render = function(team) return team.barracks end,
icon = '<i class="fas fa-warehouse"></i>',
text = 'Barracks',
},
{
render = function(team) return team.roshans end,
icon = '<i class="liquipedia-custom-icon liquipedia-custom-icon-roshan"></i>',
text = 'Roshan',
},
}
},
MatchPageWidgets.MatchPageGamePlayers{
opponents = Array.map(game.teams, function (opponent)
return {
template = opponent.template,
players = opponent.players,
}
end)
},
}
}
end

---@param model table
---@return string
---@return Widget
function MatchPage.footer(model)
return TemplateEngine():render(Display.footer, model)
local vods = Array.map(model.games, function(game, gameIdx)
return game.vod and VodLink.display{
gamenum = gameIdx,
vod = game.vod,
} or ''
end)

-- Create an object array for links
local function processLink(site, link)
return Table.mergeInto({link = link}, MatchLinks[site])
end

local links = Array.flatMap(Table.entries(model.links), function(linkData)
local site, link = unpack(linkData)
if type(link) == 'table' then
return Array.map(link, function(sublink)
return processLink(site, sublink)
end)
end
return {processLink(site, link)}
end)

return MatchPageWidgets.footer{
vods = vods,
links = links,
patch = model.patch,
}
end

return MatchPage
Loading