You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
10 KiB

local Addon = LibStub("AceAddon-3.0"):NewAddon("WoWthing_Collector", "AceEvent-3.0")
Addon:SetDefaultModuleLibraries("AceBucket-3.0", "AceEvent-3.0", "AceTimer-3.0")
local ModulePrototype = {
UniqueTimer = function(self, name, seconds, callback, ...)
self.__timers = self.__timers or {}
if self.__timers[name] and self:TimeLeft(self.__timers[name]) > 0 then
-- print('Timer '..name..' already exists')
return
end
self.__timers[name] = self:ScheduleTimer(callback, seconds, ...)
end
}
Addon:SetDefaultModulePrototype(ModulePrototype)
local LibRealmInfo = LibStub('LibRealmInfo17janekjl')
-- Default SavedVariables
local defaultWWTCSaved = {
version = 9158,
chars = {},
guilds = {},
heirloomsV2 = {},
questsV2 = {},
toys = {},
worldQuestIds = {},
}
function Addon:OnInitialize()
-- Initialize saved variables to default if required
if WWTCSaved == nil or WWTCSaved.version < defaultWWTCSaved.version then
WWTCSaved = defaultWWTCSaved
end
Addon:Cleanup()
WWTCSaved.heirloomsV2 = WWTCSaved.heirloomsV2 or {}
WWTCSaved.questsV2 = WWTCSaved.questsV2 or {}
WWTCSaved.worldQuestIds = WWTCSaved.worldQuestIds or {}
WWTCSaved.honorCurrent = WWTCSaved.honorCurrent or 0
WWTCSaved.honorLevel = WWTCSaved.honorLevel or 0
WWTCSaved.honorMax = WWTCSaved.honorMax or 0
self.parseItemLinkCache = {}
-- Build a unique ID for this character
-- id, name, nameForAPI, rules, locale, nil, region, timezone, connections, englishName, englishNameForAPI
local _, realm, _, _, _, _, region, _, _, realmEnglish = LibRealmInfo:GetRealmInfoByUnit("player")
self.regionName = region or GetCurrentRegion()
self.charName = self.regionName .. "/" .. (realmEnglish or realm) .. "/" .. UnitName("player")
self.charClassID = select(3, UnitClass("player"))
-- Set up character data table
self.charData = WWTCSaved.chars[self.charName] or {}
self.charData.scanTimes = self.charData.scanTimes or {}
WWTCSaved.chars[self.charName] = self.charData
self:RegisterEvent('PLAYER_ENTERING_WORLD')
self:RegisterEvent('PLAYER_LOGOUT')
self:RegisterEvent('PLAYER_MONEY')
end
function Addon:Cleanup()
WWTCSaved.heirlooms = nil
WWTCSaved.quests = nil
WWTCSaved.transmogSources = nil
WWTCSaved.transmogSourcesV2 = nil
-- Remove data for any characters not seen in the last 3 days
local old = time() - (3 * 24 * 60 * 60)
for charName, charData in pairs(WWTCSaved.chars) do
if not charData.lastSeen or charData.lastSeen < old then
WWTCSaved.chars[charName] = nil
else
-- Wipe any deprecated data
charData.auras = nil
charData.balanceMythic15 = nil
charData.balanceUnleashedMonstrosities = nil
charData.biggerFishToFry = nil
charData.equipment = nil
charData.hiddenDungeons = nil
charData.hiddenKills = nil
charData.hiddenWorldQuests = nil
charData.mythicPlus = nil
charData.transmog = nil
charData.weeklyQuests = nil
charData.weeklyUghQuests = nil
if type(charData.illusions) == 'table' then
charData.illusions = nil
end
end
end
end
function Addon:UpdateLastSeen()
self.charData.lastSeen = time()
end
function Addon:PLAYER_ENTERING_WORLD()
self:UpdateLastSeen()
self:PLAYER_MONEY()
for _, module in Addon:IterateModules() do
if module.OnEnteringWorld ~= nil then
module:OnEnteringWorld()
end
end
end
function Addon:PLAYER_LOGOUT()
self:UpdateLastSeen()
for _, module in Addon:IterateModules() do
if module.OnLogout ~= nil then
module:OnLogout()
end
end
end
function Addon:PLAYER_MONEY()
self.charData.copper = GetMoney()
end
-- Utils
function Addon:TableKeys(tbl)
local keys = {}
for key, value in pairs(tbl) do
keys[#keys + 1] = key
end
return keys
end
function Addon:ParseItemLink(link, quality, count)
local cached = self.parseItemLinkCache[link]
if cached ~= nil then
return table.concat({ count, cached }, ':')
end
local parts = { strsplit(":", link) }
if string.find(parts[1], '\|Hbattlepet') then
return table.concat({
'pet',
parts[2], -- speciesID
parts[3], -- level
parts[4], -- quality
}, ':')
end
local item = {
count = count,
itemID = tonumber(parts[2]),
bonusIDs = {},
gems = {},
modifiers = {},
quality = quality,
}
if quality < 0 then
item.quality = C_Item.GetItemQualityByID(link)
end
if parts[3] ~= '' then
item.enchantID = tonumber(parts[3])
end
if parts[4] ~= '' then
for i = 4, 7 do
if parts[i] then
item.gems[#item.gems + 1] = tonumber(parts[i])
end
end
end
if parts[8] ~= '' then
item.suffixID = tonumber(parts[8])
end
-- 9 = uniqueID
-- 10 = linkLevel
-- 11 = specializationID
-- 12 = modifiersMask
if parts[13] ~= '' then
item.context = tonumber(parts[13])
end
local numBonusIDs = tonumber(parts[14])
if numBonusIDs ~= nil then
for i = 15, 14 + numBonusIDs do
item.bonusIDs[#item.bonusIDs + 1] = tonumber(parts[i])
end
end
-- 15 + numBonusIds = numModifiers
local startModifiers = 15 + (numBonusIDs or 0)
local numModifiers = tonumber(parts[startModifiers])
if numModifiers ~= nil then
for i = startModifiers + 1, startModifiers + (numModifiers * 2), 2 do
item.modifiers[#item.modifiers + 1] = parts[i] .. '_' .. parts[i + 1]
end
end
local effectiveILvl, _, _ = GetDetailedItemLevelInfo(link)
item.itemLevel = effectiveILvl
-- count:id:context:enchant:ilvl:quality:suffix:bonusIDs:gems
local ret = table.concat({
item.itemID,
item.context or 0,
item.enchantID or 0,
item.itemLevel or 0,
item.quality or 0,
item.suffixID or 0,
table.concat(item.bonusIDs, ','),
table.concat(item.gems, ','),
table.concat(item.modifiers, ','),
}, ':')
self.parseItemLinkCache[link] = ret
return table.concat({ count, ret }, ':')
end
-- https://www.wowinterface.com/forums/showthread.php?t=58916
-- Budgets 50% of target or current FPS to perform a workload.
-- finished = start(workload, onFinish, onDelay)
-- Arguments:
-- workload table Stack (last in, first out) of functions to call.
-- onFinish function? Optional callback when the table is empty.
-- onDelay function? Optional callback each time work delays to the next frame.
-- Returns:
-- finished boolean True when finished without any delay; false otherwise.
function Addon:BatchWork(workload, onFinish, onDelay)
local maxDuration = 500 / (tonumber(C_CVar.GetCVar("targetFPS")) or GetFrameRate())
local startTime = debugprofilestop()
local function continue()
local startTime = debugprofilestop()
local task = tremove(workload)
while (task) do
task()
if (debugprofilestop() - startTime > maxDuration) then
C_Timer.After(0, continue)
if (onDelay) then
onDelay()
end
return false
end
task = tremove(workload)
end
if (onFinish) then
onFinish()
end
return true
end
return continue()
end
-- Encode a sorted run of numbers into a moderately space-efficient format
-- [questID1].[encoded deltas]|[questID2].[deltas]|...
local CHAR_VALUES = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-_=+[{]};:,<.>/?'
local CHAR_TO_VALUE = {}
local VALUE_TO_CHAR = {}
for index = 1, strlen(CHAR_VALUES) do
local char = strbyte(CHAR_VALUES, index)
CHAR_TO_VALUE[char] = index
VALUE_TO_CHAR[index] = strchar(char)
end
function Addon:DeltaEncode(ids, onFinish)
local count = #ids
local maxDiff = strlen(CHAR_VALUES)
local anyDiffed = false
local output = {}
local index = 1
local last = nil
local workload = {}
for i = 1, count, 1000 do
table.insert(workload, 1, function()
for j = i, min(i + 999, count) do
local questId = ids[j]
if last ~= nil then
local diff = questId - last
if diff <= maxDiff then
if anyDiffed ~= true then
anyDiffed = true
output[index] = '.'
index = index + 1
end
output[index] = VALUE_TO_CHAR[diff]
else
output[index] = '|'
index = index + 1
last = nil
end
end
if last == nil then
anyDiffed = false
output[index] = questId
end
index = index + 1
last = questId
end
end)
end
Addon:BatchWork(workload, function()
onFinish(table.concat(output, ''))
end)
end
function Addon:DeltaDecode(squished)
local data = {}
local index = 1
-- local startTime = debugprofilestop()
local parts = { strsplit('|', squished) }
for _, part in ipairs(parts) do
local deltaParts = { strsplit('.', part, 2) }
local id = tonumber(deltaParts[1])
data[index] = id
index = index + 1
local deltas = deltaParts[2]
if deltas ~= nil then
for i = 1, #deltas do
local byte = strbyte(deltas, i)
id = id + CHAR_TO_VALUE[byte]
data[index] = id
index = index + 1
end
end
end
-- local endTime = debugprofilestop()
-- print('DeltaDecode: '..#squished.. ' bytes in '..endTime - startTime..'ms')
return data
end