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