BryghtShadow (talk | contribs) mNo edit summary |
BryghtShadow (talk | contribs) No edit summary |
||
(19 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | -- <nowiki> |
||
local p = {} |
local p = {} |
||
+ | local h = {} |
||
local cargo = require('Module:CargoUtil') |
local cargo = require('Module:CargoUtil') |
||
+ | local yesno = require('Module:Yesno') |
||
local dataModel = require("Module:Data/Model") |
local dataModel = require("Module:Data/Model") |
||
local util_text = require('Module:TextUtil') |
local util_text = require('Module:TextUtil') |
||
Line 7: | Line 10: | ||
local trim = util_text.trim |
local trim = util_text.trim |
||
+ | local langs = {'english', 'japanese'} |
||
− | function getTitlePath() |
||
+ | local locPrefixes = { |
||
+ | ['Ability'] = true, |
||
+ | ['Artifact'] = true, |
||
+ | ['ConceptCard'] = true, |
||
+ | ['Item'] = true, |
||
+ | ['Job'] = true, |
||
+ | ['Skill'] = true, |
||
+ | ['Unit'] = true, |
||
+ | } |
||
+ | function h.getEntityType(args) |
||
+ | local name = args.name or mw.title.getCurrentTitle().prefixedText |
||
+ | return name:match('Data:Game/MasterParam/([^/]+)/.+') |
||
+ | end |
||
+ | |||
+ | function p.displayLocs(data) |
||
+ | local locs = data.loc |
||
+ | if not locs then return end |
||
+ | local entityType = h.getEntityType(data) |
||
+ | if not entityType or not locPrefixes[entityType] then return end |
||
+ | |||
+ | local definitions = mw.loadData('Module:CargoDeclare/'..entityType..'Loc') |
||
+ | |||
+ | -- HOTFIX: "otherdesc" |
||
+ | local temp = {} |
||
+ | for param, obj in pairs(locs) do |
||
+ | if param == 'otherdesc' then |
||
+ | param = 'desc_ot' |
||
+ | end |
||
+ | for lang, value in pairs(obj) do |
||
+ | temp[param] = temp[param] or {} |
||
+ | temp[param][lang] = value |
||
+ | end |
||
+ | end |
||
+ | locs = temp |
||
+ | |||
+ | -- Build localization wikitable |
||
+ | local wikitable = mw.html.create('table'):addClass('wikitable') |
||
+ | local tr = wikitable:tag('tr') |
||
+ | tr:tag('th'):wikitext('param') |
||
+ | for _, lang in ipairs(langs) do |
||
+ | tr:tag('th'):wikitext(lang) |
||
+ | end |
||
+ | for _, definition in ipairs(definitions) do |
||
+ | local field = definition.field |
||
+ | if field and locs[field] then |
||
+ | tr = wikitable:tag('tr') |
||
+ | tr:tag('th'):wikitext(field) |
||
+ | for _, lang in ipairs(langs) do |
||
+ | tr:tag('td'):wikitext(locs[field][lang]) |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | return tostring(wikitable) |
||
+ | end |
||
+ | |||
+ | function p.storeLocs(nocargo, data) |
||
+ | local locs = data.loc |
||
+ | if not locs then return end |
||
+ | local entityType = h.getEntityType(data) |
||
+ | if not entityType or not locPrefixes[entityType] then return end |
||
+ | |||
+ | local iname = (data.gl or data.jp or {}).iname |
||
+ | local definitions = mw.loadData('Module:CargoDeclare/'..entityType..'Loc') |
||
+ | |||
+ | -- HOTFIX: "otherdesc" |
||
+ | local temp = {} |
||
+ | for param, obj in pairs(locs) do |
||
+ | if param == 'otherdesc' then |
||
+ | param = 'desc_ot' |
||
+ | end |
||
+ | for lang, value in pairs(obj) do |
||
+ | temp[param] = temp[param] or {} |
||
+ | temp[param][lang] = value |
||
+ | end |
||
+ | end |
||
+ | locs = temp |
||
+ | |||
+ | local rows = {} |
||
+ | for _, definition in ipairs(definitions) do |
||
+ | local field = definition.field |
||
+ | if field and locs[field] then |
||
+ | for lang, value in pairs(locs[field]) do |
||
+ | rows[lang] = rows[lang] or { |
||
+ | _table = entityType .. 'Loc', |
||
+ | iname = iname, |
||
+ | lang = lang, |
||
+ | } |
||
+ | rows[lang][field] = value |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | |||
+ | local result = {} |
||
+ | -- Store localization |
||
+ | if not yesno(nocargo) then |
||
+ | for _, row in pairs(rows) do |
||
+ | mw.logObject(row) |
||
+ | result[#result+1] = cargo.store(row) |
||
+ | end |
||
+ | end |
||
+ | return table.concat(result) |
||
+ | end |
||
+ | |||
+ | function h.getTitlePath() |
||
local curTitle = mw.title.getCurrentTitle() |
local curTitle = mw.title.getCurrentTitle() |
||
--if curTitle.prefixedText == "Module:Data" then curTitle = mw.title.new("Game/MasterParam/Unit/UN_V2_LOGI", "Data") end |
--if curTitle.prefixedText == "Module:Data" then curTitle = mw.title.new("Game/MasterParam/Unit/UN_V2_LOGI", "Data") end |
||
Line 17: | Line 124: | ||
return titleNodes |
return titleNodes |
||
end |
end |
||
+ | -- Generates table for data page |
||
+ | function h.insertQueryResult(result, title, tbl) |
||
+ | local fields = {} |
||
+ | local found = {} |
||
+ | local count = 0 |
||
+ | local hideCols = true |
||
+ | for i, row in pairs(tbl) do |
||
+ | count = count + 1 |
||
+ | for col in ipairs(row) do |
||
+ | if found[col] == nil then |
||
+ | table.insert(fields, col) |
||
+ | found[col] = true |
||
+ | end |
||
+ | end |
||
+ | for col in pairs(row) do |
||
+ | if found[col] == nil then |
||
+ | table.insert(fields, col) |
||
+ | found[col] = true |
||
+ | hideCols = false |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | table.sort(fields, function(a, b) return a == "server" or a == "lang" or (b ~= "server" and b ~= "lang" and (a or '') < (b or '')) end) |
||
+ | if count == 0 then return nil end |
||
+ | if title ~= nil then table.insert(result, "==="..title.."===\n") end |
||
+ | table.insert(result, '{| class="wikitable"') |
||
+ | for i, col in ipairs(fields) do |
||
+ | table.insert(result, "\n|-") |
||
+ | if not hideCols then |
||
+ | table.insert(result, "\n! ") |
||
+ | table.insert(result, col) |
||
+ | end |
||
+ | |||
+ | -- Merge matching rows |
||
+ | local allSame = true |
||
+ | local testVal = tbl[next(tbl)][col] |
||
+ | for j, row in pairs(tbl) do |
||
+ | if type(testVal) == 'table' and type(row[col]) == 'table' then |
||
+ | for k, v in pairs(testVal) do if v ~= row[col][k] then allSame = false end end |
||
+ | for k, v in pairs(row[col]) do if v ~= testVal[k] then allSame = false end end |
||
+ | elseif row[col] ~= testVal then allSame = false end |
||
+ | end |
||
+ | |||
+ | local function writeVal(val) |
||
+ | if type(val) == "table" then |
||
+ | table.insert(result, "\n") |
||
+ | h.insertQueryResult(result, nil, {val}) |
||
+ | else |
||
+ | table.insert(result, tostring(val or '')) |
||
+ | end |
||
+ | end |
||
+ | |||
+ | if allSame then |
||
+ | table.insert(result, '\n| colspan="'..count..'" | ') |
||
+ | writeVal(testVal) |
||
+ | else |
||
+ | for j, row in pairs(tbl) do |
||
+ | table.insert(result, "\n| ") |
||
+ | writeVal(row[col]) |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | table.insert(result, "\n|}\n") |
||
+ | end |
||
+ | p.insertQueryResult = h.insertQueryResult |
||
-- Will only actually perform the declares on the CargoTable template pages. |
-- Will only actually perform the declares on the CargoTable template pages. |
||
function p.init(frame) |
function p.init(frame) |
||
− | + | local args = require('Module:Arguments').getArgs(frame, {parentFirst=true}) |
|
− | + | return p._init(args) |
|
end |
end |
||
function p._init(args) |
function p._init(args) |
||
Line 42: | Line 214: | ||
local curTitle = mw.title.getCurrentTitle() |
local curTitle = mw.title.getCurrentTitle() |
||
− | + | if args[1] then |
|
− | + | curTitle = mw.title.new(args[1]) |
|
− | + | end |
|
if curTitle.basePageTitle.prefixedText == "Template:CargoTable" then |
if curTitle.basePageTitle.prefixedText == "Template:CargoTable" then |
||
local statement = declareStatements[curTitle.subpageText] |
local statement = declareStatements[curTitle.subpageText] |
||
if statement == nil then return "Invalid table "..curTitle.subpageText end |
if statement == nil then return "Invalid table "..curTitle.subpageText end |
||
− | local |
+ | local tbl = {'{{#cargo_declare:', '}}'} |
− | + | for k,v in pairs(statement) do |
|
+ | if k ~= 1 then |
||
− | return mw.getCurrentFrame():extensionTag('pre', tostring(declare)) |
||
+ | tbl[#tbl+1] = '| ' .. k..' = '..v |
||
+ | end |
||
+ | end |
||
+ | table.sort(tbl) |
||
+ | local declare = table.concat(tbl, '\n') |
||
+ | if yesno(args.debug) then |
||
+ | return tostring(mw.html.create('pre'):wikitext(declare)) |
||
else |
else |
||
− | + | mw.log(declare) |
|
+ | return mw.getCurrentFrame():callParserFunction('#cargo_declare', statement) |
||
− | end |
||
+ | end |
||
end |
end |
||
if mw.getCurrentFrame():getParent() == nil then |
if mw.getCurrentFrame():getParent() == nil then |
||
Line 63: | Line 243: | ||
-- Called from Data pages |
-- Called from Data pages |
||
function p.insert(frame) |
function p.insert(frame) |
||
− | + | local args = require('Module:Arguments').getArgs(frame, {parentFirst = true}) |
|
− | + | return p._insert(args) |
|
end |
end |
||
function p._insert(args) |
function p._insert(args) |
||
+ | local nocargo = args.nocargo |
||
local curNode = {nodes = {Game = dataModel}} |
local curNode = {nodes = {Game = dataModel}} |
||
− | local titlePath = getTitlePath() |
+ | local titlePath = h.getTitlePath() |
for i, pathItem in ipairs(titlePath) do |
for i, pathItem in ipairs(titlePath) do |
||
if curNode == nil then return nil end |
if curNode == nil then return nil end |
||
Line 77: | Line 258: | ||
if curNode.model == nil then return nil end |
if curNode.model == nil then return nil end |
||
− | |||
-- Now that we know this is a valid page |
-- Now that we know this is a valid page |
||
local result = {} |
local result = {} |
||
+ | |||
− | |||
+ | if next(curNode.model) ~= nil then table.insert(result, "==Tables==\nThe following tables have these rows defined by this data entry.\n") end |
||
− | -- Generates table for data page |
||
+ | |||
− | local insertQueryResult |
||
+ | -- Decode JSON |
||
− | function insertQueryResult(title, tbl) |
||
− | + | local jsonSets = {} |
|
− | + | for k, v in pairs(args) do |
|
+ | if type(v) == 'string' then |
||
− | local count = 0 |
||
+ | v = mw.text.decode(mw.text.unstripNoWiki(v)) |
||
− | local hideCols = true |
||
+ | local success, result = pcall(mw.text.jsonDecode, v) |
||
− | for i, row in pairs(tbl) do |
||
+ | if success then |
||
− | count = count + 1 |
||
+ | v = result |
||
− | for col in ipairs(row) do |
||
+ | end |
||
− | if found[col] == nil then |
||
+ | args[k] = v |
||
− | table.insert(fields, col) |
||
+ | end |
||
− | found[col] = true |
||
− | + | end |
|
+ | local content_sha256s = {} |
||
− | end |
||
+ | local suffix = '_sha256' |
||
− | for col in pairs(row) do |
||
+ | for server, json in pairs(args) do |
||
− | if found[col] == nil then |
||
− | + | if server == 'gl' or server == 'jp' or server == 'loc' then |
|
− | + | jsonSets[server] = json |
|
+ | elseif string.sub(server, -string.len(suffix)) == suffix then |
||
− | hideCols = false |
||
− | + | -- TODO: Store this in a cargo table somewhere. |
|
+ | content_sha256s[string.sub(server, 1, -string.len(suffix))] = json |
||
− | end |
||
end |
end |
||
− | table.sort(fields, function(a, b) return a == "server" or a == "lang" or (b ~= "server" and b ~= "lang" and (a or '') < (b or '')) end) |
||
− | if count == 0 then return nil end |
||
− | if title ~= nil then table.insert(result, "=="..title.."==\n") end |
||
− | table.insert(result, '{| class="wikitable"') |
||
− | for i, col in ipairs(fields) do |
||
− | table.insert(result, "\n|-") |
||
− | if not hideCols then |
||
− | table.insert(result, "\n! ") |
||
− | table.insert(result, col) |
||
− | end |
||
− | |||
− | -- Merge matching rows |
||
− | local allSame = true |
||
− | local testVal = tbl[next(tbl)][col] |
||
− | for j, row in pairs(tbl) do |
||
− | if type(testVal) == 'table' and type(row[col]) == 'table' then |
||
− | for k, v in pairs(testVal) do if v ~= row[col][k] then allSame = false end end |
||
− | for k, v in pairs(row[col]) do if v ~= testVal[k] then allSame = false end end |
||
− | elseif row[col] ~= testVal then allSame = false end |
||
− | end |
||
− | |||
− | local function writeVal(val) |
||
− | if type(val) == "table" then |
||
− | table.insert(result, "\n") |
||
− | insertQueryResult(nil, {val}) |
||
− | else table.insert(result, tostring(val or '')) end |
||
− | end |
||
− | |||
− | if allSame then |
||
− | table.insert(result, '\n| colspan="'..count..'" | ') |
||
− | writeVal(testVal) |
||
− | else |
||
− | for j, row in pairs(tbl) do |
||
− | table.insert(result, "\n| ") |
||
− | writeVal(row[col]) |
||
− | end |
||
− | end |
||
− | end |
||
− | table.insert(result, "\n|}\n") |
||
end |
end |
||
− | |||
− | if next(curNode.model) ~= nil then table.insert(result, "=Tables=\nThe following tables have these rows defined by this data entry.\n") end |
||
− | |||
− | -- Decode JSON |
||
− | local jsonDecode = mw.text.jsonDecode |
||
− | local jsonSets = {} |
||
− | for server, json in pairs(args) do jsonSets[server] = jsonDecode(json) end |
||
-- Convert Functions |
-- Convert Functions |
||
Line 167: | Line 301: | ||
-- Do loc first |
-- Do loc first |
||
+ | result[#result+1] = p.storeLocs(nocargo, args) |
||
+ | result[#result+1] = p.displayLocs(args) |
||
+ | |||
local locSets = jsonSets.loc or {} |
local locSets = jsonSets.loc or {} |
||
jsonSets.loc = nil |
jsonSets.loc = nil |
||
local expected = 0 |
local expected = 0 |
||
− | table.insert(result, mw.getCurrentFrame():expandTemplate{ title = "CargoTable/Loc" }) |
+ | table.insert(result, '\n'..mw.getCurrentFrame():expandTemplate{ title = "CargoTable/Loc" }) |
+ | |||
for param, json in pairs(locSets) do |
for param, json in pairs(locSets) do |
||
− | + | if type(json) == "table" then |
|
− | + | for lang, value in pairs(json) do |
|
− | + | table.insert(result, cargo.store{ |
|
− | + | _table = 'Loc', |
|
− | + | lang = lang, |
|
− | + | param = param, |
|
− | + | value = value, |
|
− | + | }) |
|
+ | expected = expected + 1 |
||
+ | end |
||
end |
end |
||
end |
end |
||
-- Query loc table |
-- Query loc table |
||
local rows = cargo.query{ |
local rows = cargo.query{ |
||
− | + | tables = 'Loc', |
|
− | + | fields = 'lang, param, value', |
|
− | + | where = where, |
|
− | + | orderBy = 'lang' |
|
} |
} |
||
− | + | -- Check if expected row count matches actual row count. |
|
local actual = #rows |
local actual = #rows |
||
if actual ~= expected then |
if actual ~= expected then |
||
Line 199: | Line 339: | ||
local queryResult = {} |
local queryResult = {} |
||
for i, row in ipairs(rows) do |
for i, row in ipairs(rows) do |
||
+ | if row.param == 'name' then |
||
+ | local pagename = string.gsub(row.value, "[%[%]]", { |
||
+ | ["["] = "【", |
||
+ | ["]"] = "】", |
||
+ | }) |
||
+ | if pagename ~= row.value then |
||
+ | row.value = '[[' .. pagename .. '|' .. row.value .. ']]' |
||
+ | else |
||
+ | row.value = '[[' .. row.value .. ']]' |
||
+ | end |
||
+ | end |
||
queryResult[i] = row |
queryResult[i] = row |
||
end |
end |
||
− | insertQueryResult(tbl, queryResult) |
+ | h.insertQueryResult(result, tbl, queryResult) |
local iname |
local iname |
||
for server, json in pairs(jsonSets) do |
for server, json in pairs(jsonSets) do |
||
− | + | if not iname and json.iname then |
|
− | + | iname = json.iname |
|
− | + | end |
|
− | + | end |
|
− | + | local actualTitle = table.concat(titlePath, '/', 1, 3) |
|
− | + | mw.logObject(actualTitle, 'actualTitle') |
|
if actualTitle == 'Game/MasterParam/Buff' then |
if actualTitle == 'Game/MasterParam/Buff' then |
||
+ | local definitions = mw.loadData('Module:CargoDeclare/BuffDetail') |
||
for server, json in pairs(jsonSets) do |
for server, json in pairs(jsonSets) do |
||
for i=1,11 do |
for i=1,11 do |
||
− | local |
+ | local values = { |
− | + | _table = 'BuffDetail', |
|
+ | } |
||
− | local tktag = (json['tktag'..i] or '') ~= '' and json['tktag'..i] or nil |
||
− | + | for _, definition in ipairs(definitions) do |
|
− | local |
+ | local field = definition.field |
− | + | if definition.type == 'Integer' then |
|
− | + | values[field] = tonumber(json[field..i]) |
|
− | + | else |
|
− | + | values[field] = json[field..i] |
|
− | + | end |
|
− | + | end |
|
− | + | values.buff_iname = iname |
|
− | + | values.idx = i |
|
− | + | if (values.type or 0) <= 0 then |
|
− | + | mw.logObject(values, "Skipped insert into BuffDetail values") |
|
− | vmax = vmax, |
||
− | vone = vone, |
||
− | } |
||
− | if _type <= 0 then |
||
− | mw.logObject(values, "Skipped insert into BuffDetail values") |
||
else |
else |
||
+ | mw.logObject(values, "#cargo_store") |
||
table.insert(result, cargo.store(values)) |
table.insert(result, cargo.store(values)) |
||
− | -- json['calc'..i] = nil |
||
− | -- json['tktag'..i] = nil |
||
− | -- json['type'..i] = nil |
||
− | -- json['vini'..i] = nil |
||
− | -- json['vmax'..i] = nil |
||
− | -- json['vone'..i] = nil |
||
end |
end |
||
end |
end |
||
Line 270: | Line 412: | ||
end |
end |
||
− | + | -- Query the data |
|
local query = { |
local query = { |
||
− | + | tables = tbl, |
|
− | + | fields = {"server"}, |
|
− | + | where = where, |
|
− | + | orderBy = 'server', |
|
} |
} |
||
for col in pairs(model) do |
for col in pairs(model) do |
||
− | + | table.insert(query.fields, col) |
|
end |
end |
||
local rows = cargo.query(query) |
local rows = cargo.query(query) |
||
Line 310: | Line 452: | ||
queryResult[i] = row |
queryResult[i] = row |
||
end |
end |
||
− | insertQueryResult(tbl, queryResult) |
+ | h.insertQueryResult(result, tbl, queryResult) |
end |
end |
||
− | + | local hasEffects = false |
|
− | + | local jsonEffects = {} |
|
for server, json in pairs(jsonSets) do |
for server, json in pairs(jsonSets) do |
||
− | + | if json.effects then |
|
− | + | hasEffects = true |
|
− | + | jsonEffects[server] = {effects = {}} |
|
− | + | for i,effect in ipairs(json.effects) do |
|
− | + | local values = {} |
|
− | + | values._table = 'ConceptCardEffect' |
|
− | + | values.server = server |
|
− | + | values.cc_iname = iname |
|
− | + | jsonEffects[server].effects[i] = {} |
|
− | + | for k,v in pairs(effect) do |
|
− | + | values[k] = v |
|
− | + | jsonEffects[server].effects[i][k] = v |
|
− | + | effect[k] = nil |
|
+ | end |
||
− | end |
||
− | + | table.insert(result, cargo.store(values)) |
|
− | + | jsonEffects[server].server = server |
|
+ | end |
||
− | end |
||
− | + | -- A table of failed effect insertions. |
|
− | + | local errorEffects = {} |
|
− | + | for i, effect in ipairs(json.effects) do |
|
− | + | local empty = true |
|
− | + | for k, v in pairs(effect) do empty = false end |
|
− | + | if not empty then |
|
− | + | errorEffects[#errorEffects+1] = effect |
|
+ | end |
||
− | end |
||
+ | end |
||
− | end |
||
− | + | json.effects = #errorEffects > 0 and errorEffects or nil |
|
− | + | end |
|
− | + | end |
|
+ | |||
− | |||
− | + | if next(jsonEffects) then |
|
− | + | table.insert(result, '===ConceptCardEffect===\n') |
|
− | + | local toInsert = {} |
|
− | + | for k in pairs(jsonEffects) do table.insert(toInsert, k) end |
|
− | + | table.sort(toInsert) |
|
− | + | for i, k in ipairs(toInsert) do toInsert[i] = jsonEffects[k] end |
|
− | + | h.insertQueryResult(result, nil, toInsert) |
|
− | + | end |
|
local buffDetailRows = cargo.query{ |
local buffDetailRows = cargo.query{ |
||
− | + | tables = 'BuffDetail', |
|
− | + | fields = 'buff_iname, server, idx, calc, type, tktag, vini, vmax, vone', |
|
− | + | where = where, |
|
− | + | orderBy = 'idx' |
|
} |
} |
||
− | insertQueryResult('BuffDetail', buffDetailRows) |
+ | h.insertQueryResult(result, 'BuffDetail', buffDetailRows) |
+ | |||
− | |||
-- Display unused keys here |
-- Display unused keys here |
||
local unused = false |
local unused = false |
||
Line 371: | Line 513: | ||
end end |
end end |
||
if unused then |
if unused then |
||
− | table.insert(result, "==Unused Keys==\nThe following keys were not used by inserted into any table and are thus unused.\n") |
+ | table.insert(result, "===Unused Keys===\nThe following keys were not used by inserted into any table and are thus unused.\n") |
local toInsert = {} |
local toInsert = {} |
||
for k in pairs(jsonSets) do table.insert(toInsert, k) end |
for k in pairs(jsonSets) do table.insert(toInsert, k) end |
||
table.sort(toInsert) |
table.sort(toInsert) |
||
for i, k in ipairs(toInsert) do toInsert[i] = jsonSets[k] end |
for i, k in ipairs(toInsert) do toInsert[i] = jsonSets[k] end |
||
− | insertQueryResult(nil, toInsert) |
+ | h.insertQueryResult(result, nil, toInsert) |
end |
end |
||
Line 382: | Line 524: | ||
-- Handle errors encountered |
-- Handle errors encountered |
||
if errors.cargoStore then |
if errors.cargoStore then |
||
− | + | table.insert(result, '[[Category:Data pages that failed a table insert]]' ) |
|
− | + | end |
|
− | + | if hasEffects then |
|
− | + | table.insert(result, '[[Category:Data pages with effects]]') |
|
− | + | end |
|
return table.concat(result) |
return table.concat(result) |
||
Line 405: | Line 547: | ||
----------- |
----------- |
||
dataModel.query = function(tables, fields, args) |
dataModel.query = function(tables, fields, args) |
||
− | + | local query = args |
|
− | + | query.tables = tables |
|
− | + | query.fields = fields |
|
local result = cargo.query(query) |
local result = cargo.query(query) |
||
local toCast = {} |
local toCast = {} |
||
if type(query.tables) == 'string' then |
if type(query.tables) == 'string' then |
||
− | + | query.tables = split(query.tables, ',', true) |
|
end |
end |
||
if type(query.fields) == 'string' then |
if type(query.fields) == 'string' then |
||
− | + | query.fields = split(query.fields, ',', true) |
|
end |
end |
||
for _, field in ipairs(query.fields) do |
for _, field in ipairs(query.fields) do |
Revision as of 17:55, 8 January 2021
Documentation for this module may be created at Module:Data/doc
-- <nowiki>
local p = {}
local h = {}
local cargo = require('Module:CargoUtil')
local yesno = require('Module:Yesno')
local dataModel = require("Module:Data/Model")
local util_text = require('Module:TextUtil')
local split = util_text.split
local gsplit = util_text.gsplit
local trim = util_text.trim
local langs = {'english', 'japanese'}
local locPrefixes = {
['Ability'] = true,
['Artifact'] = true,
['ConceptCard'] = true,
['Item'] = true,
['Job'] = true,
['Skill'] = true,
['Unit'] = true,
}
function h.getEntityType(args)
local name = args.name or mw.title.getCurrentTitle().prefixedText
return name:match('Data:Game/MasterParam/([^/]+)/.+')
end
function p.displayLocs(data)
local locs = data.loc
if not locs then return end
local entityType = h.getEntityType(data)
if not entityType or not locPrefixes[entityType] then return end
local definitions = mw.loadData('Module:CargoDeclare/'..entityType..'Loc')
-- HOTFIX: "otherdesc"
local temp = {}
for param, obj in pairs(locs) do
if param == 'otherdesc' then
param = 'desc_ot'
end
for lang, value in pairs(obj) do
temp[param] = temp[param] or {}
temp[param][lang] = value
end
end
locs = temp
-- Build localization wikitable
local wikitable = mw.html.create('table'):addClass('wikitable')
local tr = wikitable:tag('tr')
tr:tag('th'):wikitext('param')
for _, lang in ipairs(langs) do
tr:tag('th'):wikitext(lang)
end
for _, definition in ipairs(definitions) do
local field = definition.field
if field and locs[field] then
tr = wikitable:tag('tr')
tr:tag('th'):wikitext(field)
for _, lang in ipairs(langs) do
tr:tag('td'):wikitext(locs[field][lang])
end
end
end
return tostring(wikitable)
end
function p.storeLocs(nocargo, data)
local locs = data.loc
if not locs then return end
local entityType = h.getEntityType(data)
if not entityType or not locPrefixes[entityType] then return end
local iname = (data.gl or data.jp or {}).iname
local definitions = mw.loadData('Module:CargoDeclare/'..entityType..'Loc')
-- HOTFIX: "otherdesc"
local temp = {}
for param, obj in pairs(locs) do
if param == 'otherdesc' then
param = 'desc_ot'
end
for lang, value in pairs(obj) do
temp[param] = temp[param] or {}
temp[param][lang] = value
end
end
locs = temp
local rows = {}
for _, definition in ipairs(definitions) do
local field = definition.field
if field and locs[field] then
for lang, value in pairs(locs[field]) do
rows[lang] = rows[lang] or {
_table = entityType .. 'Loc',
iname = iname,
lang = lang,
}
rows[lang][field] = value
end
end
end
local result = {}
-- Store localization
if not yesno(nocargo) then
for _, row in pairs(rows) do
mw.logObject(row)
result[#result+1] = cargo.store(row)
end
end
return table.concat(result)
end
function h.getTitlePath()
local curTitle = mw.title.getCurrentTitle()
--if curTitle.prefixedText == "Module:Data" then curTitle = mw.title.new("Game/MasterParam/Unit/UN_V2_LOGI", "Data") end
local titleNodes = {curTitle.subpageText}
while curTitle.baseText ~= curTitle.text do
curTitle = curTitle.basePageTitle
table.insert(titleNodes, 1, curTitle.subpageText)
end
return titleNodes
end
-- Generates table for data page
function h.insertQueryResult(result, title, tbl)
local fields = {}
local found = {}
local count = 0
local hideCols = true
for i, row in pairs(tbl) do
count = count + 1
for col in ipairs(row) do
if found[col] == nil then
table.insert(fields, col)
found[col] = true
end
end
for col in pairs(row) do
if found[col] == nil then
table.insert(fields, col)
found[col] = true
hideCols = false
end
end
end
table.sort(fields, function(a, b) return a == "server" or a == "lang" or (b ~= "server" and b ~= "lang" and (a or '') < (b or '')) end)
if count == 0 then return nil end
if title ~= nil then table.insert(result, "==="..title.."===\n") end
table.insert(result, '{| class="wikitable"')
for i, col in ipairs(fields) do
table.insert(result, "\n|-")
if not hideCols then
table.insert(result, "\n! ")
table.insert(result, col)
end
-- Merge matching rows
local allSame = true
local testVal = tbl[next(tbl)][col]
for j, row in pairs(tbl) do
if type(testVal) == 'table' and type(row[col]) == 'table' then
for k, v in pairs(testVal) do if v ~= row[col][k] then allSame = false end end
for k, v in pairs(row[col]) do if v ~= testVal[k] then allSame = false end end
elseif row[col] ~= testVal then allSame = false end
end
local function writeVal(val)
if type(val) == "table" then
table.insert(result, "\n")
h.insertQueryResult(result, nil, {val})
else
table.insert(result, tostring(val or ''))
end
end
if allSame then
table.insert(result, '\n| colspan="'..count..'" | ')
writeVal(testVal)
else
for j, row in pairs(tbl) do
table.insert(result, "\n| ")
writeVal(row[col])
end
end
end
table.insert(result, "\n|}\n")
end
p.insertQueryResult = h.insertQueryResult
-- Will only actually perform the declares on the CargoTable template pages.
function p.init(frame)
local args = require('Module:Arguments').getArgs(frame, {parentFirst=true})
return p._init(args)
end
function p._init(args)
local declareStatements = {}
local recFunc
function recFunc(node)
if node.nodes ~= nil then for k, child in pairs(node.nodes) do recFunc(child) end end
if node.model ~= nil then for tbl, model in pairs(node.model) do
local statement = {"", _table = tbl, server = "String"}
for col, colModel in pairs(model) do
if type(colModel) == "string" then colModel = {colModel} end
local modelType = colModel[1]
if colModel.list ~= nil then modelType = "List ("..colModel.list..") of "..modelType end
statement[col] = modelType
end
declareStatements[tbl] = statement
end end
end
recFunc(dataModel)
local curTitle = mw.title.getCurrentTitle()
if args[1] then
curTitle = mw.title.new(args[1])
end
if curTitle.basePageTitle.prefixedText == "Template:CargoTable" then
local statement = declareStatements[curTitle.subpageText]
if statement == nil then return "Invalid table "..curTitle.subpageText end
local tbl = {'{{#cargo_declare:', '}}'}
for k,v in pairs(statement) do
if k ~= 1 then
tbl[#tbl+1] = '| ' .. k..' = '..v
end
end
table.sort(tbl)
local declare = table.concat(tbl, '\n')
if yesno(args.debug) then
return tostring(mw.html.create('pre'):wikitext(declare))
else
mw.log(declare)
return mw.getCurrentFrame():callParserFunction('#cargo_declare', statement)
end
end
if mw.getCurrentFrame():getParent() == nil then
return nil
end
return "asdf"
end
-- Called from Data pages
function p.insert(frame)
local args = require('Module:Arguments').getArgs(frame, {parentFirst = true})
return p._insert(args)
end
function p._insert(args)
local nocargo = args.nocargo
local curNode = {nodes = {Game = dataModel}}
local titlePath = h.getTitlePath()
for i, pathItem in ipairs(titlePath) do
if curNode == nil then return nil end
if i == #titlePath then break end
if curNode.nodes == nil then return nil end
curNode = curNode.nodes[pathItem]
end
if curNode.model == nil then return nil end
-- Now that we know this is a valid page
local result = {}
if next(curNode.model) ~= nil then table.insert(result, "==Tables==\nThe following tables have these rows defined by this data entry.\n") end
-- Decode JSON
local jsonSets = {}
for k, v in pairs(args) do
if type(v) == 'string' then
v = mw.text.decode(mw.text.unstripNoWiki(v))
local success, result = pcall(mw.text.jsonDecode, v)
if success then
v = result
end
args[k] = v
end
end
local content_sha256s = {}
local suffix = '_sha256'
for server, json in pairs(args) do
if server == 'gl' or server == 'jp' or server == 'loc' then
jsonSets[server] = json
elseif string.sub(server, -string.len(suffix)) == suffix then
-- TODO: Store this in a cargo table somewhere.
content_sha256s[string.sub(server, 1, -string.len(suffix))] = json
end
end
-- Convert Functions
local convertFrom = {
table = function(val, model)
if model.list ~= nil then
return table.concat(val, model.list)
end
error("JSON data for "..model[1].." is a table but is not modeled to handle it.")
end,
}
-- Insert Rows
local where = '_pageId='..mw.title.getCurrentTitle().id
local errors = {}
-- Do loc first
result[#result+1] = p.storeLocs(nocargo, args)
result[#result+1] = p.displayLocs(args)
local locSets = jsonSets.loc or {}
jsonSets.loc = nil
local expected = 0
table.insert(result, '\n'..mw.getCurrentFrame():expandTemplate{ title = "CargoTable/Loc" })
for param, json in pairs(locSets) do
if type(json) == "table" then
for lang, value in pairs(json) do
table.insert(result, cargo.store{
_table = 'Loc',
lang = lang,
param = param,
value = value,
})
expected = expected + 1
end
end
end
-- Query loc table
local rows = cargo.query{
tables = 'Loc',
fields = 'lang, param, value',
where = where,
orderBy = 'lang'
}
-- Check if expected row count matches actual row count.
local actual = #rows
if actual ~= expected then
table.insert(result, string.format('Entry count mismatch in table %q (%s expected, got %s)\n', 'Loc', expected, actual))
errors.cargoStore = true
end
-- Generate loc tables from queried data
local queryResult = {}
for i, row in ipairs(rows) do
if row.param == 'name' then
local pagename = string.gsub(row.value, "[%[%]]", {
["["] = "【",
["]"] = "】",
})
if pagename ~= row.value then
row.value = '[[' .. pagename .. '|' .. row.value .. ']]'
else
row.value = '[[' .. row.value .. ']]'
end
end
queryResult[i] = row
end
h.insertQueryResult(result, tbl, queryResult)
local iname
for server, json in pairs(jsonSets) do
if not iname and json.iname then
iname = json.iname
end
end
local actualTitle = table.concat(titlePath, '/', 1, 3)
mw.logObject(actualTitle, 'actualTitle')
if actualTitle == 'Game/MasterParam/Buff' then
local definitions = mw.loadData('Module:CargoDeclare/BuffDetail')
for server, json in pairs(jsonSets) do
for i=1,11 do
local values = {
_table = 'BuffDetail',
}
for _, definition in ipairs(definitions) do
local field = definition.field
if definition.type == 'Integer' then
values[field] = tonumber(json[field..i])
else
values[field] = json[field..i]
end
end
values.buff_iname = iname
values.idx = i
if (values.type or 0) <= 0 then
mw.logObject(values, "Skipped insert into BuffDetail values")
else
mw.logObject(values, "#cargo_store")
table.insert(result, cargo.store(values))
end
end
end
end
-- Now get the data
for tbl, model in pairs(curNode.model) do
table.insert(result, mw.getCurrentFrame():expandTemplate{ title = "CargoTable/"..tbl })
expected = 0
for server, json in pairs(jsonSets) do
local statement = {_table = tbl, server = server}
for col, colModel in pairs(model) do
if type(colModel) == "string" then colModel = {colModel} end
-- Extract value
local jsonVal = json[colModel.from or col]
json[colModel.from or col] = nil
-- Convert datatypes here
local converter = convertFrom[type(jsonVal)]
if converter ~= nil then jsonVal = converter(jsonVal, colModel) end
-- Append to statement
statement[col] = jsonVal
end
mw.logObject(statement, 'statement')
table.insert(result, cargo.store(statement))
expected = expected + 1
end
-- Query the data
local query = {
tables = tbl,
fields = {"server"},
where = where,
orderBy = 'server',
}
for col in pairs(model) do
table.insert(query.fields, col)
end
local rows = cargo.query(query)
local actual = #rows
if actual ~= expected then
table.insert(result, string.format('Entry count mismatch in table %q (%s expected, got %s)\n', tbl, expected, actual))
errors.cargoStore = true
end
-- Generate tables from queried data
queryResult = {}
for i, row in ipairs(rows) do
for col, val in pairs(row) do
if type(model[col]) == "table" then
if model[col].list ~= nil then
val = #val == 0 and {} or split(val, model[col].list, true)
end
if model[col].dataRef ~= nil then
if type(val) == "table" then
for k, v in pairs(val) do
val[k] = "[[Data:Game/"..model[col].dataRef.."/"..v.."|"..v.."]]"
end
elseif #val > 0 then
val = "[[Data:Game/"..model[col].dataRef.."/"..val.."|"..val.."]]"
end
end
end
row[col] = val
end
queryResult[i] = row
end
h.insertQueryResult(result, tbl, queryResult)
end
local hasEffects = false
local jsonEffects = {}
for server, json in pairs(jsonSets) do
if json.effects then
hasEffects = true
jsonEffects[server] = {effects = {}}
for i,effect in ipairs(json.effects) do
local values = {}
values._table = 'ConceptCardEffect'
values.server = server
values.cc_iname = iname
jsonEffects[server].effects[i] = {}
for k,v in pairs(effect) do
values[k] = v
jsonEffects[server].effects[i][k] = v
effect[k] = nil
end
table.insert(result, cargo.store(values))
jsonEffects[server].server = server
end
-- A table of failed effect insertions.
local errorEffects = {}
for i, effect in ipairs(json.effects) do
local empty = true
for k, v in pairs(effect) do empty = false end
if not empty then
errorEffects[#errorEffects+1] = effect
end
end
json.effects = #errorEffects > 0 and errorEffects or nil
end
end
if next(jsonEffects) then
table.insert(result, '===ConceptCardEffect===\n')
local toInsert = {}
for k in pairs(jsonEffects) do table.insert(toInsert, k) end
table.sort(toInsert)
for i, k in ipairs(toInsert) do toInsert[i] = jsonEffects[k] end
h.insertQueryResult(result, nil, toInsert)
end
local buffDetailRows = cargo.query{
tables = 'BuffDetail',
fields = 'buff_iname, server, idx, calc, type, tktag, vini, vmax, vone',
where = where,
orderBy = 'idx'
}
h.insertQueryResult(result, 'BuffDetail', buffDetailRows)
-- Display unused keys here
local unused = false
for server, json in pairs(jsonSets) do if next(json) ~= nil then
unused = true
json.server = server
end end
if unused then
table.insert(result, "===Unused Keys===\nThe following keys were not used by inserted into any table and are thus unused.\n")
local toInsert = {}
for k in pairs(jsonSets) do table.insert(toInsert, k) end
table.sort(toInsert)
for i, k in ipairs(toInsert) do toInsert[i] = jsonSets[k] end
h.insertQueryResult(result, nil, toInsert)
end
table.insert(result, '[[Category:Data pages]]') -- Tracking category.
-- Handle errors encountered
if errors.cargoStore then
table.insert(result, '[[Category:Data pages that failed a table insert]]' )
end
if hasEffects then
table.insert(result, '[[Category:Data pages with effects]]')
end
return table.concat(result)
end
-- Add functions to model
p.model = (function()
dataModel.tables = {}
local recFunc
function recFunc(node)
if node.nodes ~= nil then for k, child in pairs(node.nodes) do recFunc(child) end end
if node.model ~= nil then for tbl, model in pairs(node.model) do dataModel.tables[tbl] = model end end
end
recFunc(dataModel)
-----------
-- Query --
-----------
dataModel.query = function(tables, fields, args)
local query = args
query.tables = tables
query.fields = fields
local result = cargo.query(query)
local toCast = {}
if type(query.tables) == 'string' then
query.tables = split(query.tables, ',', true)
end
if type(query.fields) == 'string' then
query.fields = split(query.fields, ',', true)
end
for _, field in ipairs(query.fields) do
-- Extract alias
local t = split(field, '=', true)
local alias = trim(t[2] or t[1])
local fnMatch = string.match(t[1], "([^()]*)[(](.*)[)](.*)")
if fnMatch ~= nil then
mw.log(fnMatch)
toCast[alias] = {"String"}
else
-- Extract table
local t2 = split(t[1], '.', true)
local tbl = #t2 > 1 and trim(t2[1]) or nil
local key = trim(t2[#t2])
if tbl == nil then
for _, tblName in ipairs(query.tables) do
tblName = trim(tblName)
if (dataModel.tables[tblName] or {})[key] ~= nil then
tbl = tblName
break
end
end
end
local model = (dataModel.tables[tbl] or {})[key]
toCast[alias] = type(model) == "string" and {model} or model
end
end
local castFuncs = {
Integer = tonumber
}
for i, row in ipairs(result) do
for k, castTo in pairs(toCast) do
local castFunc = castFuncs[castTo[1]] or function(v) return v end
if castTo.list ~= nil then
local list = {}
if row[k] and row[k] ~= '' then
for s in gsplit(row[k], castTo.list, true) do
list[#list+1] = castFunc(s)
end
end
row[k] = list
else
row[k] = castFunc(row[k])
end
end
end
return result
end
------------
-- getLoc --
------------
dataModel.getLoc = function(_pageName, param, lang)
if _pageName == nil then return '???' end
local where = "_pageName='".._pageName.."' and param='"..param.."' and value<>'' and lang='"
local thisLang = cargo.query{tables='Loc',fields='value',where=where..(lang or "english'")}
if #thisLang == 0 then thisLang = cargo.query{tables='Loc',fields='value',where=where.."english'"} end
if #thisLang == 0 then thisLang = cargo.query{tables='Loc',fields='value',where=where.."japanese'"} end
if #thisLang == 0 then thisLang = {{value = ''}} end
return thisLang[1].value
end
-------------
-- Sources --
-------------
dataModel.sources = require("Module:Data/Sources")(dataModel)
return dataModel
end)()
return p