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.
402 lines
12 KiB
402 lines
12 KiB
--[[
|
|
Copyright (c) 2012-2016 Robin Schoonover
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to
|
|
deal in the Software without restriction, including without limitation the
|
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
sell copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
IN THE SOFTWARE.
|
|
]]
|
|
|
|
local MAJOR, MINOR = "LibPetJournal-2.0", 32
|
|
local lib, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
|
|
|
if not lib then return end
|
|
|
|
--
|
|
--
|
|
--
|
|
|
|
local _G = _G
|
|
local assert, GetTime, hooksecurefunc, ipairs, IsLoggedIn, pairs, tinsert, wipe
|
|
= assert, GetTime, hooksecurefunc, ipairs, IsLoggedIn, pairs, tinsert, wipe
|
|
local C_PetJournal = _G.C_PetJournal
|
|
|
|
local PJLU_TIMEOUT = 1
|
|
|
|
--
|
|
--
|
|
--
|
|
|
|
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
|
|
lib.event_frame = lib.event_frame or CreateFrame("FRAME")
|
|
lib.event_frame:UnregisterAllEvents()
|
|
lib.event_frame:SetScript("OnEvent", function(frame, event, ...)
|
|
frame[event](frame, ...)
|
|
end)
|
|
|
|
--
|
|
-- filter handling
|
|
--
|
|
|
|
do
|
|
local PJ_FLAG_FILTERS = {
|
|
[LE_PET_JOURNAL_FILTER_COLLECTED] = true,
|
|
[LE_PET_JOURNAL_FILTER_NOT_COLLECTED] = true,
|
|
}
|
|
|
|
|
|
lib._filter_hooks = lib._filter_hooks or {}
|
|
lib._filter_values = lib._filter_values or {}
|
|
lib._filter_values.flag_filters = lib._filter_values.flag_filters or {}
|
|
lib._filter_values.type_filters = lib._filter_values.type_filters or {}
|
|
lib._filter_values.source_filters = lib._filter_values.source_filters or {}
|
|
|
|
local filter_values = lib._filter_values
|
|
local flag_filters = filter_values.flag_filters
|
|
local type_filters = filter_values.type_filters
|
|
local source_filters = filter_values.source_filters
|
|
|
|
-- hook C_PetJournal.SetSearchFilter
|
|
if not lib._filter_hooks.SetSearchFilter then
|
|
hooksecurefunc(C_PetJournal, "SetSearchFilter", function(...)
|
|
lib._filter_hooks.SetSearchFilter(...)
|
|
end)
|
|
end
|
|
lib._filter_hooks.SetSearchFilter = function(str)
|
|
filter_values.last_search_filter = str
|
|
end
|
|
|
|
-- hook C_PetJournal.ClearSearchFilter
|
|
if not lib._filter_hooks.ClearSearchFilter then
|
|
hooksecurefunc(C_PetJournal, "ClearSearchFilter", function(...)
|
|
lib._filter_hooks.ClearSearchFilter(...)
|
|
end)
|
|
end
|
|
lib._filter_hooks.ClearSearchFilter = function()
|
|
filter_values.last_search_filter = ""
|
|
end
|
|
|
|
--- Save and clear the PetJournal filters.
|
|
-- Also prevents LibPetJournal or the PetJournal from reacting to filter
|
|
-- events until :RestoreFilters() is called. This is called
|
|
-- automatically by LibPetJournal.
|
|
-- @name LibPetJournal:ClearFilters()
|
|
function lib:ClearFilters()
|
|
local has_changes = false
|
|
|
|
assert(not lib._filters_cleared, "ClearFilters() already called")
|
|
lib._filters_cleared = true
|
|
|
|
if _G.PetJournal then
|
|
_G.PetJournal:UnregisterEvent("PET_JOURNAL_LIST_UPDATE")
|
|
end
|
|
|
|
for flag, value in pairs(PJ_FLAG_FILTERS) do
|
|
flag_filters[flag] = C_PetJournal.IsFilterChecked(flag)
|
|
if flag_filters[flag] ~= value then
|
|
C_PetJournal.SetFilterChecked(flag, value)
|
|
has_changes = true
|
|
end
|
|
end
|
|
|
|
local need_add_all = false
|
|
local ntypes = C_PetJournal.GetNumPetTypes()
|
|
for i=1,ntypes do
|
|
type_filters[i] = C_PetJournal.IsPetTypeChecked(i)
|
|
if not type_filters[i] then
|
|
need_add_all = true
|
|
end
|
|
end
|
|
if need_add_all then
|
|
C_PetJournal.SetAllPetTypesChecked(true)
|
|
has_changes = true
|
|
end
|
|
|
|
need_add_all = false
|
|
local nsources = C_PetJournal.GetNumPetSources()
|
|
for i=1,nsources do
|
|
source_filters[i] = C_PetJournal.IsPetSourceChecked(i)
|
|
if not source_filters[i] then
|
|
need_add_all = true
|
|
end
|
|
end
|
|
if need_add_all then
|
|
C_PetJournal.SetAllPetSourcesChecked(true)
|
|
has_changes = true
|
|
end
|
|
|
|
if filter_values.last_search_filter == nil then
|
|
-- There's no way to actually get the current search filter without hooking it,
|
|
-- and anyone loading earlier (especially if we are LOD) could have set it
|
|
-- before our hook, so always clear the first time
|
|
filter_values.last_search_filter = ""
|
|
C_PetJournal.ClearSearchFilter()
|
|
elseif filter_values.last_search_filter ~= "" then
|
|
filter_values.s_search_filter = filter_values.last_search_filter
|
|
C_PetJournal.ClearSearchFilter()
|
|
has_changes = true
|
|
else
|
|
filter_values.s_search_filter = nil
|
|
end
|
|
|
|
return has_changes
|
|
end
|
|
|
|
--- Restore PetJournal filters after a :ClearFilters() call.
|
|
-- Also reenables PetJournal and LibPetJournal reacting to the updated pet
|
|
-- journal event. This is called automatically by LibPetJournal.
|
|
-- @name LibPetJournal:RestoreFilters()
|
|
function lib:RestoreFilters()
|
|
assert(lib._filters_cleared, "ClearFilters() not called yet")
|
|
lib._filters_cleared = false
|
|
|
|
if filter_values.s_search_filter and filter_values.s_search_filter ~= "" then
|
|
C_PetJournal.SetSearchFilter(filter_values.s_search_filter)
|
|
end
|
|
|
|
for flag, value in pairs(flag_filters) do
|
|
if value ~= PJ_FLAG_FILTERS[flag] then
|
|
C_PetJournal.SetFilterChecked(flag, value)
|
|
end
|
|
end
|
|
|
|
for flag,value in pairs(type_filters) do
|
|
if value ~= true then
|
|
C_PetJournal.SetPetTypeFilter(flag, value)
|
|
end
|
|
end
|
|
|
|
for flag,value in pairs(source_filters) do
|
|
if value ~= true then
|
|
C_PetJournal.SetPetSourceChecked(flag, value)
|
|
end
|
|
end
|
|
|
|
if _G.PetJournal then
|
|
_G.PetJournal:RegisterEvent("PET_JOURNAL_LIST_UPDATE")
|
|
end
|
|
end
|
|
end
|
|
|
|
--
|
|
--
|
|
--
|
|
|
|
lib._petids = lib._petids or {}
|
|
lib._speciesids = lib._speciesids or {}
|
|
lib._set_speciesids = lib._set_speciesids or {}
|
|
lib._creatureids = lib._creatureids or {}
|
|
lib._set_creatureids = lib._set_creatureids or {}
|
|
|
|
lib._last_total = lib._last_total or 0
|
|
|
|
--- Get an iterator over the list of pet ids.
|
|
-- The specific order of pet ids returned should not be relied upon.
|
|
-- @name LibPetJournal:IteratePetIDs()
|
|
function lib:IteratePetIDs()
|
|
return ipairs(self._petids)
|
|
end
|
|
lib.IteratePetIds = lib.IteratePetIDs
|
|
|
|
--- Get an iterator over the list of species ids.
|
|
-- @name LibPetJournal:IterateSpeciesIDs()
|
|
function lib:IterateSpeciesIDs()
|
|
return ipairs(self._speciesids)
|
|
end
|
|
lib.IterateSpeciesIds = lib.IterateSpeciesIDs
|
|
|
|
--- Get an iterator over the list of creature ids.
|
|
-- @name LibPetJournal:IterateCreatureIDs()
|
|
function lib:IterateCreatureIDs()
|
|
return ipairs(self._creatureids)
|
|
end
|
|
|
|
--- Return the species id for a given creature id.
|
|
-- @name LibPetJournal:GetSpeciesIDForCreatureID()
|
|
function lib:GetSpeciesIDForCreatureID(creatureid)
|
|
return self._set_creatureids[creatureid]
|
|
end
|
|
|
|
local function loadPetsTimeout()
|
|
-- we were waiting for PJLU, but it never came
|
|
-- this should rarely happen!
|
|
|
|
if not lib._waiting or lib._timeout_started == nil then
|
|
return
|
|
end
|
|
|
|
if GetTime() - lib._timeout_started >= PJLU_TIMEOUT then
|
|
lib._waiting = false
|
|
if lib:_LoadPets() then
|
|
lib:_LoadPetsFinish()
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Load pets stored in the PetJournal.
|
|
-- Under normal circumstances with API will run on its own in response to
|
|
-- updates to the Pet Journal.
|
|
-- @name LibPetJournal:LoadPets()
|
|
function lib:LoadPets()
|
|
if self._running or lib._waiting then
|
|
return
|
|
end
|
|
|
|
lib._running = true
|
|
local filters_changed = self:ClearFilters()
|
|
|
|
if not filters_changed then
|
|
if self:_LoadPets() then
|
|
self:_LoadPetsFinish()
|
|
end
|
|
else
|
|
-- The collected/uncollected flags seem to no longer take effect immediately,
|
|
-- so we'll need to wait for PJLU to finish our work.
|
|
lib._waiting = true
|
|
lib._timeout_started = GetTime()
|
|
C_Timer.After(PJLU_TIMEOUT, loadPetsTimeout)
|
|
end
|
|
end
|
|
|
|
local function doLoadPets()
|
|
lib:LoadPets()
|
|
end
|
|
|
|
local function restoreAndRetryLater()
|
|
lib:RestoreFilters()
|
|
lib._running = false
|
|
C_Timer.After(0.1, doLoadPets)
|
|
end
|
|
|
|
function lib:_LoadPets()
|
|
wipe(lib._petids)
|
|
|
|
local total, owned = C_PetJournal.GetNumPets()
|
|
if total == 0 and owned == 0 then
|
|
restoreAndRetryLater()
|
|
return false
|
|
end
|
|
lib._last_total = total
|
|
|
|
-- scan pets
|
|
for i = 1,total do
|
|
local petID, speciesID, isOwned, _, _, _, _, _, _, _, creatureID = C_PetJournal.GetPetInfoByIndex(i)
|
|
|
|
if i == 1 and isOwned then
|
|
-- PetJournal has some weird consistency issues when the UI is loading.
|
|
-- GetPetInfoByPetID is not immediately ready, while GetPetInfoByIndex is.
|
|
-- This check only seems to need to happen once.
|
|
local _, _, _, _, _, _, _, name = C_PetJournal.GetPetInfoByPetID(petID)
|
|
|
|
if not name then
|
|
restoreAndRetryLater()
|
|
return false
|
|
end
|
|
end
|
|
|
|
if isOwned then
|
|
tinsert(self._petids, petID)
|
|
end
|
|
|
|
if not self._set_speciesids[speciesID] then
|
|
self._set_speciesids[speciesID] = true
|
|
tinsert(self._speciesids, speciesID)
|
|
end
|
|
|
|
if not self._set_creatureids[creatureID] then
|
|
self._set_creatureids[creatureID] = speciesID
|
|
tinsert(self._creatureids, creatureID)
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function lib:_LoadPetsFinish()
|
|
-- Signal
|
|
self.callbacks:Fire("PetListUpdated", self)
|
|
|
|
-- restore PJ filters
|
|
self:RestoreFilters()
|
|
|
|
-- Signal, part 2
|
|
self.callbacks:Fire("PostPetListUpdated", self)
|
|
|
|
self.event_frame:Hide()
|
|
self._running = false
|
|
end
|
|
|
|
--- Determine if the pet list has been loaded.
|
|
-- @name LibPetJournal:IsLoaded()
|
|
-- @return boolean indicating whether the pet list has been loaded.
|
|
function lib:IsLoaded()
|
|
return #self._petids > 0 or #self._speciesids > 0
|
|
end
|
|
|
|
--- Determine how many pets the player owns.
|
|
-- @name LibPetJournal:NumPets()
|
|
-- @return number of owned pets
|
|
function lib:NumPets()
|
|
return #self._petids
|
|
end
|
|
|
|
--- Determine how many owned and unowned species are exposed to the player.
|
|
-- @name LibPetJournal:NumSpecies()
|
|
-- @return number of species in the PetJournal
|
|
function lib:NumSpecies()
|
|
return #self._speciesids
|
|
end
|
|
|
|
lib.event_frame:RegisterEvent("PET_JOURNAL_LIST_UPDATE")
|
|
function lib.event_frame:PET_JOURNAL_LIST_UPDATE()
|
|
if not IsLoggedIn() then
|
|
return
|
|
end
|
|
|
|
if lib._waiting then
|
|
lib._waiting = false
|
|
if lib:_LoadPets() then
|
|
lib:_LoadPetsFinish()
|
|
end
|
|
return
|
|
end
|
|
|
|
local total, owned = C_PetJournal.GetNumPets()
|
|
if lib._last_owned ~= owned then
|
|
lib._last_owned = owned
|
|
lib:LoadPets()
|
|
elseif total > lib._last_total then
|
|
C_Timer.After(0.1, doLoadPets)
|
|
end
|
|
|
|
lib.callbacks:Fire("PetsUpdated", self)
|
|
end
|
|
|
|
lib.event_frame:RegisterEvent("ADDON_LOADED")
|
|
function lib.event_frame:ADDON_LOADED()
|
|
lib.event_frame:UnregisterEvent("ADDON_LOADED")
|
|
|
|
if not IsLoggedIn() then
|
|
-- PJLU will come later
|
|
return
|
|
end
|
|
|
|
if not lib:IsLoaded() then
|
|
lib:LoadPets()
|
|
end
|
|
end
|
|
|
|
lib.event_frame:SetScript("OnUpdate", nil)
|
|
|