From 23283705b61c966e9400f62bb4fb5635a2e73c7b Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 6 Nov 2024 12:01:06 +0100 Subject: [PATCH] feat(match2): standard processMatch on dota2 and lol (#5032) * feat(match2): standard processMatch on dota2 and lol * lint --- .../match2/commons/match_group_input_util.lua | 13 +- .../wikis/dota2/match_group_input_custom.lua | 126 ++++++------------ .../match_group_input_custom.lua | 110 +++++---------- 3 files changed, 82 insertions(+), 167 deletions(-) diff --git a/components/match2/commons/match_group_input_util.lua b/components/match2/commons/match_group_input_util.lua index 3059ba78538..33d4e91c643 100644 --- a/components/match2/commons/match_group_input_util.lua +++ b/components/match2/commons/match_group_input_util.lua @@ -1078,11 +1078,12 @@ function MatchGroupInputUtil.mergeStandaloneIntoMatch(match, standaloneMatch) end ---@class MatchParserInterface ----@field extractMaps fun(match: table, opponents: table[]): table[] +---@field extractMaps fun(match: table, opponents: table[], mapProps: any?): table[] ---@field getBestOf fun(bestOfInput: string|integer, maps: table[]): integer ---@field calculateMatchScore fun(maps: table[]): fun(opponentIndex: integer): integer ---@field removeUnsetMaps? fun(maps: table[]): table[] ---@field getExtraData? fun(match: table, games: table[], opponents: table[]): table +---@field getLinks? fun(match: table, games: table[]): table ---@field DEFAULT_MODE? string ---@field DATE_FALLBACKS? string[] ---@field OPPONENT_CONFIG? readOpponentOptions @@ -1090,13 +1091,14 @@ end --- The standard way to process a match input. --- --- The Parser injection must have the following functions: ---- - extractMaps(match, opponents): table[] +--- - extractMaps(match, opponents, mapProps): table[] --- - getBestOf(bestOfInput, maps): integer --- - calculateMatchScore(maps): fun(opponentIndex): integer --- --- It may optionally have the following functions: --- - removeUnsetMaps(maps): table[] --- - getExtraData(match, games, opponents): table +--- - getLinks --- --- Additionally, the Parser may have the following properties: --- - DEFAULT_MODE: string @@ -1104,8 +1106,9 @@ end --- - OPPONENT_CONFIG: table ---@param match table ---@param Parser MatchParserInterface +---@param mapProps any? ---@return table -function MatchGroupInputUtil.standardProcessMatch(match, Parser) +function MatchGroupInputUtil.standardProcessMatch(match, Parser, mapProps) local finishedInput = match.finished --[[@as string?]] local winnerInput = match.winner --[[@as string?]] @@ -1115,11 +1118,11 @@ function MatchGroupInputUtil.standardProcessMatch(match, Parser) return MatchGroupInputUtil.readOpponent(match, opponentIndex, Parser.OPPONENT_CONFIG) end) - local games = Parser.extractMaps(match, opponents) + local games = Parser.extractMaps(match, opponents, mapProps) match.bestof = Parser.getBestOf(match.bestof, games) games = Parser.removeUnsetMaps and Parser.removeUnsetMaps(games) or games - match.links = MatchGroupInputUtil.getLinks(match) + match.links = Parser.getLinks and Parser.getLinks(match, games) or MatchGroupInputUtil.getLinks(match) local autoScoreFunction = MatchGroupInputUtil.canUseAutoScore(match, games) and Parser.calculateMatchScore(games) diff --git a/components/match2/wikis/dota2/match_group_input_custom.lua b/components/match2/wikis/dota2/match_group_input_custom.lua index 6bb7c98e0f6..cb35a12d073 100644 --- a/components/match2/wikis/dota2/match_group_input_custom.lua +++ b/components/match2/wikis/dota2/match_group_input_custom.lua @@ -13,7 +13,6 @@ local Logic = require('Module:Logic') local Lua = require('Module:Lua') local Operator = require('Module:Operator') local String = require('Module:StringUtils') -local Streams = require('Module:Links/Stream') local Table = require('Module:Table') local Variables = require('Module:Variables') @@ -23,20 +22,20 @@ local MatchGroupUtil = Lua.import('Module:MatchGroup/Util') local OpponentLibraries = Lua.import('Module:OpponentLibraries') local Opponent = OpponentLibraries.Opponent -local OPPONENT_CONFIG = { +local CustomMatchGroupInput = {} +local MatchFunctions = {} +local MapFunctions = {} + +local DUMMY_MAP = 'default' +MatchFunctions.OPPONENT_CONFIG = { resolveRedirect = true, pagifyTeamNames = false, maxNumPlayers = 15, } -local DEFAULT_MODE = 'team' -local DUMMY_MAP = 'default' - -local MatchFunctions = {} -local MapFunctions = {} +MatchFunctions.DEFAULT_MODE = 'team' +MatchFunctions.getBestOf = MatchGroupInputUtil.getBestOf -local CustomMatchGroupInput = {} - ----@class Dota2MatchParserInterface +---@class Dota2MapParserInterface ---@field getMap fun(mapInput: table): table ---@field getLength fun(map: table): string? ---@field getSide fun(map: table, opponentIndex: integer): string? @@ -61,76 +60,33 @@ function CustomMatchGroupInput.processMatch(match, options) end end - local MatchParser + local MapParser if options.isMatchPage then - MatchParser = Lua.import('Module:MatchGroup/Input/Custom/MatchPage') + MapParser = Lua.import('Module:MatchGroup/Input/Custom/MatchPage') else - MatchParser = Lua.import('Module:MatchGroup/Input/Custom/Normal') + MapParser = Lua.import('Module:MatchGroup/Input/Custom/Normal') end - return CustomMatchGroupInput.processMatchWithoutStandalone(MatchParser, match) + return CustomMatchGroupInput.processMatchWithoutStandalone(MapParser, match) end ----@param MatchParser Dota2MatchParserInterface +---@param MapParser Dota2MapParserInterface ---@param match table ---@return table -function CustomMatchGroupInput.processMatchWithoutStandalone(MatchParser, match) - local finishedInput = match.finished --[[@as string?]] - local winnerInput = match.winner --[[@as string?]] - Table.mergeInto(match, MatchGroupInputUtil.readDate(match.date)) - - local opponents = Array.mapIndexes(function(opponentIndex) - return MatchGroupInputUtil.readOpponent(match, opponentIndex, OPPONENT_CONFIG) - end) - local games = MatchFunctions.extractMaps(MatchParser, match, opponents) - match.bestof = MatchGroupInputUtil.getBestOf(match.bestof, games) - match.links = MatchFunctions.getLinks(match, games, opponents) - - local autoScoreFunction = MatchGroupInputUtil.canUseAutoScore(match, games) - and MatchFunctions.calculateMatchScore(games) - or nil - - Array.forEach(opponents, function(opponent, opponentIndex) - opponent.score, opponent.status = MatchGroupInputUtil.computeOpponentScore({ - walkover = match.walkover, - winner = match.winner, - opponentIndex = opponentIndex, - score = opponent.score, - }, autoScoreFunction) - end) - - match.finished = MatchGroupInputUtil.matchIsFinished(match, opponents) - - if match.finished then - match.resulttype = MatchGroupInputUtil.getResultType(winnerInput, finishedInput, opponents) - match.walkover = MatchGroupInputUtil.getWalkover(match.resulttype, opponents) - match.winner = MatchGroupInputUtil.getWinner(match.resulttype, winnerInput, opponents) - Array.forEach(opponents, function(opponent, opponentIndex) - opponent.placement = MatchGroupInputUtil.placementFromWinner(match.resulttype, match.winner, opponentIndex) - end) - end - - match.mode = Logic.emptyOr(match.mode, Variables.varDefault('tournament_mode'), DEFAULT_MODE) - Table.mergeInto(match, MatchGroupInputUtil.getTournamentContext(match)) - - match.stream = Streams.processStreams(match) - - match.games = games - match.opponents = opponents - - match.extradata = MatchFunctions.getExtraData(match) - - return match +function CustomMatchGroupInput.processMatchWithoutStandalone(MapParser, match) + local parsedMatch = MatchGroupInputUtil.standardProcessMatch(match, MatchFunctions, MapParser) + parsedMatch.links.headtohead = MatchFunctions.getHeadToHeadLink(match, parsedMatch.opponents) + return parsedMatch end ----@param MatchParser Dota2MatchParserInterface ---@param match table ---@param opponents table[] +---@param MapParser Dota2MapParserInterface ---@return table[] -function MatchFunctions.extractMaps(MatchParser, match, opponents) +function MatchFunctions.extractMaps(match, opponents, MapParser) local maps = {} for key, mapInput, mapIndex in Table.iter.pairsByPrefix(match, 'map', {requireIndex = true}) do - local map = MatchParser.getMap(mapInput) + local map = MapParser.getMap(mapInput) local finishedInput = map.finished --[[@as string?]] local winnerInput = map.winner --[[@as string?]] @@ -138,11 +94,11 @@ function MatchFunctions.extractMaps(MatchParser, match, opponents) map.map = nil end - map.length = MatchParser.getLength(map) + map.length = MapParser.getLength(map) map.vod = map.vod or String.nilIfEmpty(match['vodgame' .. mapIndex]) map.publisherid = map.matchid or String.nilIfEmpty(match['matchid' .. mapIndex]) - map.participants = MapFunctions.getParticipants(MatchParser, map, opponents) - map.extradata = MapFunctions.getExtraData(MatchParser, map, #opponents) + map.participants = MapFunctions.getParticipants(MapParser, map, opponents) + map.extradata = MapFunctions.getExtraData(MapParser, map, #opponents) map.finished = MatchGroupInputUtil.mapIsFinished(map) local opponentInfo = Array.map(opponents, function(_, opponentIndex) @@ -179,9 +135,8 @@ end ---@param match table ---@param games table[] ----@param opponents table[] ---@return table -function MatchFunctions.getLinks(match, games, opponents) +function MatchFunctions.getLinks(match, games) ---@type table local links = MatchGroupInputUtil.getLinks(match) links.stratz = {} @@ -197,17 +152,22 @@ function MatchFunctions.getLinks(match, games, opponents) end ) + return links +end + +---@param match table +---@param opponents table[] +---@return string? +function MatchFunctions.getHeadToHeadLink(match, opponents) local isTeamGame = Array.all(opponents, function(opponent) return opponent.type == Opponent.team end) if Logic.readBool(Logic.emptyOr(match.headtohead, Variables.varDefault('headtohead'))) and isTeamGame then local team1, team2 = string.gsub(opponents[1].name, ' ', '_'), string.gsub(opponents[2].name, ' ', '_') - links.headtohead = tostring(mw.uri.fullUrl('Special:RunQuery/Match_history')) .. + return tostring(mw.uri.fullUrl('Special:RunQuery/Match_history')) .. '?pfRunQueryFormName=Match+history&Head_to_head_query%5Bplayer%5D=' .. team1 .. '&Head_to_head_query%5Bopponent%5D=' .. team2 .. '&wpRunQuery=Run+query' end - - return links end ---@param match table @@ -219,11 +179,11 @@ function MatchFunctions.getExtraData(match) } end ----@param MatchParser Dota2MatchParserInterface +---@param MapParser Dota2MapParserInterface ---@param map table ---@param opponentCount integer ---@return table -function MapFunctions.getExtraData(MatchParser, map, opponentCount) +function MapFunctions.getExtraData(MapParser, map, opponentCount) local extraData = { publisherid = tonumber(map.publisherid), comment = map.comment, @@ -236,14 +196,14 @@ function MapFunctions.getExtraData(MatchParser, map, opponentCount) for opponentIndex = 1, opponentCount do local opponentData = { - objectives = MatchParser.getObjectives(map, opponentIndex), - side = MatchParser.getSide(map, opponentIndex), + objectives = MapParser.getObjectives(map, opponentIndex), + side = MapParser.getSide(map, opponentIndex), } opponentData = Table.merge(opponentData, - Table.map(MatchParser.getHeroPicks(map, opponentIndex) or {}, function(idx, hero) + Table.map(MapParser.getHeroPicks(map, opponentIndex) or {}, function(idx, hero) return 'hero' .. idx, getCharacterName(hero) end), - Table.map(MatchParser.getHeroBans(map, opponentIndex) or {}, function(idx, hero) + Table.map(MapParser.getHeroBans(map, opponentIndex) or {}, function(idx, hero) return 'ban' .. idx, getCharacterName(hero) end) ) @@ -253,7 +213,7 @@ function MapFunctions.getExtraData(MatchParser, map, opponentCount) end)) end - extraData.vetophase = MatchParser.getVetoPhase(map) + extraData.vetophase = MapParser.getVetoPhase(map) Array.forEach(extraData.vetophase or {}, function(veto) veto.character = getCharacterName(veto.character) end) @@ -262,16 +222,16 @@ function MapFunctions.getExtraData(MatchParser, map, opponentCount) end -- Parse participant information ----@param MatchParser Dota2MatchParserInterface +---@param MapParser Dota2MapParserInterface ---@param map table ---@param opponents table[] ---@return table -function MapFunctions.getParticipants(MatchParser, map, opponents) +function MapFunctions.getParticipants(MapParser, map, opponents) local allParticipants = {} local getCharacterName = FnUtil.curry(MatchGroupInputUtil.getCharacterName, HeroNames) Array.forEach(opponents, function(opponent, opponentIndex) - local participantList = MatchParser.getParticipants(map, opponentIndex) or {} + local participantList = MapParser.getParticipants(map, opponentIndex) or {} local participants, unattachedParticipants = MatchGroupInputUtil.parseParticipants( opponent.match2players, participantList, diff --git a/components/match2/wikis/leagueoflegends/match_group_input_custom.lua b/components/match2/wikis/leagueoflegends/match_group_input_custom.lua index 1f4e864e85f..0349e735931 100644 --- a/components/match2/wikis/leagueoflegends/match_group_input_custom.lua +++ b/components/match2/wikis/leagueoflegends/match_group_input_custom.lua @@ -9,30 +9,27 @@ local Array = require('Module:Array') local FnUtil = require('Module:FnUtil') local HeroNames = mw.loadData('Module:ChampionNames') -local Logic = require('Module:Logic') local Lua = require('Module:Lua') local Operator = require('Module:Operator') local String = require('Module:StringUtils') -local Streams = require('Module:Links/Stream') local Table = require('Module:Table') -local Variables = require('Module:Variables') local MatchGroupInputUtil = Lua.import('Module:MatchGroup/Input/Util') local MatchGroupUtil = Lua.import('Module:MatchGroup/Util') -local OPPONENT_CONFIG = { +local CustomMatchGroupInput = {} +local MatchFunctions = {} +local MapFunctions = {} + +MatchFunctions.OPPONENT_CONFIG = { resolveRedirect = true, pagifyTeamNames = false, maxNumPlayers = 15, } -local DEFAULT_MODE = 'team' - -local MatchFunctions = {} -local MapFunctions = {} - -local CustomMatchGroupInput = {} +MatchFunctions.DEFAULT_MODE = 'team' +MatchFunctions.getBestOf = MatchGroupInputUtil.getBestOf ----@class LeagueOfLegendsMatchParserInterface +---@class LeagueOfLegendsMapParserInterface ---@field getMap fun(mapInput: table): table ---@field getLength fun(map: table): string? ---@field getSide fun(map: table, opponentIndex: integer): string? @@ -57,83 +54,38 @@ function CustomMatchGroupInput.processMatch(match, options) end end - local MatchParser + local MapParser if options.isMatchPage then - MatchParser = Lua.import('Module:MatchGroup/Input/Custom/MatchPage') + MapParser = Lua.import('Module:MatchGroup/Input/Custom/MatchPage') else - MatchParser = Lua.import('Module:MatchGroup/Input/Custom/Normal') + MapParser = Lua.import('Module:MatchGroup/Input/Custom/Normal') end - return CustomMatchGroupInput.processMatchWithoutStandalone(MatchParser, match) + return CustomMatchGroupInput.processMatchWithoutStandalone(MapParser, match) end ----@param MatchParser LeagueOfLegendsMatchParserInterface +---@param MapParser LeagueOfLegendsMapParserInterface ---@param match table ---@return table -function CustomMatchGroupInput.processMatchWithoutStandalone(MatchParser, match) - local finishedInput = match.finished --[[@as string?]] - local winnerInput = match.winner --[[@as string?]] - Table.mergeInto(match, MatchGroupInputUtil.readDate(match.date)) - - local opponents = Array.mapIndexes(function(opponentIndex) - return MatchGroupInputUtil.readOpponent(match, opponentIndex, OPPONENT_CONFIG) - end) - local games = MatchFunctions.extractMaps(MatchParser, match, opponents) - match.bestof = MatchGroupInputUtil.getBestOf(match.bestof, games) - match.links = MatchGroupInputUtil.getLinks(match) - - local autoScoreFunction = MatchGroupInputUtil.canUseAutoScore(match, games) - and MatchFunctions.calculateMatchScore(games) - or nil - - Array.forEach(opponents, function(opponent, opponentIndex) - opponent.score, opponent.status = MatchGroupInputUtil.computeOpponentScore({ - walkover = match.walkover, - winner = match.winner, - opponentIndex = opponentIndex, - score = opponent.score, - }, autoScoreFunction) - end) - - match.finished = MatchGroupInputUtil.matchIsFinished(match, opponents) - - if match.finished then - match.resulttype = MatchGroupInputUtil.getResultType(winnerInput, finishedInput, opponents) - match.walkover = MatchGroupInputUtil.getWalkover(match.resulttype, opponents) - match.winner = MatchGroupInputUtil.getWinner(match.resulttype, winnerInput, opponents) - Array.forEach(opponents, function(opponent, opponentIndex) - opponent.placement = MatchGroupInputUtil.placementFromWinner(match.resulttype, match.winner, opponentIndex) - end) - end - - match.mode = Logic.emptyOr(match.mode, Variables.varDefault('tournament_mode'), DEFAULT_MODE) - Table.mergeInto(match, MatchGroupInputUtil.getTournamentContext(match)) - - match.stream = Streams.processStreams(match) - - match.games = games - match.opponents = opponents - - match.extradata = MatchFunctions.getExtraData(match) - - return match +function CustomMatchGroupInput.processMatchWithoutStandalone(MapParser, match) + return MatchGroupInputUtil.standardProcessMatch(match, MatchFunctions, MapParser) end ----@param MatchParser LeagueOfLegendsMatchParserInterface ---@param match table ---@param opponents table[] +---@param MapParser LeagueOfLegendsMapParserInterface ---@return table[] -function MatchFunctions.extractMaps(MatchParser, match, opponents) +function MatchFunctions.extractMaps(match, opponents, MapParser) local maps = {} for key, mapInput, mapIndex in Table.iter.pairsByPrefix(match, 'map', {requireIndex = true}) do - local map = MatchParser.getMap(mapInput) + local map = MapParser.getMap(mapInput) local finishedInput = map.finished --[[@as string?]] local winnerInput = map.winner --[[@as string?]] - map.length = MatchParser.getLength(map) + map.length = MapParser.getLength(map) map.vod = map.vod or String.nilIfEmpty(match['vodgame' .. mapIndex]) - map.participants = MapFunctions.getParticipants(MatchParser, map, opponents) - map.extradata = MapFunctions.getExtraData(MatchParser, map, #opponents) + map.participants = MapFunctions.getParticipants(MapParser, map, opponents) + map.extradata = MapFunctions.getExtraData(MapParser, map, #opponents) map.finished = MatchGroupInputUtil.mapIsFinished(map) local opponentInfo = Array.map(opponents, function(_, opponentIndex) @@ -176,11 +128,11 @@ function MatchFunctions.getExtraData(match) } end ----@param MatchParser LeagueOfLegendsMatchParserInterface +---@param MapParser LeagueOfLegendsMapParserInterface ---@param map table ---@param opponentCount integer ---@return table -function MapFunctions.getExtraData(MatchParser, map, opponentCount) +function MapFunctions.getExtraData(MapParser, map, opponentCount) local extraData = { comment = map.comment, } @@ -192,14 +144,14 @@ function MapFunctions.getExtraData(MatchParser, map, opponentCount) for opponentIndex = 1, opponentCount do local opponentData = { - objectives = MatchParser.getObjectives(map, opponentIndex), - side = MatchParser.getSide(map, opponentIndex), + objectives = MapParser.getObjectives(map, opponentIndex), + side = MapParser.getSide(map, opponentIndex), } opponentData = Table.merge(opponentData, - Table.map(MatchParser.getHeroPicks(map, opponentIndex) or {}, function(idx, hero) + Table.map(MapParser.getHeroPicks(map, opponentIndex) or {}, function(idx, hero) return 'champion' .. idx, getCharacterName(hero) end), - Table.map(MatchParser.getHeroBans(map, opponentIndex) or {}, function(idx, hero) + Table.map(MapParser.getHeroBans(map, opponentIndex) or {}, function(idx, hero) return 'ban' .. idx, getCharacterName(hero) end) ) @@ -209,7 +161,7 @@ function MapFunctions.getExtraData(MatchParser, map, opponentCount) end)) end - extraData.vetophase = MatchParser.getVetoPhase(map) + extraData.vetophase = MapParser.getVetoPhase(map) Array.forEach(extraData.vetophase or {}, function(veto) veto.character = getCharacterName(veto.character) end) @@ -218,16 +170,16 @@ function MapFunctions.getExtraData(MatchParser, map, opponentCount) end -- Parse participant information ----@param MatchParser LeagueOfLegendsMatchParserInterface +---@param MapParser LeagueOfLegendsMapParserInterface ---@param map table ---@param opponents table[] ---@return table -function MapFunctions.getParticipants(MatchParser, map, opponents) +function MapFunctions.getParticipants(MapParser, map, opponents) local allParticipants = {} local getCharacterName = FnUtil.curry(MatchGroupInputUtil.getCharacterName, HeroNames) Array.forEach(opponents, function(opponent, opponentIndex) - local participantList = MatchParser.getParticipants(map, opponentIndex) or {} + local participantList = MapParser.getParticipants(map, opponentIndex) or {} local participants, unattachedParticipants = MatchGroupInputUtil.parseParticipants( opponent.match2players, participantList,