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.

509 lines
16 KiB

local _, addon = ...
local DataProvider = {};
addon.PerksProgramDataProvider = DataProvider;
local PerksProgramAPI = C_PerksProgram;
local C_TransmogCollection = C_TransmogCollection;
if PerksProgramAPI then
DataProvider.programExisted = true;
else
PerksProgramAPI = {};
end
local CURRENCY_ID = Constants.CurrencyConsts.CURRENCY_ID_PERKS_PROGRAM_DISPLAY_INFO or 2032;
local GetVendorItemInfo = PerksProgramAPI.GetVendorItemInfo;
local GetTimeRemaining = PerksProgramAPI.GetTimeRemaining;
local GetCurrencyAmount = PerksProgramAPI.GetCurrencyAmount; --Returns the amount of Trader's Tendor (2032) Constants.CurrencyConsts.CURRENCY_ID_PERKS_PROGRAM_DISPLAY_INFO
local GetCurrentCalendarTime = C_DateAndTime.GetCurrentCalendarTime;
local type = type;
local VendorItemDataCache = {};
local DB;
local IGNORED_KEYS = {
purchased = true,
perksVendorItemID = true,
timeRemaining = true,
refundable = true,
pending = true,
};
local DELIMITER = "::";
local function CompressTable(tbl)
local output = DELIMITER;
local valueType;
for k, v in pairs(tbl) do
if not IGNORED_KEYS[k] then
valueType = type(v);
if valueType == "number" or valueType == "string" and v ~= 0 and v ~= "" then
output = output ..k ..DELIMITER.. v ..DELIMITER;
end
end
end
return output
end
local function DecompressData(dataString)
local key, value, seg;
local numericVal;
local tonumber = tonumber;
local find = string.find;
local strsub = string.sub;
local tbl = {};
local isKey = true;
local stringLen = string.len(dataString);
local initPos = 3;
local fromIndex, toIndex = find(dataString, DELIMITER, initPos);
while fromIndex and toIndex do
seg = strsub(dataString, initPos, fromIndex - 1);
initPos = toIndex + 1;
fromIndex, toIndex = find(dataString, DELIMITER, initPos);
if isKey then
key = seg;
else
value = seg;
numericVal = tonumber(value);
if numericVal then
tbl[key] = numericVal;
else
tbl[key] = value;
end
end
isKey = not isKey;
end
return tbl
end
function DataProvider:DoesPerksProgramExist()
return self.programExisted
end
function DataProvider:IsNewVendorItem(vendorItemID)
return vendorItemID and DB.VendorItems[vendorItemID] == nil
end
function DataProvider:SaveVendorItemData(vendorItemID, overwrite)
if vendorItemID and (overwrite or self:IsNewVendorItem(vendorItemID)) then
local info = GetVendorItemInfo(vendorItemID);
if info and info.perksVendorItemID and info.perksVendorItemID ~= 0 then
if info.name == "" or info.description == "" then
return false
end
local dataString = CompressTable(info);
local month, year = self:GetActivePerksDate();
local date = year.."/"..month;
dataString = dataString .. "addedDate" ..DELIMITER.. date ..DELIMITER;
VendorItemDataCache[vendorItemID] = info;
info.addedInYear = year;
info.addedInMonth = month;
DB.VendorItems[vendorItemID] = dataString;
return dataString
end
end
end
function DataProvider:GetVendorItemInfoFromDatabase(vendorItemID)
local info;
if DB.VendorItems[vendorItemID] then
info = DecompressData( DB.VendorItems[vendorItemID] );
info.isCache = true;
return info
end
end
function DataProvider:GetAndCacheVendorItemInfo(vendorItemID)
if not VendorItemDataCache[vendorItemID] then
local info = GetVendorItemInfo(vendorItemID);
--! After patch ?, the perksVendorItemID will not return 0 even you haven't visited Trading Post during the game session
--! So (perksVendorItemID ~= 0) is no longer a reliable way to check if we need to decompress data from our SavedVariables
if info and info.perksVendorItemID ~= 0 then
if info.name and info.name ~= "" then
VendorItemDataCache[vendorItemID] = info;
end
return info
else
VendorItemDataCache[vendorItemID] = self:GetVendorItemInfoFromDatabase(vendorItemID);
end
end
return VendorItemDataCache[vendorItemID]
end
function DataProvider:GetVendorItemName(vendorItemID)
local info = self:GetAndCacheVendorItemInfo(vendorItemID);
if info then
return info.name
else
return ""
end
end
function DataProvider:GetVendorItemCategory(vendorItemID)
local info = self:GetAndCacheVendorItemInfo(vendorItemID);
if info then
return info.perksVendorCategoryID
else
return 128
end
end
function DataProvider:GetVendorItemDescription(vendorItemID)
local info = self:GetAndCacheVendorItemInfo(vendorItemID);
if info then
return info.description
else
return ""
end
end
function DataProvider:GetVendorItemPrice(vendorItemID)
local info = self:GetAndCacheVendorItemInfo(vendorItemID);
if info then
if info.isCache then
return info.price or 0
else
local cachedData = self:GetVendorItemInfoFromDatabase(vendorItemID);
local price = cachedData and cachedData.price;
if price then
return price
end
end
end
return 0
end
function DataProvider:GetVendorItemTransmogSetID(vendorItemID)
local info = self:GetAndCacheVendorItemInfo(vendorItemID);
if info and info.transmogSetID ~= 0 then
return info.transmogSetID
else
local cachedData = self:GetVendorItemInfoFromDatabase(vendorItemID);
return cachedData and cachedData.transmogSetID or nil;
end
end
function DataProvider:IsVendorItemPurchased(vendorItemID)
local info = self:GetAndCacheVendorItemInfo(vendorItemID);
if info then
if info.isCache or (info.price == 0) then
--Player didn't visit Trading Post during this session, use cache
--[[
1 Transmog
2 Mount
3 Pet
5 Toy
7 Illusion
8 Transmogset
--]]
local itemID = info.itemID;
local category = info.perksVendorCategoryID;
if category == 1 then
local appearanceID;
local sourceID = info.itemModifiedAppearanceID;
if (not sourceID) or sourceID == 0 then
appearanceID, sourceID = C_TransmogCollection.GetItemInfo(itemID);
end
if sourceID and sourceID ~= 0 then
return C_TransmogCollection.PlayerKnowsSource(sourceID);
end
elseif category == 2 then
local mountID = C_MountJournal.GetMountFromItem(itemID);
if mountID then
local isCollected = select(11, C_MountJournal.GetMountInfoByID(mountID));
return isCollected
end
elseif category == 3 then
local petName = C_PetJournal.GetPetInfoByItemID(itemID);
if petName then
local _, petGUID = C_PetJournal.FindPetIDByName(petName);
return petGUID ~= nil
end
elseif category == 5 then
return PlayerHasToy(itemID);
elseif category == 7 then
local illusionID = info.illusionID;
if illusionID then
local tbl = C_TransmogCollection.GetIllusionInfo(illusionID);
return tbl and tbl.isCollected
end
elseif category == 8 then
local transmogSetID = info.transmogSetID;
if transmogSetID == 0 then
local itemInfo = DataProvider:GetVendorItemInfoFromDatabase(vendorItemID);
transmogSetID = itemInfo and itemInfo.transmogSetID;
end
if transmogSetID then
local sourceIDs = C_TransmogSets.GetAllSourceIDs(transmogSetID);
if sourceIDs and sourceIDs[1] then
return C_TransmogCollection.PlayerKnowsSource( sourceIDs[1] );
end
end
end
end
return info.purchased
end
end
function DataProvider:UpdateActivePerksMonthInfo()
if not (self.month and self.currentMonthName) then
local activitiesInfo = C_PerksActivities.GetPerksActivitiesInfo();
local month = activitiesInfo.activePerksMonth;
local currentCalendarTime = GetCurrentCalendarTime();
local year = currentCalendarTime.year;
self.currentMonthName = activitiesInfo.displayMonthName;
self.year = year;
self.month = month;
for _, monthInfo in ipairs(DB.MonthNames) do
if month == monthInfo.m and year == monthInfo.y then
return
end
end
table.insert(DB.MonthNames, {
y = year,
m = month,
n = activitiesInfo.displayMonthName,
});
end
end
function DataProvider:GetActivePerksDate()
self:UpdateActivePerksMonthInfo();
return self.month, self.year
end
function DataProvider:GetCurrentDisplayMonthName()
self:UpdateActivePerksMonthInfo();
return self.currentMonthName;
end
function DataProvider:GetDisplayMonthName(year, month)
if type(year) == "string" then
year, month = string.match(year, "(%d+)/(%d+)");
year = tonumber(year);
month = tonumber(month);
end
if not self.monthNames then
--[year] = {[month] = name},
self.monthNames = {};
for _, monthInfo in ipairs(DB.MonthNames) do
if not self.monthNames[monthInfo.y] then
self.monthNames[monthInfo.y] = {};
end
self.monthNames[monthInfo.y][monthInfo.m] = monthInfo.n;
end
end
if not self.monthNames[year] then
self.monthNames[year] = {};
end
if not self.monthNames[year][month] then
self.monthNames[year][month] = self:GetCurrentDisplayMonthName();
end
return self.monthNames[year][month]
end
local EventListener = CreateFrame("Frame");
if DataProvider:DoesPerksProgramExist() then
EventListener:RegisterEvent("PERKS_ACTIVITIES_UPDATED");
EventListener:RegisterEvent("PERKS_ACTIVITY_COMPLETED");
EventListener:RegisterEvent("PERKS_PROGRAM_DATA_REFRESH");
EventListener:RegisterEvent("PERKS_PROGRAM_CURRENCY_REFRESH");
EventListener:RegisterEvent("PERKS_PROGRAM_REFUND_SUCCESS");
EventListener:RegisterEvent("PERKS_PROGRAM_PURCHASE_SUCCESS");
end
EventListener:SetScript("OnEvent", function(self, event, ...)
if event == "PERKS_ACTIVITIES_UPDATED" or event == "PERKS_ACTIVITY_COMPLETED" then
DataProvider:ClearActivityCache();
elseif event == "PERKS_PROGRAM_DATA_REFRESH" then
local vendorItemIDs = C_PerksProgram.GetAvailableVendorItemIDs();
for _, vendorItemID in pairs(vendorItemIDs) do
GetVendorItemInfo(vendorItemID);
end
C_Timer.After(1, function()
for _, vendorItemID in pairs(vendorItemIDs) do
GetVendorItemInfo(vendorItemID);
DataProvider:SaveVendorItemData(vendorItemID);
end
end);
DataProvider:UpdateActivePerksMonthInfo();
DataProvider:SaveCurrentMonthItems(vendorItemIDs);
elseif event == "PERKS_PROGRAM_CURRENCY_REFRESH" then
DataProvider.ownedCurrencyAmount = nil;
elseif event == "PERKS_PROGRAM_REFUND_SUCCESS" or event == "PERKS_PROGRAM_PURCHASE_SUCCESS" then
local vendorItemID = ...;
local isOwned = event == "PERKS_PROGRAM_PURCHASE_SUCCESS";
if vendorItemID and VendorItemDataCache[vendorItemID] then
VendorItemDataCache[vendorItemID].purchased = isOwned;
VendorItemDataCache[vendorItemID].refundable = isOwned;
end
DataProvider.ownedCurrencyAmount = nil;
end
end);
function DataProvider:ClearActivityCache()
self.unclaimedPoints = nil;
self.unearnedPoints = nil;
self.currentMonthName = nil;
self.month = nil;
end
function DataProvider:CacheActivityInfo()
if not self.unclaimedPoints then
local pendingRewards = PerksProgramAPI.GetPendingChestRewards();
local numUnclaimed = 0;
if pendingRewards then
for _, reward in pairs(pendingRewards) do
numUnclaimed = numUnclaimed + (reward.rewardAmount or 0);
end
end
self.unclaimedPoints = numUnclaimed;
end
if not self.unearnedPoints then
local activitiesInfo = C_PerksActivities.GetPerksActivitiesInfo();
local currentPoints = 0;
local numUnearned = 0;
for _, activityInfo in pairs(activitiesInfo.activities) do
if activityInfo.completed then
currentPoints = currentPoints + activityInfo.thresholdContributionAmount;
end
end
for _, thresholdInfo in pairs(activitiesInfo.thresholds) do
if thresholdInfo.requiredContributionAmount > currentPoints then
numUnearned = numUnearned + thresholdInfo.currencyAwardAmount;
end
end
self.unearnedPoints = numUnearned;
end
end
function DataProvider:GetAvailableCurrency()
--Returns the amounts of unclaimed and unearned token
self:CacheActivityInfo();
return self.unclaimedPoints or 0, self.unearnedPoints or 0;
end
function DataProvider:GetCurrencyAmount()
if not self.ownedCurrencyAmount then
self.ownedCurrencyAmount = GetCurrencyAmount() or 0;
end
return self.ownedCurrencyAmount
end
function DataProvider:SaveCurrentMonthItems(vendorItemIDs)
local month = self:GetActivePerksDate();
if month ~= DB.CurrentMonthData.month then
local tbl = {};
local total = 0;
for i, id in ipairs(vendorItemIDs) do
if id ~= 0 then
total = total + 1;
tbl[total] = id;
end
end
DB.CurrentMonthData.items = tbl;
DB.CurrentMonthData.month = month;
end
end
function DataProvider:GetCurrentMonthItems()
local month = self:GetActivePerksDate();
if month and month == DB.CurrentMonthData.month then
return DB.CurrentMonthData.items
else
DB.CurrentMonthData = {};
end
end
function DataProvider:GetVendorItemAddedMonthName(vendorItemID)
local info = self:GetVendorItemInfoFromDatabase(vendorItemID);
if info and info.addedDate then
if not self.currentMonthDate then
local month, year = self:GetActivePerksDate();
self.currentMonthDate = year.."/"..month;
end
local monthName = DataProvider:GetDisplayMonthName(info.addedDate);
return monthName, (self.currentMonthDate == info.addedDate);
else
return nil, true
end
end
local function LoadDatabase()
if not NarcissusDB.PerksProgramDB then
NarcissusDB.PerksProgramDB = {};
end
DB = NarcissusDB.PerksProgramDB;
if not DB.VendorItems then
DB.VendorItems = {};
end
if not DB.MonthNames then
DB.MonthNames = {};
end
if not DB.CurrentMonthData then
DB.CurrentMonthData = {};
end
end
addon.AddInitializationCallback(LoadDatabase);
--[[
local activitiesInfo = C_PerksActivities.GetPerksActivitiesInfo();
[thresholds]
[displayMonthName]
Enum.PerksVendorCategoryType
1 Transmog
2 Mount
3 Pet
5 Toy
7 Illusion
8 Transmogset
--]]