Mercurial > wow > dependencyloader
comparison DependencyLoader/DependencyLoader.lua @ 15:a46bf694050c
cleaned up Tree's methods a bit and improved documentation
Addon:Exists will now return false for Blizzard addons (needs to be handled better)
Addon.lua will now use the raw hooks from the interface module
fixed the inverted returns from IsForceLoadAvailable
EnableAddOn and LoadAddOn hooks will now skip the extra processing if the addon does not exist or is a Blizzard addon
moved the EnableAddOn queing to the interface
author | mckenziemc |
---|---|
date | Sat, 11 Dec 2010 01:48:39 -0800 |
parents | 78b28ebdc169 |
children |
comparison
equal
deleted
inserted
replaced
14:78b28ebdc169 | 15:a46bf694050c |
---|---|
1 -- DependencyLoader | 1 -- DependencyLoader |
2 -- | 2 -- |
3 | 3 |
4 -- TODO: disable bootstrap if we load successfully? | |
4 | 5 |
5 -- TODO: implement a feature to disable unneeded libraries when a parent | 6 -- TODO: implement a feature to disable unneeded libraries when a parent |
6 -- is disabled? | 7 -- is disabled? |
7 | 8 |
8 local addonName, addonTable = ... | 9 local addonName, addonTable = ... |
9 | 10 |
10 | 11 |
11 local DependencyLoader = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceHook-3.0") | 12 local DependencyLoader = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceHook-3.0", "AceEvent-3.0") |
12 _G[addonName] = DependencyLoader | 13 _G[addonName] = DependencyLoader |
13 | 14 |
14 addonTable.interface = DependencyLoader | 15 addonTable.interface = DependencyLoader |
16 | |
17 local classes = addonTable.classes | |
15 | 18 |
16 | 19 |
17 local LibPrint = LibStub("LibPrint-1.0") | 20 local LibPrint = LibStub("LibPrint-1.0") |
18 local LibScriptLink = LibStub("LibScriptLink-1.0") | 21 local LibScriptLink = LibStub("LibScriptLink-1.0") |
19 | 22 |
20 DependencyLoader.printStream = LibPrint:NewStream("DependencyLoader", "DpLdr", print) | 23 DependencyLoader.printStream = LibPrint:NewStream("DependencyLoader", "DpLdr", print) |
21 DependencyLoader.debugStream = LibPrint:NewStream("DependencyLoader", "DpLdr", "mcm") | 24 DependencyLoader.debugStream = LibPrint:NewStream("DependencyLoader", "DpLdr", "mcm") |
25 | |
26 DependencyLoader.queuedEnables = {} -- addons queued to be enabled after PLAYER_LOGIN | |
22 | 27 |
23 | 28 |
24 function DependencyLoader:Print(...) | 29 function DependencyLoader:Print(...) |
25 self.printStream:Print(...) | 30 self.printStream:Print(...) |
26 end | 31 end |
36 self:Enable() | 41 self:Enable() |
37 end | 42 end |
38 | 43 |
39 | 44 |
40 function DependencyLoader:OnEnable() | 45 function DependencyLoader:OnEnable() |
46 -- this may get called early so don't rely on | |
47 -- it as an indicator for PLAYER_LOGIN | |
48 | |
49 self:RegisterEvent("PLAYER_LOGIN") | |
50 | |
41 self:RawHook("LoadAddOn", true) | 51 self:RawHook("LoadAddOn", true) |
42 self:RawHook("EnableAddOn", true) | 52 self:RawHook("EnableAddOn", true) |
43 | 53 |
44 self:PrepareAllAddons() | 54 self:PrepareAllAddons() |
45 | 55 |
46 self:Print("Enabled", addonName) | 56 self:Print("Enabled", addonName) |
47 end | 57 end |
48 | 58 |
49 | 59 |
60 function DependencyLoader:PLAYER_LOGIN(...) | |
61 self:Debug(...) | |
62 | |
63 self:ProcessEnableQueue() | |
64 end | |
65 | |
66 | |
50 function DependencyLoader:OnDisable() | 67 function DependencyLoader:OnDisable() |
51 self:Print("Disabled", addonName) | 68 self:Print("Disabled", addonName) |
52 end | 69 end |
53 | 70 |
54 | 71 |
55 -- Does not consider user settings or addon errata. | 72 -- Does not consider user settings or addon errata. |
56 function DependencyLoader:IsForceLoadAvailable() | 73 function DependencyLoader:IsForceLoadAvailable() |
57 return IsLoggedIn() and true or false | 74 if IsLoggedIn() then |
75 return false | |
76 else | |
77 return true | |
78 end | |
58 end | 79 end |
59 | 80 |
60 | 81 |
61 function DependencyLoader:IsForceLoadAllowed() | 82 function DependencyLoader:IsForceLoadAllowed() |
62 -- TODO: check user settings | 83 -- TODO: check user settings |
73 -- that have already been enabled | 94 -- that have already been enabled |
74 function DependencyLoader:PrepareAllAddons() | 95 function DependencyLoader:PrepareAllAddons() |
75 local requestReload = false | 96 local requestReload = false |
76 | 97 |
77 for i=1, GetNumAddOns() do | 98 for i=1, GetNumAddOns() do |
78 local addon = addonTable.classes.Addon:Get(i) | 99 local addon = classes.Addon:Get(i) |
79 | 100 |
80 -- TODO: what if an addon was loaded but its deps were then disabled? | 101 -- TODO: what if an addon was loaded but its deps were then disabled? |
81 if addon:IsEnabled() and not addon:IsLoaded() then | 102 if addon:IsEnabled() and not addon:IsLoaded() then |
82 self:EnableAddOn(addon:GetName()) | 103 self:EnableAddOn(addon:GetName()) |
83 end | 104 end |
90 end | 111 end |
91 ]] | 112 ]] |
92 end | 113 end |
93 | 114 |
94 | 115 |
116 -- FIXME: use pcall in EnableAddOn and LoadAddOn, so that if my part errors, | |
117 -- it can still use the unhooked version | |
118 | |
95 function DependencyLoader:EnableAddOn(...) | 119 function DependencyLoader:EnableAddOn(...) |
96 local id = ... | 120 local id = ... |
97 local addon = addonTable.classes.Addon:Get(id) | 121 |
98 local tree = addonTable.classes.Tree:Get(addon) | 122 self:Debug("EnableAddOn", ...) |
99 | 123 |
100 local requestReload = false | 124 -- even though we know EnableAddOn can cause force-loading before PLAYER_LOGIN, |
101 | 125 -- DO NOT attempt to "fix" it: another addon that -does- know about |
102 if self:CanForceLoad() then | 126 -- the different behavior might call our hook. |
103 -- NOTE: if we can force-load, then will enabling LoD addons cause them to load too? | 127 |
104 -- A: no, they will still wait for LoadAddOn | 128 if classes.Addon:Exists(id) then |
105 | 129 local addon = classes.Addon:Get(id) |
106 -- Can the addon be loaded on demand if force-loading is | 130 local tree = classes.Tree:Get(addon) |
107 -- allowed for its dependencies | 131 |
108 -- if so, enable all deps and force-load if nec. | 132 local requestReload = false |
109 -- deps will get enabled if all parents are lod, force-loaded | 133 |
110 -- if any parent can't be loaded on demand | 134 if self:CanForceLoad() then |
111 -- else | 135 -- NOTE: if we can force-load, then will enabling LoD addons cause them to load too? |
112 -- if the addon is not loadable on demand but the tree can be | 136 -- A: no, they will still wait for LoadAddOn |
113 -- force-loaded, then force-load it all | 137 |
114 -- deps will all get loaded since req. for root to load | 138 -- Can the addon be loaded on demand if force-loading is |
115 -- else | 139 -- allowed for its dependencies |
116 -- if it can be loaded with a reloadui then prepare after login | 140 -- if so, enable all deps and force-load if nec. |
117 -- else | 141 -- deps will get enabled if all parents are lod, force-loaded |
118 -- it can't be loaded, maybe tell the user | 142 -- if any parent can't be loaded on demand |
119 | 143 -- else |
120 if tree:CanLoDWithForce() then | 144 -- if the addon is not loadable on demand but the tree can be |
121 tree:PrepareForLoD() | 145 -- force-loaded, then force-load it all |
122 elseif tree:CanForceLoad() then | 146 -- deps will all get loaded since req. for root to load |
123 tree:ForceLoad() | 147 -- else |
124 elseif tree:CanLoad() then | 148 -- if it can be loaded with a reloadui then prepare after login |
125 tree:PrepareForReload() | 149 -- else |
126 requestReload = true | 150 -- it can't be loaded, maybe tell the user |
151 | |
152 if tree:CanForceLoad() then | |
153 if addon:CanLoD() then | |
154 tree:PrepareForLoD() | |
155 else | |
156 tree:ForceLoad() | |
157 end | |
158 elseif tree:CanLoad() then | |
159 tree:PrepareForLoad() | |
160 requestReload = true | |
161 else | |
162 -- TODO: tell user | |
163 end | |
164 | |
165 | |
166 --[[ | |
167 if tree:CanLoDWithForce() then | |
168 tree:PrepareForLoD() | |
169 elseif tree:CanForceLoad() then | |
170 tree:ForceLoad() | |
171 elseif tree:CanLoad() then | |
172 tree:PrepareForLoad() | |
173 requestReload = true | |
174 else | |
175 -- TODO: tell user | |
176 end | |
177 ]] | |
127 else | 178 else |
128 -- TODO: tell user | 179 -- if it can be loaded on demand (deps are loaded or LoD) then |
129 end | 180 -- prepare it (enable all deps) |
130 else | 181 -- else |
131 -- if it can be loaded on demand (deps are loaded or LoD) then | 182 -- if it can be loaded (and isn't already) then |
132 -- prepare it (enable all deps) | 183 -- if force loading is available, we have to wait, then enable everything |
133 -- else | 184 -- else |
134 -- if it can be loaded (and isn't already) then | 185 -- prepare for reload (TODO: move this check and similar to PLAYER_LOGOUT) |
135 -- if force loading is available, we have to wait, then enable everything | 186 -- else |
136 -- else | 187 -- can't be loaded, maybe tell the user |
137 -- prepare for reload (TODO: move this check and similar to PLAYER_LOGOUT) | 188 |
138 -- else | 189 if tree:CanLoD() then |
139 -- can't be loaded, maybe tell the user | 190 tree:PrepareForLoad() |
140 | 191 -- don't actually intend to reload, just enable everything |
141 if tree:CanLoD() then | 192 elseif tree:CanLoad() then |
142 tree:PrepareForReload() | 193 tree:PrepareForLoad() |
143 -- don't actually intend to reload, just enable everything | 194 requestReload = true |
144 elseif tree:CanLoad() then | 195 else |
145 tree:PrepareForReload() | 196 -- TODO: tell user |
146 requestReload = true | 197 end |
147 else | 198 end |
148 -- TODO: tell user | 199 |
149 end | 200 if requestReload then |
150 end | 201 self:RequestReload() |
151 | 202 end |
152 -- TODO: requestReload | 203 end |
153 | 204 |
205 -- propogate the call even if it doesn't exist or deps are unavailable | |
154 return self.hooks.EnableAddOn(...) | 206 return self.hooks.EnableAddOn(...) |
155 end | 207 end |
156 | 208 |
157 | 209 |
158 | 210 |
159 --- Prepares the addon tree rooted at the specified addon | 211 --- Prepares the addon tree rooted at the specified addon |
160 function DependencyLoader:LoadAddOn(...) | 212 function DependencyLoader:LoadAddOn(...) |
161 local id = ... | 213 local id = ... |
162 | 214 |
163 local isBlizzardAddon = false | 215 self:Debug("LoadAddOn", ...) |
164 | 216 |
165 if type(id) == "string" and string.match(id, "Blizzard_") then | 217 if classes.Addon:Exists(id) then |
166 self:Debug("Asked to load Blizzard addon", id, ", skipping") | 218 local addon = classes.Addon:Get(id) |
167 isBlizzardAddon = true | 219 local tree = classes.Tree:Get(addon) |
168 end | |
169 | |
170 if not isBlizzardAddon then | |
171 local addon = addonTable.classes.Addon:Get(id) | |
172 local tree = addonTable.classes.Tree:Get(addon) | |
173 | 220 |
174 if tree:CanLoD() then | 221 if tree:CanLoD() then |
175 tree:PrepareForLoD() | 222 tree:PrepareForLoD() |
176 elseif tree:CanLoad() then | 223 elseif tree:CanLoad() then |
177 tree:PrepareForReload() | 224 tree:PrepareForReload() |
179 end | 226 end |
180 | 227 |
181 -- call even if it can't be loaded so regular returns appear | 228 -- call even if it can't be loaded so regular returns appear |
182 return self.hooks.LoadAddOn(...) | 229 return self.hooks.LoadAddOn(...) |
183 end | 230 end |
231 | |
232 | |
233 function DependencyLoader:RequestReload() | |
234 -- TODO: this should only run once | |
235 end | |
236 | |
237 | |
238 function DependencyLoader:QueueEnable(name) | |
239 self.queuedEnables[name] = true | |
240 end | |
241 | |
242 | |
243 function DependencyLoader:RawEnableAddOn(...) | |
244 return self.hooks.EnableAddOn(...) | |
245 end | |
246 | |
247 | |
248 function DependencyLoader:RawLoadAddOn(...) | |
249 return self.hooks.LoadAddOn(...) | |
250 end | |
251 | |
252 | |
253 function DependencyLoader:ProcessEnableQueue() | |
254 for addon in pairs(self.queuedEnables) do | |
255 self:RawEnableAddOn(addon) | |
256 self.queuedEnables[addon] = nil | |
257 end | |
258 end |