0
- Copyright (C) 2007 Nymbia
0
- This program is free software; you can redistribute it and/or modify
0
- it under the terms of the GNU General Public License as published by
0
- the Free Software Foundation; either version 2 of the License, or
0
- (at your option) any later version.
0
- This program is distributed in the hope that it will be useful,
0
- but WITHOUT ANY WARRANTY; without even the implied warranty of
0
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0
- GNU General Public License for more details.
0
- You should have received a copy of the GNU General Public License along
0
- with this program; if not, write to the Free Software Foundation, Inc.,
0
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
0
-local L = AceLibrary("AceLocale-2.2"):new("AddonLoader")
0
-AddonLoader = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceDB-2.0", "AceEvent-2.0", "AceModuleCore-2.0")
0
local AddonLoader = AddonLoader
0
-AddonLoader.slashes = {}
0
-AddonLoader:SetModuleMixins("AceEvent-2.0", "AceDB-2.0", "AceHook-2.1")
0
-AddonLoader:RegisterDB("AddonLoaderDB")
0
-local numaddons = GetNumAddOns()
0
-local GetAddOnInfo = GetAddOnInfo
0
-local GetAddOnMetadata = GetAddOnMetadata
0
+AddonLoader.events = {}
0
+AddonLoader.conditiontexts = {}
0
-local overridesvalidate = {
0
- [L.Always] = 'X-LoadOn-Always',
0
- [L.AuctionHouse] = 'X-LoadOn-AuctionHouse',
0
- [L.Arena] = 'X-LoadOn-Arena',
0
- [L.Bank] = 'X-LoadOn-Bank',
0
- [L.Battleground] = 'X-LoadOn-Battleground',
0
- [L.Combat] = 'X-LoadOn-Combat',
0
- [L.Crafting] = 'X-LoadOn-Crafting',
0
- [L.Group] = 'X-LoadOn-Group',
0
- [L.Guild] = 'X-LoadOn-Guild',
0
- [L.Instance] = 'X-LoadOn-Instance',
0
- [L.Mailbox] = 'X-LoadOn-Mailbox',
0
- [L.Merchant] = 'X-LoadOn-Merchant',
0
- [L.NotResting] = 'X-LoadOn-NotResting',
0
- [L.PvPFlagged] = 'X-LoadOn-PvPFlagged',
0
- [L.Raid] = 'X-LoadOn-Raid',
0
- [L.Resting] = 'X-LoadOn-Resting',
0
+local frame = CreateFrame("Frame", "AddonLoaderFrame")
0
+AddonLoader.frame = frame -- easy reference for use in X-LoadOn-Events
0
- desc = L["Show messages in the chat frame when addons are loaded"],
0
- return AddonLoader.db.profile.messages
0
- AddonLoader.db.profile.messages = v
0
- name = L["Overrides"],
0
- desc = L["Set alternate conditions for loading a given addon, overriding those in its toc file. NOTE: These settings do not take effect until a UI reload."],
0
+function AddonLoader:Print(text)
0
+ DEFAULT_CHAT_FRAME:AddMessage("|cFF33FF99AddonLoader|r: ".. tostring(text))
0
-function AddonLoader:ADDON_LOADED(addon)
0
- if addon=="ForkliftGnome" then -- Keep ForkliftGnome from doing the same work as AddonLoader (and generating errors!)
0
- ForkliftGnome.OnEnable = function() end
0
+function AddonLoader:AddCondition(condname, addonname, metatext)
0
+ if AddonLoader.conditions[condname] then
0
+ local cond = AddonLoader.conditions[condname]
0
+ for k, event in pairs(cond.events) do
0
+ if not AddonLoader.events[event] then
0
+ AddonLoader.events[event] = {}
0
+ frame:RegisterEvent(event)
0
+ if not AddonLoader.events[event][addonname] then
0
+ AddonLoader.events[event][addonname] = {}
0
+ AddonLoader.events[event][addonname][condname] = {
0
+ handler = cond.handler,
0
-function AddonLoader:OnInitialize()
0
- self:RegisterDefaults('profile', {
0
- self:RegisterChatCommand({'/addonloader','/aloader','/aload'}, options)
0
- self:RegisterEvent("ADDON_LOADED");
0
+-- scan all addons and their metadata for X-LoadOn directives.
0
+function AddonLoader:ScanAddons()
0
+ for i = 1, GetNumAddOns() do
0
+ if IsAddOnLoadOnDemand(i) and not IsAddOnLoaded(i) then
0
+ -- inject events with the correct handlers for all addons.
0
+ -- register for those events on our frame
0
+ local name = GetAddOnInfo(i)
0
+ for condname, cond in pairs(AddonLoader.conditions) do
0
+ local meta = GetAddOnMetadata(name, condname)
0
- local loadattempted = {}
0
- function handleLoadAddOn(addon)
0
- if tonumber(addon) then
0
- addon = GetAddOnInfo(addon)
0
- if loadattempted[addon] then
0
- loadattempted[addon] = true
0
- if options.args.overrides.args[addon] then
0
- if IsAddOnLoaded(addon) then
0
- if AddonLoader.db.profile.messages then
0
- AddonLoader:Print(L["Loaded %s."]:format(addon));
0
+ -- build the textblock as base for overrides
0
+ if not AddonLoader.conditiontexts[name] then
0
+ AddonLoader.conditiontexts[name] = ""
0
- local name, _,_, enabled = GetAddOnInfo(addon);
0
- if name and not enabled then
0
- local _, reason = LoadAddOn(addon)
0
- AddonLoader:Print(L["Failed to load %s: %s."]:format(addon, reason));
0
- for name, module in AddonLoader:IterateModules() do
0
- if not module.off then
0
- local t = module.addons
0
- elseif t and t[addon] then
0
+ AddonLoader.conditiontexts[name] = AddonLoader.conditiontexts[name] .. condname..": "..meta.."\n"
0
+ -- special handling for hook and events
0
+ if condname == "X-LoadOn-Events" or condname == "X-LoadOn-Hooks" then
0
+ for item in meta:gmatch("[^ ,]+") do
0
+ local metaitem = GetAddOnMetadata(name, "X-LoadOn-"..item)
0
+ AddonLoader.conditiontexts[name] = AddonLoader.conditiontexts[name].."X-LoadOn-"..item..": "..metaitem.."\n"
0
+ elseif condname == "X-LoadOn-Execute" then -- special handling for execute
0
+ local metaitem = GetAddOnMetadata(name, "X-LoadOn-Execute"..i)
0
+ AddonLoader.conditiontexts[name] = AddonLoader.conditiontexts[name].."X-LoadOn-Execute"..i..": "..metaitem.."\n"
0
+ AddonLoader:AddCondition(condname, name, meta)
0
- for _, v in ipairs(AddonLoader.slashes) do
0
- hash_SlashCmdList[v] = nil
0
- local function get(addon)
0
- local value = AddonLoader.db.profile.overrides[addon]
0
+-- this will be called at PLAYER_LOGIN at which point the saved vars should be present
0
+function AddonLoader:LoadOverrides()
0
+ if not AddonLoaderSV then
0
+ AddonLoaderSV = { -- overrides
0
+ AddonLoader.originals = {}
0
+ for k, v in pairs(AddonLoader.conditiontexts) do
0
+ AddonLoader.originals[k] = v
0
+ for addon, conditiontext in pairs(AddonLoaderSV.overrides) do
0
+ -- we have an addon lets clear the events for this addon and override unconditionaly.
0
+ for event, addons in pairs(AddonLoader.events) do
0
+ addons[addon] = nil -- nuke
0
- for k,v in pairs(overrides) do
0
+ AddonLoader.conditiontexts[addon] = conditiontext
0
+ -- we have a conditiontext override lets do it.
0
+ for line in conditiontext:gmatch("[^\n]+") do
0
+ local condname, text = string.match(line, "^([^:]*): (.*)$")
0
+ if condname and text then
0
+ AddonLoader:AddCondition(condname, addon, text)
0
- local function set(addon,v)
0
- AddonLoader.db.profile.overrides[addon] = false
0
- AddonLoader.db.profile.overrides[addon] = overrides[v]
0
+function AddonLoader:LoadAddOn(name)
0
+ -- Verify that the addon isn't disabled
0
+ local enabled = select(4, GetAddOnInfo(name))
0
+ if not enabled then return false end
0
+ if not AddonLoaderSV.silent then
0
+ AddonLoader:Print("Loading " .. name)
0
- function AddonLoader:OnEnable(first)
0
- hooksecurefunc('LoadAddOn', handleLoadAddOn)
0
- local metadatafields = self.metadatafields
0
- local overrides = self.db.profile.overrides
0
- local options = options.args.overrides.args
0
- for i = 1, numaddons do
0
- if IsAddOnLoadOnDemand(i) then
0
- local name = GetAddOnInfo(i)
0
- if overrides[name] and overrides[name] == 'X-LoadOn-Always' then
0
- metadatafields[overrides[name]](name)
0
- elseif overrides[name] then
0
- metadatafields[overrides[name]](name)
0
- local metadata = GetAddOnMetadata(i, 'X-LoadOn-Slash')
0
- metadatafields['X-LoadOn-Slash'](name, metadata)
0
- local metadata = GetAddOnMetadata(i, 'X-LoadOn-Execute')
0
- metadatafields['X-LoadOn-Execute'](name, metadata)
0
- alreadyloaded = not not IsAddOnLoaded(i)
0
- for k,v in pairs(metadatafields) do
0
- local metadata = GetAddOnMetadata(i, k)
0
- if not alreadyloaded then
0
+ local succ, err = LoadAddOn(name)
0
+ AddonLoader:Print("Error loading " .. name .. " (" .. err .. ")")
0
+local function OnEvent(this, event, ...)
0
+ if event == "PLAYER_LOGIN" then
0
+ AddonLoader:ScanAddons()
0
+ AddonLoader:LoadOverrides()
0
+ if AddonLoader.events[event] then
0
+ for name, conditions in pairs(AddonLoader.events[event]) do
0
+ if not IsAddOnLoaded(name) then
0
+ for condname, condition in pairs(conditions) do
0
+ if condition.handler(event, name, condition.arg, ...) then
0
+ AddonLoader:LoadAddOn(name)
0
- desc = L["Set the loading condition for %s. NOTE: Does not take effect until a UI reload."]:format(name),
0
- validate = overridesvalidate,
0
- disabled = alreadyloaded,
0
+ -- we do a lazy cleanup here
0
+ -- if an addon gets loaded by means other than AddonLoader it will be removed from the events list upon next firing of the event.
0
+ if IsAddOnLoaded(name) then -- cleanup
0
+ AddonLoader.events[event][name] = nil
0
+ local found = next(AddonLoader.events[event])
0
+ AddonLoader.events[event] = nil
0
+ frame:UnregisterEvent(event)
0
- self.metadatafields = nil
0
-function AddonLoader.modulePrototype:Disable()
0
- self:UnregisterAllEvents()
0
- if self.UnhookAll then
0
+frame:SetScript("OnEvent", OnEvent)
0
+frame:RegisterEvent("PLAYER_LOGIN")