Module:AchievementSystem: Difference between revisions
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| Line 79: | Line 79: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local ACHIEVEMENT_DATA_PAGE = 'MediaWiki:AchievementData.json' | local ACHIEVEMENT_DATA_PAGE = 'MediaWiki:AchievementData.json' | ||
local ACHIEVEMENT_LIST_PAGE = 'MediaWiki:AchievementList.json' | |||
local dataCache = nil | local dataCache = nil | ||
local typesCache = nil | |||
local DEFAULT_DATA = { | local DEFAULT_DATA = { | ||
| Line 87: | Line 89: | ||
user_achievements = {}, | user_achievements = {}, | ||
} | } | ||
-------------------------------------------------------------------------------- | |||
-- Load achievement types from the JSON page | |||
-------------------------------------------------------------------------------- | |||
function Achievements.loadTypes(frame) | |||
-- Use the request-level cache if we already loaded data once | |||
if typesCache then | |||
return typesCache | |||
end | |||
local success, types = pcall(function() | |||
-- Get the JSON content using frame:preprocess if available | |||
local jsonText | |||
if frame and type(frame) == "table" and frame.preprocess then | |||
-- Make sure frame is valid and has preprocess method | |||
local preprocessSuccess, preprocessResult = pcall(function() | |||
return frame:preprocess('{{MediaWiki:AchievementList.json}}') | |||
end) | |||
if preprocessSuccess and preprocessResult then | |||
jsonText = preprocessResult | |||
end | |||
end | |||
-- If we couldn't get JSON from frame:preprocess, fall back to direct content loading | |||
if not jsonText then | |||
-- Try using mw.loadJsonData first (preferred method) | |||
if mw.loadJsonData then | |||
local loadJsonSuccess, jsonData = pcall(function() | |||
return mw.loadJsonData(ACHIEVEMENT_LIST_PAGE) | |||
end) | |||
if loadJsonSuccess and jsonData and type(jsonData) == 'table' and jsonData.achievement_types then | |||
return jsonData.achievement_types | |||
end | |||
end | |||
-- Direct content loading approach as fallback | |||
local pageTitle = mw.title.new(ACHIEVEMENT_LIST_PAGE) | |||
if pageTitle and pageTitle.exists then | |||
-- Get raw content from the wiki page | |||
local contentSuccess, content = pcall(function() | |||
return pageTitle:getContent() | |||
end) | |||
if contentSuccess and content and content ~= "" then | |||
-- Remove any BOM or leading whitespace that might cause issues | |||
content = content:gsub("^%s+", "") | |||
if content:byte(1) == 239 and content:byte(2) == 187 and content:byte(3) == 191 then | |||
content = content:sub(4) | |||
end | |||
jsonText = content | |||
-- Try different JSON decode approaches | |||
if jsonText and mw.text and mw.text.jsonDecode then | |||
-- First try WITHOUT PRESERVE_KEYS flag (standard approach) | |||
local jsonDecodeSuccess, jsonData = pcall(function() | |||
return mw.text.jsonDecode(jsonText) | |||
end) | |||
if jsonDecodeSuccess and jsonData and jsonData.achievement_types then | |||
return jsonData.achievement_types | |||
end | |||
-- If that failed, try with JSON_TRY_FIXING flag | |||
jsonDecodeSuccess, jsonData = pcall(function() | |||
return mw.text.jsonDecode(jsonText, mw.text.JSON_TRY_FIXING) | |||
end) | |||
if jsonDecodeSuccess and jsonData and jsonData.achievement_types then | |||
return jsonData.achievement_types | |||
end | |||
end | |||
end | |||
end | |||
-- If we couldn't load from AchievementList.json, fall back to AchievementData.json | |||
local data = Achievements.loadData(frame) | |||
if data and data.achievement_types then | |||
return data.achievement_types | |||
end | |||
else | |||
-- We have jsonText from frame:preprocess, try to decode it | |||
if jsonText and mw.text and mw.text.jsonDecode then | |||
-- First try WITHOUT PRESERVE_KEYS flag (standard approach) | |||
local jsonDecodeSuccess, jsonData = pcall(function() | |||
return mw.text.jsonDecode(jsonText) | |||
end) | |||
if jsonDecodeSuccess and jsonData and jsonData.achievement_types then | |||
return jsonData.achievement_types | |||
end | |||
-- If that failed, try with JSON_TRY_FIXING flag | |||
jsonDecodeSuccess, jsonData = pcall(function() | |||
return mw.text.jsonDecode(jsonText, mw.text.JSON_TRY_FIXING) | |||
end) | |||
if jsonDecodeSuccess and jsonData and jsonData.achievement_types then | |||
return jsonData.achievement_types | |||
end | |||
end | |||
-- If we couldn't decode the JSON, fall back to AchievementData.json | |||
local data = Achievements.loadData(frame) | |||
if data and data.achievement_types then | |||
return data.achievement_types | |||
end | |||
end | |||
-- As an absolute last resort, return an empty array | |||
return {} | |||
end) | |||
if not success or not types then | |||
-- If there was an error, fall back to AchievementData.json | |||
local data = Achievements.loadData(frame) | |||
if data and data.achievement_types then | |||
typesCache = data.achievement_types | |||
return typesCache | |||
end | |||
types = {} | |||
end | |||
typesCache = types | |||
return types | |||
end | |||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
| Line 233: | Line 363: | ||
end | end | ||
local | local types = Achievements.loadTypes() | ||
-- Try to match achievement ID | -- Try to match achievement ID | ||
for _, typeData in ipairs( | for _, typeData in ipairs(types) do | ||
if typeData.id == achievementType then | if typeData.id == achievementType then | ||
if typeData.name and typeData.name ~= "" then | if typeData.name and typeData.name ~= "" then | ||
| Line 266: | Line 393: | ||
end | end | ||
local | local types = Achievements.loadTypes() | ||
local highestTier = 999 | local highestTier = 999 | ||
local highestAchievement = nil | local highestAchievement = nil | ||
| Line 273: | Line 400: | ||
local achType = achievement.type | local achType = achievement.type | ||
for _, typeData in ipairs( | for _, typeData in ipairs(types) do | ||
if typeData.id == achType then | if typeData.id == achType then | ||
local tier = typeData.tier or 999 | local tier = typeData.tier or 999 | ||
| Line 307: | Line 434: | ||
end | end | ||
local | local types = Achievements.loadTypes() | ||
-- Build a lookup table for achievement type definitions | -- Build a lookup table for achievement type definitions | ||
local typeDefinitions = {} | local typeDefinitions = {} | ||
for _, typeData in ipairs(types) do | |||
if typeData.id and typeData.name then | |||
typeDefinitions[typeData.id] = { | |||
name = typeData.name, | |||
tier = typeData.tier or 999 | |||
} | |||
end | end | ||
end | end | ||
| Line 417: | Line 542: | ||
end | end | ||
local | local types = Achievements.loadTypes() | ||
-- Direct lookup in achievement_types array | -- Direct lookup in achievement_types array | ||
for _, typeData in ipairs( | for _, typeData in ipairs(types) do | ||
if typeData.id == achievementType then | if typeData.id == achievementType then | ||
return typeData | return typeData | ||
| Line 447: | Line 569: | ||
end | end | ||
local | local types = Achievements.loadTypes() | ||
-- Build a table of achievement definitions for quick lookup | -- Build a table of achievement definitions for quick lookup | ||
local typeDefinitions = {} | local typeDefinitions = {} | ||
for _, typeData in ipairs( | for _, typeData in ipairs(types) do | ||
typeDefinitions[typeData.id] = typeData | typeDefinitions[typeData.id] = typeData | ||
end | end | ||