mckenziemc@16: -- Core mckenziemc@17: -- Provides core functionality of Core mckenziemc@17: mckenziemc@17: mckenziemc@17: -- TODO: disable bootstrap if we load successfully? mckenziemc@17: -- TODO: implement a feature to disable unneeded libraries when a parent mckenziemc@17: -- is disabled? mckenziemc@0: mckenziemc@0: mckenziemc@0: local addonName, addonTable = ... mckenziemc@0: mckenziemc@0: mckenziemc@17: -- locals mckenziemc@17: local print = addonTable.print mckenziemc@17: local debug = addonTable.debug mckenziemc@17: local classes = addonTable.classes mckenziemc@17: mckenziemc@17: local AceHook = LibStub("AceHook-3.0") mckenziemc@17: local LibScriptLink = LibStub("LibScriptLink-1.0") mckenziemc@17: mckenziemc@17: mckenziemc@17: local Core = addonTable:NewClass("Core") mckenziemc@17: mckenziemc@17: mckenziemc@17: AceHook:Embed(Core) mckenziemc@17: mckenziemc@17: Core.queuedEnables = {} -- addons queued to be enabled after PLAYER_LOGIN mckenziemc@17: mckenziemc@17: mckenziemc@17: -- Does not consider user settings or addon errata. mckenziemc@17: function Core:IsForceLoadAvailable() mckenziemc@17: if IsLoggedIn() then mckenziemc@17: return false mckenziemc@17: else mckenziemc@17: return true mckenziemc@17: end mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:IsForceLoadAllowed() mckenziemc@17: -- TODO: check user settings mckenziemc@17: return true mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:CanForceLoad() mckenziemc@17: return self:IsForceLoadAvailable() and self:IsForceLoadAllowed() mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@18: function Core:CanLoadLate() mckenziemc@18: -- assume we've already logged in mckenziemc@18: return true mckenziemc@18: -- TODO: check user settings mckenziemc@18: end mckenziemc@18: mckenziemc@18: mckenziemc@17: -- Enables any dependencies needed by the addons mckenziemc@17: -- that have already been enabled mckenziemc@17: function Core:PrepareAllAddons() mckenziemc@17: for i=1, GetNumAddOns() do mckenziemc@17: local addon = classes.Addon:Get(i) mckenziemc@17: mckenziemc@17: -- TODO: what if an addon was loaded but its deps were then disabled? mckenziemc@17: if addon:IsEnabled() and not addon:IsLoaded() then mckenziemc@17: self:EnableAddOn(i) mckenziemc@17: end mckenziemc@17: end mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:SetHooks() mckenziemc@17: self:RawHook("EnableAddOn", true) mckenziemc@17: self:RawHook("LoadAddOn", true) mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: -- FIXME: use pcall in EnableAddOn and LoadAddOn, so that if my part errors, mckenziemc@17: -- it can still use the unhooked version mckenziemc@17: mckenziemc@17: function Core:EnableAddOn(...) mckenziemc@17: local id = ... mckenziemc@17: mckenziemc@17: debug("EnableAddOn", ...) mckenziemc@17: mckenziemc@17: -- even though we know EnableAddOn can cause force-loading before PLAYER_LOGIN, mckenziemc@17: -- DO NOT attempt to "fix" it: another addon that -does- know about mckenziemc@17: -- the different behavior might call our hook. mckenziemc@17: mckenziemc@17: if classes.Addon:Exists(id) then mckenziemc@17: local addon = classes.Addon:Get(id) mckenziemc@17: local tree = classes.Tree:Get(addon) mckenziemc@17: mckenziemc@17: local requestReload = false mckenziemc@17: mckenziemc@17: if self:CanForceLoad() then mckenziemc@17: -- NOTE: if we can force-load, then will enabling LoD addons cause them to load too? mckenziemc@17: -- A: no, they will still wait for LoadAddOn mckenziemc@17: mckenziemc@17: -- Can the addon be loaded on demand if force-loading is mckenziemc@17: -- allowed for its dependencies mckenziemc@17: -- if so, enable all deps and force-load if nec. mckenziemc@17: -- deps will get enabled if all parents are lod, force-loaded mckenziemc@17: -- if any parent can't be loaded on demand mckenziemc@17: -- else mckenziemc@17: -- if the addon is not loadable on demand but the tree can be mckenziemc@17: -- force-loaded, then force-load it all mckenziemc@17: -- deps will all get loaded since req. for root to load mckenziemc@17: -- else mckenziemc@17: -- if it can be loaded with a reloadui then prepare after login mckenziemc@17: -- else mckenziemc@17: -- it can't be loaded, maybe tell the user mckenziemc@17: mckenziemc@18: debug("EnableAddOn hook, checking", addon:GetName()) mckenziemc@18: mckenziemc@17: if tree:CanForceLoad() then mckenziemc@17: if addon:CanLoD() then mckenziemc@17: tree:PrepareForLoD() mckenziemc@17: else mckenziemc@17: tree:ForceLoad() mckenziemc@17: end mckenziemc@17: elseif tree:CanLoad() then mckenziemc@17: tree:PrepareForLoad() mckenziemc@17: requestReload = true mckenziemc@17: else mckenziemc@17: -- TODO: tell user mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: --[[ mckenziemc@17: if tree:CanLoDWithForce() then mckenziemc@17: tree:PrepareForLoD() mckenziemc@17: elseif tree:CanForceLoad() then mckenziemc@17: tree:ForceLoad() mckenziemc@17: elseif tree:CanLoad() then mckenziemc@17: tree:PrepareForLoad() mckenziemc@17: requestReload = true mckenziemc@17: else mckenziemc@17: -- TODO: tell user mckenziemc@17: end mckenziemc@17: ]] mckenziemc@17: else mckenziemc@17: -- if it can be loaded on demand (deps are loaded or LoD) then mckenziemc@17: -- prepare it (enable all deps) mckenziemc@17: -- else mckenziemc@17: -- if it can be loaded (and isn't already) then mckenziemc@17: -- if force loading is available, we have to wait, then enable everything mckenziemc@17: -- else mckenziemc@17: -- prepare for reload (TODO: move this check and similar to PLAYER_LOGOUT) mckenziemc@17: -- else mckenziemc@17: -- can't be loaded, maybe tell the user mckenziemc@17: mckenziemc@17: if tree:CanLoD() then mckenziemc@17: tree:PrepareForLoad() mckenziemc@17: -- don't actually intend to reload, just enable everything mckenziemc@18: elseif self:CanLoadLate() and tree:CanLoadLate() then mckenziemc@18: tree:LoadLate() mckenziemc@17: elseif tree:CanLoad() then mckenziemc@17: tree:PrepareForLoad() mckenziemc@17: requestReload = true mckenziemc@17: else mckenziemc@17: -- TODO: tell user mckenziemc@17: end mckenziemc@17: end mckenziemc@17: mckenziemc@17: if requestReload then mckenziemc@17: self:RequestReload() mckenziemc@17: end mckenziemc@17: end mckenziemc@17: mckenziemc@17: -- propogate the call even if it doesn't exist or deps are unavailable mckenziemc@17: return self:RawEnableAddOn(...) mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: mckenziemc@17: --- Prepares the addon tree rooted at the specified addon mckenziemc@17: function Core:LoadAddOn(...) mckenziemc@17: local id = ... mckenziemc@17: mckenziemc@17: debug("LoadAddOn", ...) mckenziemc@17: mckenziemc@17: if classes.Addon:Exists(id) then mckenziemc@17: local addon = classes.Addon:Get(id) mckenziemc@17: local tree = classes.Tree:Get(addon) mckenziemc@17: mckenziemc@17: if tree:CanLoD() then mckenziemc@17: tree:PrepareForLoD() mckenziemc@17: elseif tree:CanLoad() then mckenziemc@17: tree:PrepareForLoad() mckenziemc@17: -- TODO: request reload mckenziemc@17: end mckenziemc@17: end mckenziemc@17: mckenziemc@17: -- call even if it can't be loaded so regular returns appear mckenziemc@17: return self:RawLoadAddOn(...) mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:RequestReload() mckenziemc@17: -- TODO: this should be throtled so that it can mckenziemc@17: -- occur more than once but not within a short time mckenziemc@17: mckenziemc@17: debug("reload requested (NYI)") mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: -- name or index mckenziemc@17: function Core:QueueEnable(addon) mckenziemc@17: self.queuedEnables[addon] = true mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:RawEnableAddOn(...) mckenziemc@18: debug("RawEnableAddOn: enabling", ...) mckenziemc@17: return self.hooks.EnableAddOn(...) mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:RawLoadAddOn(...) mckenziemc@17: return self.hooks.LoadAddOn(...) mckenziemc@17: end mckenziemc@17: mckenziemc@17: mckenziemc@17: function Core:ProcessEnableQueue() mckenziemc@17: for addon in pairs(self.queuedEnables) do mckenziemc@17: self:RawEnableAddOn(addon) mckenziemc@17: self.queuedEnables[addon] = nil mckenziemc@17: end mckenziemc@17: end