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.

311 lines
8.6 KiB

local _, addonTable = ...
local Serialization = {}
-- Upvalues
local R = Rarity
-- Externals
local compress = LibStub("LibCompress")
local L = LibStub("AceLocale-3.0"):GetLocale("Rarity")
-- Lua APIs
local tonumber = tonumber
local pairs = pairs
local type = type
local CONSTANTS = addonTable.constants
local FormatTime = Rarity.Utils.PrettyPrint.FormatTime -- Utils are loaded before Core modules, so this should be fine
--- Sets some default values for items (used before importing them)?
--- TODO: LuaDoc
function Serialization:CleanItemForImport(item)
item.attempts = 0
item.lastAttempts = 0
item.enabled = true
item.found = false
item.enableAnnouncements = true
item.holidayReminder = true
end
--- Returns true if an item has a valid format ?
-- TODO: LuaDoc
function Serialization:CanItemBeExportedImported(item)
if not item then
return false
end
if not item.method then
return false
end
if not item.type then
return false
end
if not item.itemId or tonumber(item.itemId) == nil or item.itemId <= 0 then
return false
end
if not item.chance or tonumber(item.chance) == nil or item.chance <= 0 then
return false
end
if item.method == CONSTANTS.DETECTION_METHODS.COLLECTION then
if not item.collectedItemId or tonumber(item.collectedItemId) == nil or item.collectedItemId <= 0 then
return false
end
end
if item.type ~= CONSTANTS.ITEM_TYPES.ITEM then
if not item.spellId or tonumber(item.spellId) == nil or item.spellId <= 0 then
return false
end
end
if item.type == CONSTANTS.ITEM_TYPES.PET then
if not item.creatureId or tonumber(item.creatureId) == nil or item.creatureId <= 0 then
return false
end
end
if item.method == CONSTANTS.DETECTION_METHODS.ARCH then
if not item.raceId or tonumber(item.raceId) == nil or item.raceId <= 0 then
return false
end
end
if item.method == CONSTANTS.DETECTION_METHODS.ZONE or item.method == CONSTANTS.DETECTION_METHODS.FISHING then
if not item.zones or #item.zones <= 0 then
return false
end
end
if item.method == CONSTANTS.DETECTION_METHODS.USE then
if not item.items or #item.items <= 0 then
return false
end
end
if item.method == CONSTANTS.DETECTION_METHODS.NPC or item.method == CONSTANTS.DETECTION_METHODS.BOSS then
if (not item.npcs or #item.npcs <= 0) and (not item.statisticId or #item.statisticId <= 0) then
return false
end
end
return true
end
--- Attempts to import data from the BunnyHunter addon?
-- This must be ancient, I've never even heard of it before...
-- TODO: LuaDoc
function Serialization:ImportFromBunnyHunter()
self = Rarity
if self.db.profile.importedFromBunnyHunter then
return
end
if BunnyHunterDB then
StaticPopupDialogs["RARITY_IMPORT_FROM_BUNNYHUNTER"] = {
text = L["Bunny Hunter is running. Would you like Rarity to import data from Bunny Hunter now? Disable Bunny Hunter or click Yes if you don't want to be asked again."],
button1 = YES,
button2 = NO,
hideOnEscape = 1,
timeout = 0,
exclusive = 1,
whileDead = 1,
OnAccept = function()
self = Rarity
-- Do the import
if BunnyHunterDB.loots and type(BunnyHunterDB.loots) == "table" then
for k, v in pairs(BunnyHunterDB.loots) do
for groupkey, group in pairs(self.db.profile.groups) do
for itemkey, item in pairs(group) do
if item.itemId == tonumber(k) then
self:Debug("Resetting found record for %s", itemkey)
item.finds = nil
item.totalFinds = nil
end
end
end
end
for k, v in pairs(BunnyHunterDB.loots) do
for groupkey, group in pairs(self.db.profile.groups) do
for itemkey, item in pairs(group) do
if item.itemId == tonumber(k) then
for kk, vv in pairs(v) do
self:Debug(
"%s: adding a kill after %d attempts, %s time",
itemkey,
vv.loots,
FormatTime(vv.time)
)
if not item.finds then
item.finds = {}
end
local count = 0
for x, y in pairs(item.finds) do
count = count + 1
end
table.insert(item.finds, {
num = count + 1,
totalAttempts = vv.loots,
totalTime = vv.time,
attempts = vv.loots,
time = vv.time,
})
item.totalFinds = (item.totalFinds or 0) + 1
end
end
end
end
end
end
if BunnyHunterDB.kills_by_id and type(BunnyHunterDB.kills_by_id) == "table" then
for k, v in pairs(BunnyHunterDB.kills_by_id) do
for groupkey, group in pairs(self.db.profile.groups) do
for itemkey, item in pairs(group) do
if item.npcs then
for npckey, npcid in pairs(item.npcs) do
if npcid == tonumber(k) then
self:Debug("Resetting attempts for %s", itemkey)
item.attempts = 0
item.lastAttempts = nil
end
end
end
end
end
end
for k, v in pairs(BunnyHunterDB.kills_by_id) do
for groupkey, group in pairs(self.db.profile.groups) do
for itemkey, item in pairs(group) do
if item.npcs then
for npckey, npcid in pairs(item.npcs) do
if npcid == tonumber(k) then
self:Debug("%s: adding %d attempt(s)", itemkey, v)
item.attempts = (item.attempts or 0) + v
end
end
end
end
end
end
end
if BunnyHunterDB.times and type(BunnyHunterDB.times) == "table" then
for k, v in pairs(BunnyHunterDB.times) do
for groupkey, group in pairs(self.db.profile.groups) do
for itemkey, item in pairs(group) do
if item.itemId == tonumber(k) then
self:Debug("%s: updating time to %f", itemkey, v)
item.time = v
item.lastTime = nil
end
end
end
end
end
self:UpdateInterestingThings()
Rarity.GUI:UpdateText()
-- if self:InTooltip() then self:ShowTooltip() end
self.db.profile.importedFromBunnyHunter = true
self:Print(L["Data has been imported from Bunny Hunter"])
end,
}
StaticPopup_Show("RARITY_IMPORT_FROM_BUNNYHUNTER")
end
end
-- Compression encoding
local encode_translate = { [255] = "\255\001", [0] = "\255\002" }
local function encode_helper(char)
return encode_translate[char:byte()]
end
local decode_translate = { ["\001"] = "\255", ["\002"] = "\000" }
local function decode_helper(text)
return decode_translate[text]
end
function R:Encode(data)
return data:gsub("([\255%z])", encode_helper)
end
function R:Decode(data)
return data:gsub("\255([\001\002])", decode_helper)
end
function R:Compress(data)
return self:Encode(compress:Compress(data))
end
function R:Decompress(data)
return compress:Decompress(self:Decode(data))
end
local b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
function Serialization:DecodeBase64(encodedString)
if not encodedString then
return nil
end
encodedString = string.gsub(encodedString, "[^" .. b .. "=]", "")
return (
encodedString
:gsub(".", function(x)
if x == "=" then
return ""
end
local r, f = "", (b:find(x) - 1)
for i = 6, 1, -1 do
r = r .. (f % 2 ^ i - f % 2 ^ (i - 1) > 0 and "1" or "0")
end
return r
end)
:gsub("%d%d%d?%d?%d?%d?%d?%d?", function(x)
if #x ~= 8 then
return ""
end
local c = 0
for i = 1, 8 do
c = c + (x:sub(i, i) == "1" and 2 ^ (8 - i) or 0)
end
return string.char(c)
end)
)
end
function Serialization:EncodeBase64(input)
return (
(input:gsub(".", function(x)
local r, byte = "", x:byte()
for i = 8, 1, -1 do
r = r .. (byte % 2 ^ i - byte % 2 ^ (i - 1) > 0 and "1" or "0")
end
return r
end) .. "0000"):gsub("%d%d%d?%d?%d?%d?", function(x)
if #x < 6 then
return ""
end
local c = 0
for i = 1, 6 do
c = c + (x:sub(i, i) == "1" and 2 ^ (6 - i) or 0)
end
return b:sub(c + 1, c + 1)
end) .. ({ "", "==", "=" })[#input % 3 + 1]
)
end
function Serialization:DeserializeItemString(compressedEncodedItemString)
local decodedItemString = self:DecodeBase64(compressedEncodedItemString)
local decompressedItemString = self:Decompress(decodedItemString)
local success, deserializedItemEntry = R:Deserialize(decompressedItemString)
assert(success, "Failed to deserialize item string")
return deserializedItemEntry
end
Serialization.Decode = R.Decode
Serialization.Decompress = R.Decompress
Rarity.Serialization = Serialization
return Serialization