--[[ Hello fellow addon developper, You will find bellow a way of adding custom book to Librarian. Prerequisite: To be sure your addon gets loaded after Librarian the easiest way is to add an optional dependency from your addon to Librarian If you are not used to it, you can copy this line to your Addon.txt file: ## OptionalDependsOn: Librarian ]] --[[ LIBRARIAN:RegisterNewCategory(name, totalBooks, GetBookInfo, OpenCategory) * Should be called at the end of your addon initialization - categoryIdentifier (*string*) : Identifier that will be used to identify your category from outside of the addon (save or API) You can use the same as the english name if you want - name (*string*) : Name of the category that will be displayed in the "Category" column - totalBooks (*integer*) : Total number of books in the category. Will be used when initializing Librarian with all the known book of your addon. If you want to disable this feature you can give 0 and the rest of the addon should still work) - GetBookInfo (*function*) : It is the main function that will be used to retrieve data for a book The bookIndex is an index starting from 1 to the total number of book or the maximum bookIndex received by the OnBookDisplayed function (it can't be more than 10000 though) Prototype: * GetBookInfo(*integer* bookIndex) ** _Returns:_ *string* _title_, *bool* _known_, *string* _body_, *[BookMedium|#BookMedium]* _medium_, *bool* _showTitle_ - OpenCategory (*function*, optional) : This is called when the player press the key to "Go to Category" from Librarian. So you should open your UI with the given book selected if you can. You can give nil instead, then the option won't be shown to the player Prototype: * OpenCategory(*integer* bookIndex) ]] function Librarian:RegisterNewCategory(categoryIdentifier, name, totalBooks, GetBookInfo, OpenCategory) if not self.globalSavedVars.registeredCollectionList then self.globalSavedVars.registeredCollectionList = {} self.globalSavedVars.nextCollectionToRegister = 1 end if not self.globalSavedVars.registeredCollectionList[categoryIdentifier] then self.globalSavedVars.registeredCollectionList[categoryIdentifier] = self.globalSavedVars.nextCollectionToRegister self.globalSavedVars.nextCollectionToRegister = self.globalSavedVars.nextCollectionToRegister + 1 end local newCollection = { collectionId = categoryIdentifier, name = name, totalBooks = totalBooks, GetBookInfo = GetBookInfo, OpenCategory = OpenCategory, } self.registeredCollection[self.globalSavedVars.registeredCollectionList[categoryIdentifier]] = newCollection self:RefreshData() end --[[ LIBRARIAN:OnBookDisplayed(categoryIdentifier, bookIndex) * Should be called when displaying a book with LoreReader UI * It will add the displayed book to Librarian and activate the read/unread icon and actions to lore reader - categoryIdentifier (string) : Identifier of the category you used when registering your new category - bookIndex (*integer*) : Index of the book shown in LoreReader and it will then be used with the GetBookInfo function you registered with your category ]] function Librarian:OnBookDisplayed(categoryIdentifier, bookIndex) for collectionIndex, collection in pairs(self.registeredCollection) do if collection.collectionId == categoryIdentifier then local title, _, body, medium, showTitle = collection.GetBookInfo(bookIndex) if title and body and medium then local bookId = self:GetCustomBookIdFromIndices(collectionIndex, bookIndex) Librarian.OnShowBook(eventCode, title, body, medium, showTitle, bookId) end return end end end ---------------------------------------------------------------------------------------------------------- -- INTERNAL (shouldn't be called from outside) -- -- Functions below are here to be able to switch between ESO official API and registered custom categories ---------------------------------------------------------------------------------------------------------- Librarian.constants.CUSTOM_CATEGORY = GetNumLoreCategories() + 1 Librarian.constants.CUSTOM_BOOK_ID_START = 200000 Librarian.constants.MAX_BOOK_PER_CUSTOM_COLLECTION = 10000 Librarian.registeredCollection = {} function Librarian:GetNumLoreCategories() if next(self.registeredCollection) == nil then return GetNumLoreCategories() else return Librarian.constants.CUSTOM_CATEGORY end end function Librarian:GetLoreCollectionCount(categoryIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then return select(2, GetLoreCategoryInfo(categoryIndex)) else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) return self.globalSavedVars.nextCollectionToRegister - 1 end end function Librarian:GetLoreCollectionName(categoryIndex, collectionIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then return select(1, GetLoreCollectionInfo(categoryIndex, collectionIndex)) else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] assert(collection) return collection.name end end function Librarian:GetLoreCollectionTotalBook(categoryIndex, collectionIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then return select(4, GetLoreCollectionInfo(categoryIndex, collectionIndex)) else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] if collection then return collection.totalBooks end end return 0 end function Librarian:IsLoreCollectionHidden(categoryIndex, collectionIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then return select(5, GetLoreCollectionInfo(categoryIndex, collectionIndex)) else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) assert(self.registeredCollection[collectionIndex]) return false end end function Librarian:CanOpenCollection(categoryIndex, collectionIndex) if categoryIndex and collectionIndex then if categoryIndex < self.constants.CUSTOM_CATEGORY then return collectionIndex ~= nil else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] assert(collection) return type(collection.OpenCategory) == "function" end end return false end function Librarian:OpenCollection(categoryIndex, collectionIndex, bookIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then local collectionId = select(7, GetLoreCollectionInfo(categoryIndex, collectionIndex)) LORE_LIBRARY:SetCollectionIdToSelect(collectionId) MAIN_MENU_KEYBOARD:ShowScene("loreLibrary") else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] assert(collection) collection.OpenCategory(bookIndex) end end function Librarian:GetBookInfo(categoryIndex, collectionIndex, bookIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then local title, _, known, bookId = GetLoreBookInfo(categoryIndex, collectionIndex, bookIndex) return title, known, bookId else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] assert(collection) local title, known = collection.GetBookInfo(bookIndex) local bookId = self:GetCustomBookIdFromIndices(collectionIndex, bookIndex) return title, known, bookId end end function Librarian:GetCustomBookIdFromIndices(collectionIndex, bookIndex) return self.constants.CUSTOM_BOOK_ID_START + collectionIndex * self.constants.MAX_BOOK_PER_CUSTOM_COLLECTION + bookIndex end function Librarian:GetLoreBookIndicesFromBookId(bookId) if bookId < self.constants.CUSTOM_BOOK_ID_START then return GetLoreBookIndicesFromBookId(bookId) else local bookIndexAndCollection = bookId - self.constants.CUSTOM_BOOK_ID_START local collectionIndex = math.floor(bookIndexAndCollection / self.constants.MAX_BOOK_PER_CUSTOM_COLLECTION) if self.registeredCollection[collectionIndex] then local bookIndex = bookIndexAndCollection - (collectionIndex * self.constants.MAX_BOOK_PER_CUSTOM_COLLECTION) return self.constants.CUSTOM_CATEGORY, collectionIndex, bookIndex end end return nil, nil, nil end function Librarian:ReadLoreBook(categoryIndex, collectionIndex, bookIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then return ReadLoreBook(categoryIndex, collectionIndex, bookIndex) else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] assert(collection) local _, _, body, medium, showTitle = collection.GetBookInfo(bookIndex) return body, medium, showTitle end end function Librarian:GetBookTitleAndBody(categoryIndex, collectionIndex, bookIndex) if categoryIndex < self.constants.CUSTOM_CATEGORY then local title = GetLoreBookInfo(categoryIndex, collectionIndex, bookIndex) local body = ReadLoreBook(categoryIndex, collectionIndex, bookIndex) return title, body else assert(categoryIndex == self.constants.CUSTOM_CATEGORY) local collection = self.registeredCollection[collectionIndex] assert(collection) local title, _, body = collection.GetBookInfo(bookIndex) return title, body end end