mckenziemc@0
|
1 -- Addon
|
mckenziemc@0
|
2 -- Represents individual addon modules
|
mckenziemc@0
|
3
|
mckenziemc@0
|
4
|
mckenziemc@0
|
5 local addonName, addonTable = ...
|
mckenziemc@0
|
6
|
mckenziemc@0
|
7
|
mckenziemc@0
|
8 -- NOTE: I assume that the API addon functions are
|
mckenziemc@0
|
9 -- slightly quicker with an index than with a number.
|
mckenziemc@0
|
10
|
mckenziemc@0
|
11 -- TODO: modify the dependency stuff to use the Errata module if available
|
mckenziemc@0
|
12
|
mckenziemc@0
|
13 local Addon, addon = addonTable:NewClass("Addon")
|
mckenziemc@0
|
14
|
mckenziemc@8
|
15
|
mckenziemc@8
|
16 -- load ability masks
|
mckenziemc@8
|
17 Addon.loadMasks = {
|
mckenziemc@8
|
18 reload = bit.lshift(1, 0), -- can load after reloadui
|
mckenziemc@8
|
19 ondemand = bit.lshift(1, 1), -- can load on demand
|
mckenziemc@8
|
20 forceafter = bit.lshift(1, 2), -- force load after it would normally be loaded
|
mckenziemc@8
|
21 forcebefore = bit.lshift(1, 3), -- force load before it would normally be loaded
|
mckenziemc@8
|
22 }
|
mckenziemc@8
|
23
|
mckenziemc@8
|
24
|
mckenziemc@8
|
25 Addon.addons = {}
|
mckenziemc@8
|
26 Addon.nameToIndex = {}
|
mckenziemc@8
|
27
|
mckenziemc@8
|
28
|
mckenziemc@8
|
29 -- Internal function
|
mckenziemc@8
|
30 -- Creates a new Addon object
|
mckenziemc@8
|
31 -- @param id Name or index of the addon.
|
mckenziemc@0
|
32 function Addon:New(id)
|
mckenziemc@0
|
33 local instance = {}
|
mckenziemc@0
|
34 setmetatable(instance, self.instanceMetatable)
|
mckenziemc@0
|
35
|
mckenziemc@0
|
36 if type(id) == "number" then
|
mckenziemc@0
|
37 -- TODO: make sure it's in range
|
mckenziemc@0
|
38 instance.index = id
|
mckenziemc@0
|
39 instance.name = GetAddOnInfo(id)
|
mckenziemc@0
|
40 else
|
mckenziemc@0
|
41 -- FIXME: allow blizzard addons?
|
mckenziemc@0
|
42 local index
|
mckenziemc@0
|
43
|
mckenziemc@0
|
44 for i=1,GetNumAddOns() do
|
mckenziemc@0
|
45 if GetAddOnInfo(i) == id then
|
mckenziemc@0
|
46 index = i
|
mckenziemc@0
|
47 break
|
mckenziemc@0
|
48 end
|
mckenziemc@0
|
49 end
|
mckenziemc@0
|
50
|
mckenziemc@0
|
51 if index then
|
mckenziemc@0
|
52 instance.name = GetAddOnInfo(id)
|
mckenziemc@0
|
53 instance.index = index
|
mckenziemc@0
|
54 else
|
mckenziemc@0
|
55 error("Addon not found")
|
mckenziemc@0
|
56 end
|
mckenziemc@0
|
57 end
|
mckenziemc@0
|
58
|
mckenziemc@0
|
59 return instance
|
mckenziemc@0
|
60 end
|
mckenziemc@0
|
61
|
mckenziemc@0
|
62
|
mckenziemc@8
|
63 --- Retrieves an Addon object.
|
mckenziemc@8
|
64 -- @param id Name or index of the addon to retrieve.
|
mckenziemc@8
|
65 -- @return The Addon object, or nil if not found.
|
mckenziemc@8
|
66 function Addon:Get(id)
|
mckenziemc@8
|
67 if not self:Exists(id) then
|
mckenziemc@8
|
68 return nil
|
mckenziemc@8
|
69 end
|
mckenziemc@8
|
70
|
mckenziemc@8
|
71 if type(id) == "number" then
|
mckenziemc@8
|
72 if self.addons[id] ~= nil then
|
mckenziemc@8
|
73 return self.addons[id]
|
mckenziemc@8
|
74 end
|
mckenziemc@8
|
75
|
mckenziemc@8
|
76 local new = self:New(id)
|
mckenziemc@8
|
77 self.addons[new:GetIndex()] = new
|
mckenziemc@8
|
78 self.nameToIndex[new:GetName()] = id
|
mckenziemc@8
|
79
|
mckenziemc@8
|
80 return new
|
mckenziemc@8
|
81 elseif type(id) == "string" then
|
mckenziemc@8
|
82 if self.nameToIndex[id] then
|
mckenziemc@8
|
83 return self.addons[self.nameToIndex[id] ]
|
mckenziemc@8
|
84 end
|
mckenziemc@8
|
85
|
mckenziemc@8
|
86 local new = self:New(id)
|
mckenziemc@8
|
87 self.addons[new:GetIndex()] = new
|
mckenziemc@8
|
88 self.nameToIndex[id] = new:GetIndex()
|
mckenziemc@8
|
89
|
mckenziemc@8
|
90 return new
|
mckenziemc@8
|
91 end
|
mckenziemc@8
|
92 end
|
mckenziemc@8
|
93
|
mckenziemc@0
|
94 -- Checks if an addon exists with the specified name.
|
mckenziemc@0
|
95 -- @param addon Name of the addon.
|
mckenziemc@0
|
96 -- @return True if the addon is present, false otherwise.
|
mckenziemc@0
|
97 function Addon:Exists(addon)
|
mckenziemc@0
|
98 if type(addon) == "number" then
|
mckenziemc@0
|
99 if addon >= 1 and addon <= GetNumAddOns() then
|
mckenziemc@0
|
100 return true
|
mckenziemc@0
|
101 else
|
mckenziemc@0
|
102 return false
|
mckenziemc@0
|
103 end
|
mckenziemc@0
|
104 elseif type(addon) == "string" then
|
mckenziemc@0
|
105 local status = select(6, GetAddOnInfo(addon))
|
mckenziemc@0
|
106
|
mckenziemc@0
|
107 if status == "MISSING" then
|
mckenziemc@0
|
108 return false
|
mckenziemc@0
|
109 else
|
mckenziemc@0
|
110 return true
|
mckenziemc@0
|
111 end
|
mckenziemc@0
|
112 else
|
mckenziemc@0
|
113 error()
|
mckenziemc@0
|
114 end
|
mckenziemc@0
|
115 end
|
mckenziemc@0
|
116
|
mckenziemc@0
|
117
|
mckenziemc@8
|
118 function Addon:GetLoadMasks()
|
mckenziemc@8
|
119 return self.masks
|
mckenziemc@8
|
120 end
|
mckenziemc@8
|
121
|
mckenziemc@8
|
122
|
mckenziemc@0
|
123 function addon:GetName()
|
mckenziemc@0
|
124 return self.name
|
mckenziemc@0
|
125 end
|
mckenziemc@0
|
126
|
mckenziemc@0
|
127
|
mckenziemc@0
|
128 function addon:GetIndex()
|
mckenziemc@0
|
129 return self.index
|
mckenziemc@0
|
130 end
|
mckenziemc@0
|
131
|
mckenziemc@0
|
132
|
mckenziemc@0
|
133 function addon:IsEnabled()
|
mckenziemc@0
|
134 -- FIXME: written while tired; review later
|
mckenziemc@0
|
135 local status = select(6, GetAddOnInfo(self.index))
|
mckenziemc@0
|
136
|
mckenziemc@0
|
137 if status == "DISABLED" then
|
mckenziemc@0
|
138 return false
|
mckenziemc@0
|
139 else
|
mckenziemc@0
|
140 return true
|
mckenziemc@0
|
141 end
|
mckenziemc@0
|
142 end
|
mckenziemc@0
|
143
|
mckenziemc@0
|
144
|
mckenziemc@8
|
145 function addon:GetLoadBitfield()
|
mckenziemc@8
|
146 local bitfield = 0
|
mckenziemc@8
|
147
|
mckenziemc@8
|
148 if self:CanLoad() then
|
mckenziemc@8
|
149 bitfield = bitfield + self.masks.reload
|
mckenziemc@8
|
150 end
|
mckenziemc@8
|
151
|
mckenziemc@8
|
152 if self:CanLoD() then
|
mckenziemc@8
|
153 bitfield = bitfield + self.masks.ondemand
|
mckenziemc@8
|
154 end
|
mckenziemc@8
|
155
|
mckenziemc@8
|
156 if self:CanForceLoadAfter() then
|
mckenziemc@8
|
157 bitfield = bitfield + self.masks.forceafter
|
mckenziemc@8
|
158 end
|
mckenziemc@8
|
159
|
mckenziemc@8
|
160 if self:CanForceLoadBefore() then
|
mckenziemc@8
|
161 bitfield = bitfield + self.masks.forcebefore
|
mckenziemc@8
|
162 end
|
mckenziemc@8
|
163
|
mckenziemc@8
|
164 return bitfield
|
mckenziemc@0
|
165 end
|
mckenziemc@0
|
166
|
mckenziemc@8
|
167
|
mckenziemc@8
|
168 --- Checks if the addon is loadable.
|
mckenziemc@8
|
169 -- Considers interface issues, missing, etc. (NYI)
|
mckenziemc@8
|
170 -- Does not check dependencies.
|
mckenziemc@8
|
171 function addon:CanLoad()
|
mckenziemc@8
|
172 -- FIXME: an addon may be present but unloadable if loading out of date addons is disabled.
|
mckenziemc@8
|
173 return true
|
mckenziemc@8
|
174 end
|
mckenziemc@8
|
175
|
mckenziemc@8
|
176
|
mckenziemc@0
|
177 function addon:CanLoD()
|
mckenziemc@0
|
178 -- FIXME: what will the client say about addons using LoadManagers if the LM was force-loaded?
|
mckenziemc@0
|
179 if IsAddOnLoadOnDemand(self.name) then
|
mckenziemc@0
|
180 return true
|
mckenziemc@0
|
181 else
|
mckenziemc@0
|
182 return false
|
mckenziemc@0
|
183 end
|
mckenziemc@0
|
184 end
|
mckenziemc@0
|
185
|
mckenziemc@8
|
186
|
mckenziemc@8
|
187 function addon:CanForceLoadAfter()
|
mckenziemc@8
|
188 -- TODO: check Errata module
|
mckenziemc@8
|
189 return false
|
mckenziemc@8
|
190 end
|
mckenziemc@8
|
191
|
mckenziemc@8
|
192
|
mckenziemc@8
|
193 function addon:CanForceLoadBefore()
|
mckenziemc@8
|
194 -- TODO: check Errata module
|
mckenziemc@8
|
195 return false -- TODO: check if there's any reason addons can't be forceloaded
|
mckenziemc@8
|
196 end
|
mckenziemc@8
|
197
|
mckenziemc@8
|
198
|
mckenziemc@8
|
199 function addon:Enable()
|
mckenziemc@8
|
200 -- FIXME: delay this till after PLAYER_LOGIN or it'll get force-loaded
|
mckenziemc@8
|
201 EnableAddOn(self.name)
|
mckenziemc@8
|
202 end
|
mckenziemc@8
|
203
|
mckenziemc@8
|
204
|
mckenziemc@0
|
205 -- NOTE: only call for LoD, not force-loading
|
mckenziemc@0
|
206 function addon:Load()
|
mckenziemc@0
|
207 assert(self:CanLoD())
|
mckenziemc@0
|
208
|
mckenziemc@0
|
209 EnableAddOn(self.name)
|
mckenziemc@0
|
210 LoadAddOn(self.name)
|
mckenziemc@0
|
211 end
|
mckenziemc@0
|
212
|
mckenziemc@8
|
213
|
mckenziemc@0
|
214 function addon:ForceLoad()
|
mckenziemc@0
|
215 assert(self:CanForceLoad())
|
mckenziemc@0
|
216 -- TODO: make sure force-loading is available at this time
|
mckenziemc@0
|
217
|
mckenziemc@0
|
218 EnableAddOn(self.name) -- This should cause the game to also load this addon
|
mckenziemc@0
|
219 end
|
mckenziemc@0
|
220
|
mckenziemc@0
|
221
|
mckenziemc@0
|
222 function addon:GetDependencies()
|
mckenziemc@8
|
223 -- TODO: consider no-lib embeds as deps?
|
mckenziemc@0
|
224 return GetAddOnDependencies(self.index)
|
mckenziemc@0
|
225 end
|
mckenziemc@0
|
226
|
mckenziemc@0
|
227
|
mckenziemc@0
|
228 function addon:GetEmbeds()
|
mckenziemc@0
|
229 local embeds = {}
|
mckenziemc@0
|
230
|
mckenziemc@0
|
231 local embedString = GetAddOnMetadata(self.name, "X-Embeds")
|
mckenziemc@0
|
232
|
mckenziemc@0
|
233 if embedString then
|
mckenziemc@0
|
234 for match in string.gmatch(embedString, "[^,%s]+") do
|
mckenziemc@0
|
235 table.insert(embeds, match)
|
mckenziemc@0
|
236 end
|
mckenziemc@0
|
237 end
|
mckenziemc@0
|
238
|
mckenziemc@0
|
239 return unpack(embeds)
|
mckenziemc@0
|
240 end
|
mckenziemc@0
|
241
|
mckenziemc@0
|
242 function addon:IsLoaded()
|
mckenziemc@0
|
243 if IsAddOnLoaded(self.index) then
|
mckenziemc@0
|
244 return true
|
mckenziemc@0
|
245 else
|
mckenziemc@0
|
246 return false
|
mckenziemc@0
|
247 end
|
mckenziemc@0
|
248 end
|