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 data = Achievements.loadData()
     local types = Achievements.loadTypes()
     if not data or not data.achievement_types then
      
        return achievementType
    end
 
     -- Try to match achievement ID
     -- Try to match achievement ID
     for _, typeData in ipairs(data.achievement_types) do
     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 data = Achievements.loadData()
     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(data.achievement_types) do
         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 data = Achievements.loadData()
     local types = Achievements.loadTypes()
      
      
     -- Build a lookup table for achievement type definitions
     -- Build a lookup table for achievement type definitions
     local typeDefinitions = {}
     local typeDefinitions = {}
     if data and data.achievement_types then
     for _, typeData in ipairs(types) do
        for _, typeData in ipairs(data.achievement_types) do
        if typeData.id and typeData.name then
            if typeData.id and typeData.name then
            typeDefinitions[typeData.id] = {
                typeDefinitions[typeData.id] = {
                name = typeData.name,
                    name = typeData.name,
                tier = typeData.tier or 999
                    tier = typeData.tier or 999
            }
                }
            end
         end
         end
     end
     end
Line 417: Line 542:
     end
     end
      
      
     local data = Achievements.loadData()
     local types = Achievements.loadTypes()
    if not data or not data.achievement_types then
        return nil
    end
      
      
     -- Direct lookup in achievement_types array
     -- Direct lookup in achievement_types array
     for _, typeData in ipairs(data.achievement_types) do
     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 data = Achievements.loadData()
     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(data.achievement_types) do
     for _, typeData in ipairs(types) do
         typeDefinitions[typeData.id] = typeData
         typeDefinitions[typeData.id] = typeData
     end
     end