diff --git a/SlippyCheezeReadItOnce.lua b/SlippyCheezeReadItOnce.lua index 2a8b78c..0e500b2 100644 --- a/SlippyCheezeReadItOnce.lua +++ b/SlippyCheezeReadItOnce.lua @@ -1,24 +1,34 @@ -- Copyright © 2018 Daniel Pittman <daniel@rimspace.net> -- See LICENSE for more details. -if not SlippyCheezeReadItOnce then - SlippyCheezeReadItOnce = { - ADDON_NAME="SlippyCheezeReadItOnce", +SlippyCheeze = SlippyCheeze or {} + +if not SlippyCheeze.ReadItOnce then + SlippyCheeze.ReadItOnce = { + IS_RELEASE_VERSION = false, + NAME="SlippyCheezeReadItOnce", DISPLAY_NAME = "|c798BD2ReadItOnce|r", - DOUBLE_TAP_TIME = 1000, + -- for double-tap bypass of the block previousBook = {id=nil, time=0}, - -- seen holds our saved variables. + DOUBLE_TAP_TIME = 1000, + -- used for reporting on our background achievement scan + async = nil, + lore = { + added = 0, + scanned = 0, + start = 0, + }, + -- seen holds our saved variables, eg, seen books. seen = {} } end --- my local alias for the addon itself. -local M = SlippyCheezeReadItOnce +local addon = SlippyCheeze.ReadItOnce local unpack = unpack local insert = table.insert -- reduce consing at runtime in debug message display -local msg_prefix = M.DISPLAY_NAME..": " +local msg_prefix = addon.DISPLAY_NAME..": " local function msg(fmt, ...) local args = {} @@ -31,7 +41,7 @@ end -- return bool, have we seen this before. never called before saved variables -- are loaded and initialized. -function M:HaveSeenBookBefore(id, title, body) +function addon:HaveSeenBookBefore(id, title, body) if type(id) ~= "number" then msg("ReadItOnce: id is <<1>> (<<2>>)", type(id), id) return false @@ -67,7 +77,7 @@ end -- Called when we want to skip showing a book. Probably going to be very -- strange if you call it any other time! -function M:DoNotShowThisBook(title) +function addon:DoNotShowThisBook(title) PlaySound(SOUNDS.NEGATIVE_CLICK) local params = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_SMALL_TEXT, nil) @@ -86,24 +96,24 @@ end -- 100023 -- -- The HaveSeenBook logic is my addition. -function M:OnShowBookOverride(eventCode, title, body, medium, showTitle, bookId) +function addon:OnShowBookOverride(eventCode, title, body, medium, showTitle, bookId) -- never block a book if we are not in the most basic state, which is the -- world interaction state. if not SCENE_MANAGER:IsShowingBaseScene() then - return self.DoNotShowThisBook(title) + return self:DoNotShowThisBook(title) end -- seen before, block unless is double-tap within the limit if HaveSeenBookBefore(bookId, title, body) then -- different book from the last time? block. if self.previousBook.id ~= bookId then - return self.DoNotShowThisBook(title) + return self:DoNotShowThisBook(title) end -- last book was more than our double-tap time ago? block. local now = GetGameTimeMilliseconds() if (now - self.previousBook.time) > DOUBLE_TAP_TIME then - return self.DoNotShowThisBook(title) + return self:DoNotShowThisBook(title) end -- otherwise record this state for the future. @@ -119,36 +129,59 @@ function M:OnShowBookOverride(eventCode, title, body, medium, showTitle, bookId) end end -function M:SyncFromArchivementBookHistory() - local added = 0 - - for category = 1, GetNumLoreCategories() do - local _, numCollections, _ = GetLoreCategoryInfo(category) - for collection = 1, numCollections do - local _, _, _, numBooks, _, _, _ = GetLoreCollectionInfo(category, collection) - for book = 1, numBooks do - local title, _, known, id = GetLoreBookInfo(category, collection, book) - if known then - local body = ReadLoreBook(category, collection, book) - if not self:HaveSeenBookBefore(id, title, body) then - added = added + 1 - -- msg("book <<1>>: id=<<2>>(<<3>>) title=<<4>>(<<5>>)) body=<<6>>", added, type(id), id, type(title), title, HashString(body)) - end - end - end +function addon:ScanOneLoreCategory(category) + local _, numCollections, _ = GetLoreCategoryInfo(category) + self.async:For(1, numCollections):Do(function(collection) self:ScanOneLoreCollection(category, collection) end) +end + +function addon:ScanOneLoreCollection(category, collection) + local _, _, _, numBooks, _, _, _ = GetLoreCollectionInfo(category, collection) + self.async:For(1, numBooks):Do(function(book) self:ScanOneLoreBook(category, collection, book) end) +end + +function addon:ScanOneLoreBook(category, collection, book) + self.lore.scanned = self.lore.scanned + 1 + + local title, _, known, id = GetLoreBookInfo(category, collection, book) + if known then + local body = ReadLoreBook(category, collection, book) + if not self:HaveSeenBookBefore(id, title, body) then + self.lore.added = self.lore.added + 1 end end +end - if added > 0 then +function addon:ReportAfterLoreScan() + if self.lore.added > 0 then -- ZOS quirk: the number **must** be the third argument. the plural must -- be a substitution of text. - msg('added <<2>> <<m:1>> found in your achievements.', 'previously read book', added) + msg('added <<2>> <<m:1>> found in your achievements.', 'previously read book', self.lore.added) + end + + if not self.IS_RELEASE_VERSION then + local duration = FormatTimeMilliseconds( + GetGameTimeMilliseconds() - self.lore.start, + TIME_FORMAT_STYLE_DESCRIPTIVE_MINIMAL_SHOW_TENTHS_SECS, + TIME_FORMAT_PRECISION_TENTHS_RELEVANT, + TIME_FORMAT_DIRECTION_NONE) + msg('SyncFromLoreBooks: scan ran for <<1>> total', duration) end end -function M:OnAddonLoaded(name) - if name ~= M.ADDON_NAME then return end - EVENT_MANAGER:UnregisterForEvent(M.ADDON_NAME, EVENT_ADD_ON_LOADED) +function addon:SyncFromLoreBooks() + self.async = LibStub("LibAsync"):Create(self.NAME) + + self.lore.added = 0 + self.lore.scanned = 0 + self.lore.start = GetGameTimeMilliseconds() + + self.async:For(1, GetNumLoreCategories()):Do(function(category) self:ScanOneLoreCategory(category) end) + self.async:Then(function() self:ReportAfterLoreScan() end) +end + +function addon:OnAddonLoaded(name) + if name ~= addon.NAME then return end + EVENT_MANAGER:UnregisterForEvent(addon.NAME, EVENT_ADD_ON_LOADED) -- if the second argument, the version, changes then the data is wiped and -- replaced with the defaults. @@ -157,8 +190,18 @@ function M:OnAddonLoaded(name) -- replace the original event handler with ours; sadly, we don't have -- access to the original implementation to do anything nicer. :/ LORE_READER.control:UnregisterForEvent(EVENT_SHOW_BOOK) - LORE_READER.control:RegisterForEvent(EVENT_SHOW_BOOK, function(...) self:OnShowBookOverride(...) end) + LORE_READER.control:RegisterForEvent(EVENT_SHOW_BOOK, + function(...) self:OnShowBookOverride(...) end) + + -- and once we actually log in, scan the collections for missing records in + -- our data on what we have seen, since this is the only in-game history we + -- can use... + local function SyncFromLoreBooksShim(...) + EVENT_MANAGER:UnregisterForEvent(addon.NAME, EVENT_PLAYER_ACTIVATED) + addon:SyncFromLoreBooks() + end + EVENT_MANAGER:RegisterForEvent(addon.NAME, EVENT_PLAYER_ACTIVATED, SyncFromLoreBooksShim) end -- bootstrapping -EVENT_MANAGER:RegisterForEvent(M.ADDON_NAME, EVENT_ADD_ON_LOADED, function(_, name) M:OnAddonLoaded(name) end) +EVENT_MANAGER:RegisterForEvent(addon.NAME, EVENT_ADD_ON_LOADED, function(_, name) addon:OnAddonLoaded(name) end) diff --git a/SlippyCheezeReadItOnce.txt b/SlippyCheezeReadItOnce.txt index ceb5f2f..e37133a 100644 --- a/SlippyCheezeReadItOnce.txt +++ b/SlippyCheezeReadItOnce.txt @@ -5,6 +5,7 @@ ## AddOnVersion: 1000000 ## APIVersion: 100024 ## SavedVariables: SlippyCheezeReadItOnceData +## DependsOn: LibStub LibAsync SlippyCheezeReadItOnce.lua