vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[ |
2 | Name: RosterLib-2.0 |
||
3 | Revision: $Revision: 14114 $ |
||
4 | X-ReleaseDate: $Date: 2006-08-10 08:55:29 +0200 (Thu, 10 Aug 2006) $ |
||
5 | Author: Maia (maia.proudmoore@gmail.com) |
||
6 | Website: http://wiki.wowace.com/index.php/RosterLib-2.0 |
||
7 | Documentation: http://wiki.wowace.com/index.php/RosterLib-2.0_API_Documentation |
||
8 | SVN: http://svn.wowace.com/root/trunk/RosterLib-2.0/ |
||
9 | Description: party/raid roster management |
||
10 | Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0 |
||
11 | ]] |
||
12 | |||
13 | local MAJOR_VERSION = "RosterLib-2.0" |
||
14 | local MINOR_VERSION = "$Revision: 14114 $" |
||
15 | |||
16 | if not AceLibrary then error(vmajor .. " requires AceLibrary.") end |
||
17 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end |
||
18 | if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end |
||
19 | if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0") end |
||
20 | |||
21 | local updatedUnits = {} |
||
22 | local unknownUnits = {} |
||
23 | local RosterLib = {} |
||
24 | local roster |
||
25 | |||
26 | ------------------------------------------------ |
||
27 | -- activate, enable, disable |
||
28 | ------------------------------------------------ |
||
29 | |||
30 | local function print(text) |
||
31 | ChatFrame3:AddMessage(text) |
||
32 | end |
||
33 | |||
34 | local function activate(self, oldLib, oldDeactivate) |
||
35 | RosterLib = self |
||
36 | if oldLib then |
||
37 | self.roster = oldLib.roster |
||
38 | oldLib:UnregisterAllEvents() |
||
39 | oldLib:CancelAllScheduledEvents() |
||
40 | end |
||
41 | if not self.roster then self.roster = {} end |
||
42 | if oldDeactivate then oldDeactivate(oldLib) end |
||
43 | roster = self.roster |
||
44 | end |
||
45 | |||
46 | |||
47 | local function external(self, major, instance) |
||
48 | if major == "AceEvent-2.0" then |
||
49 | AceEvent = instance |
||
50 | AceEvent:embed(self) |
||
51 | self:UnregisterAllEvents() |
||
52 | self:CancelAllScheduledEvents() |
||
53 | if AceEvent:IsFullyInitialized() then |
||
54 | self:AceEvent_FullyInitialized() |
||
55 | else |
||
56 | self:RegisterEvent("AceEvent_FullyInitialized", "AceEvent_FullyInitialized", true) |
||
57 | end |
||
58 | elseif major == "Compost-2.0" then |
||
59 | Compost = instance |
||
60 | end |
||
61 | end |
||
62 | |||
63 | |||
64 | function RosterLib:Enable() |
||
65 | -- not used anymore, but as addons still might be calling this method, we're keeping it. |
||
66 | end |
||
67 | |||
68 | |||
69 | function RosterLib:Disable() |
||
70 | -- not used anymore, but as addons still might be calling this method, we're keeping it. |
||
71 | end |
||
72 | |||
73 | ------------------------------------------------ |
||
74 | -- Internal functions |
||
75 | ------------------------------------------------ |
||
76 | |||
77 | function RosterLib:AceEvent_FullyInitialized() |
||
78 | self:TriggerEvent("RosterLib_Enabled") |
||
79 | self:RegisterEvent("RAID_ROSTER_UPDATE","ScanFullRoster") |
||
80 | self:RegisterEvent("PARTY_MEMBERS_CHANGED","ScanFullRoster") |
||
81 | self:RegisterEvent("UNIT_PET","ScanPet") |
||
82 | self:ScanFullRoster() |
||
83 | end |
||
84 | |||
85 | |||
86 | ------------------------------------------------ |
||
87 | -- Unit iterator |
||
88 | ------------------------------------------------ |
||
89 | |||
90 | local playersent, petsent, unitcount, petcount, pmem, rmem, unit |
||
91 | |||
92 | local function NextUnit() |
||
93 | -- STEP 1: pet |
||
94 | if not petsent then |
||
95 | petsent = true |
||
96 | if rmem == 0 then |
||
97 | unit = "pet" |
||
98 | if UnitExists(unit) then return unit end |
||
99 | end |
||
100 | end |
||
101 | -- STEP 2: player |
||
102 | if not playersent then |
||
103 | playersent = true |
||
104 | if rmem == 0 then |
||
105 | unit = "player" |
||
106 | if UnitExists(unit) then return unit end |
||
107 | end |
||
108 | end |
||
109 | -- STEP 3: raid units |
||
110 | if rmem > 0 then |
||
111 | -- STEP 3a: pet units |
||
112 | for i = petcount, rmem do |
||
113 | unit = string.format("raidpet%d", i) |
||
114 | petcount = petcount + 1 |
||
115 | if UnitExists(unit) then return unit end |
||
116 | end |
||
117 | -- STEP 3b: player units |
||
118 | for i = unitcount, rmem do |
||
119 | unit = string.format("raid%d", i) |
||
120 | unitcount = unitcount + 1 |
||
121 | if UnitExists(unit) then return unit end |
||
122 | end |
||
123 | -- STEP 4: party units |
||
124 | elseif pmem > 0 then |
||
125 | -- STEP 3a: pet units |
||
126 | for i = petcount, pmem do |
||
127 | unit = string.format("partypet%d", i) |
||
128 | petcount = petcount + 1 |
||
129 | if UnitExists(unit) then return unit end |
||
130 | end |
||
131 | -- STEP 3b: player units |
||
132 | for i = unitcount, pmem do |
||
133 | unit = string.format("party%d", i) |
||
134 | unitcount = unitcount + 1 |
||
135 | if UnitExists(unit) then return unit end |
||
136 | end |
||
137 | end |
||
138 | end |
||
139 | |||
140 | local function UnitIterator() |
||
141 | playersent, petsent, unitcount, petcount, pmem, rmem = false, false, 1, 1, GetNumPartyMembers(), GetNumRaidMembers() |
||
142 | return NextUnit |
||
143 | end |
||
144 | |||
145 | ------------------------------------------------ |
||
146 | -- Roster code |
||
147 | ------------------------------------------------ |
||
148 | |||
149 | |||
150 | function RosterLib:ScanFullRoster() |
||
151 | -- save all units we currently have, this way we can check who to remove from roster later. |
||
152 | local temp = Compost and Compost:Acquire() or {} |
||
153 | for name in pairs(roster) do |
||
154 | temp[name] = true |
||
155 | end |
||
156 | -- update data |
||
157 | for unitid in UnitIterator() do |
||
158 | local name = self:CreateOrUpdateUnit(unitid) |
||
159 | -- we successfully added a unit, so we don't need to remove it next step |
||
160 | if name then temp[name] = nil end |
||
161 | end |
||
162 | -- clear units we had in roster that either left the raid or are unknown for some reason. |
||
163 | for name in pairs(temp) do |
||
164 | self:RemoveUnit(name) |
||
165 | end |
||
166 | if Compost then Compost:Reclaim(temp) end |
||
167 | self:ProcessRoster() |
||
168 | end |
||
169 | |||
170 | |||
171 | function RosterLib:ScanPet(owner) |
||
172 | local unitid = self:GetPetFromOwner(owner) |
||
173 | if not unitid then |
||
174 | return |
||
175 | elseif not UnitExists(unitid) then |
||
176 | unknownUnits[unitid] = nil |
||
177 | -- find the pet in the roster we need to delete |
||
178 | for _,u in pairs(roster) do |
||
179 | if u.unitid == unitid then |
||
180 | self:RemoveUnit(u.name) |
||
181 | end |
||
182 | end |
||
183 | else |
||
184 | self:CreateOrUpdateUnit(unitid) |
||
185 | end |
||
186 | self:ProcessRoster() |
||
187 | end |
||
188 | |||
189 | |||
190 | function RosterLib:GetPetFromOwner(id) |
||
191 | -- convert party3 crap to raid IDs when in raid. |
||
192 | local owner = self:GetUnitIDFromUnit(id) |
||
193 | if not owner then |
||
194 | return |
||
195 | end |
||
196 | -- get ID |
||
197 | if string.find(owner,"raid") then |
||
198 | return string.gsub(owner, "raid", "raidpet") |
||
199 | elseif string.find(owner,"party") then |
||
200 | return string.gsub(owner, "party", "partypet") |
||
201 | elseif owner == "player" then |
||
202 | return "pet" |
||
203 | else |
||
204 | return nil |
||
205 | end |
||
206 | end |
||
207 | |||
208 | |||
209 | function RosterLib:ScanUnknownUnits() |
||
210 | local name |
||
211 | for unitid in pairs(unknownUnits) do |
||
212 | if UnitExists(unitid) then |
||
213 | name = self:CreateOrUpdateUnit(unitid) |
||
214 | else |
||
215 | unknownUnits[unitid] = nil |
||
216 | end |
||
217 | -- some pets never have a name. too bad for them, farewell! |
||
218 | if not name and string.find(unitid,"pet") then |
||
219 | unknownUnits[unitid] = nil |
||
220 | end |
||
221 | end |
||
222 | self:ProcessRoster() |
||
223 | end |
||
224 | |||
225 | |||
226 | function RosterLib:ProcessRoster() |
||
227 | if next(updatedUnits, nil) then |
||
228 | self:TriggerEvent("RosterLib_RosterChanged", updatedUnits) |
||
229 | for name in pairs(updatedUnits) do |
||
230 | local u = updatedUnits[name] |
||
231 | self:TriggerEvent("RosterLib_UnitChanged", u.unitid, u.name, u.class, u.subgroup, u.rank, u.oldname, u.oldunitid, u.oldclass, u.oldsubgroup, u.oldrank) |
||
232 | if Compost then Compost:Reclaim(updatedUnits[name]) end |
||
233 | updatedUnits[name] = nil |
||
234 | end |
||
235 | end |
||
236 | if next(unknownUnits, nil) then |
||
237 | self:CancelScheduledEvent("ScanUnknownUnits") |
||
238 | self:ScheduleEvent("ScanUnknownUnits",self.ScanUnknownUnits, 1, self) |
||
239 | end |
||
240 | end |
||
241 | |||
242 | |||
243 | function RosterLib:CreateOrUpdateUnit(unitid) |
||
244 | local old = nil |
||
245 | -- check for name |
||
246 | local name = UnitName(unitid) |
||
247 | if name and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING and not UnitIsCharmed(unitid) then |
||
248 | -- clear stuff |
||
249 | unknownUnits[unitid] = nil |
||
250 | -- return if a pet attempts to replace a player name |
||
251 | -- this doesnt fix the problem with 2 pets overwriting each other FIXME |
||
252 | if string.find(unitid,"pet") then |
||
253 | if roster[name] and roster[name].class ~= "pet" then |
||
254 | return name |
||
255 | end |
||
256 | end |
||
257 | -- save old data if existing |
||
258 | if roster[name] then |
||
259 | old = Compost and Compost:Acquire() or {} |
||
260 | old.name = roster[name].name |
||
261 | old.unitid = roster[name].unitid |
||
262 | old.class = roster[name].class |
||
263 | old.rank = roster[name].rank |
||
264 | old.subgroup = roster[name].subgroup |
||
265 | end |
||
266 | -- object |
||
267 | if not roster[name] then |
||
268 | roster[name] = Compost and Compost:Acquire() or {} |
||
269 | end |
||
270 | -- name |
||
271 | roster[name].name = name |
||
272 | -- unitid |
||
273 | roster[name].unitid = unitid |
||
274 | -- class |
||
275 | if string.find(unitid,"pet") then |
||
276 | roster[name].class = "PET" |
||
277 | else |
||
278 | _,roster[name].class = UnitClass(unitid) |
||
279 | end |
||
280 | -- subgroup and rank |
||
281 | if GetNumRaidMembers() > 0 then |
||
282 | local _,_,num = string.find(unitid, "(%d+)") |
||
283 | _,roster[name].rank,roster[name].subgroup = GetRaidRosterInfo(num) |
||
284 | else |
||
285 | roster[name].subgroup = 1 |
||
286 | roster[name].rank = 0 |
||
287 | end |
||
288 | -- compare data |
||
289 | if not old |
||
290 | or roster[name].name ~= old.name |
||
291 | or roster[name].unitid ~= old.unitid |
||
292 | or roster[name].class ~= old.class |
||
293 | or roster[name].subgroup ~= old.subgroup |
||
294 | or roster[name].rank ~= old.rank |
||
295 | then |
||
296 | updatedUnits[name] = Compost and Compost:Acquire() or {} |
||
297 | updatedUnits[name].oldname = (old and old.name) or nil |
||
298 | updatedUnits[name].oldunitid = (old and old.unitid) or nil |
||
299 | updatedUnits[name].oldclass = (old and old.class) or nil |
||
300 | updatedUnits[name].oldsubgroup = (old and old.subgroup) or nil |
||
301 | updatedUnits[name].oldrank = (old and old.rank) or nil |
||
302 | updatedUnits[name].name = roster[name].name |
||
303 | updatedUnits[name].unitid = roster[name].unitid |
||
304 | updatedUnits[name].class = roster[name].class |
||
305 | updatedUnits[name].subgroup = roster[name].subgroup |
||
306 | updatedUnits[name].rank = roster[name].rank |
||
307 | end |
||
308 | -- compost our table |
||
309 | if old and Compost then |
||
310 | Compost:Reclaim(old) |
||
311 | end |
||
312 | return name |
||
313 | else |
||
314 | unknownUnits[unitid] = true |
||
315 | return false |
||
316 | end |
||
317 | end |
||
318 | |||
319 | |||
320 | function RosterLib:RemoveUnit(name) |
||
321 | updatedUnits[name] = Compost and Compost:Acquire() or {} |
||
322 | updatedUnits[name].oldname = roster[name].name |
||
323 | updatedUnits[name].oldunitid = roster[name].unitid |
||
324 | updatedUnits[name].oldclass = roster[name].class |
||
325 | updatedUnits[name].oldsubgroup = roster[name].subgroup |
||
326 | updatedUnits[name].oldrank = roster[name].rank |
||
327 | if Compost then Compost:Reclaim(roster[name]) end |
||
328 | roster[name] = nil |
||
329 | end |
||
330 | |||
331 | |||
332 | ------------------------------------------------ |
||
333 | -- API |
||
334 | ------------------------------------------------ |
||
335 | |||
336 | function RosterLib:GetUnitIDFromName(name) |
||
337 | if roster[name] then |
||
338 | return roster[name].unitid |
||
339 | else |
||
340 | return nil |
||
341 | end |
||
342 | end |
||
343 | |||
344 | |||
345 | function RosterLib:GetUnitIDFromUnit(unit) |
||
346 | local name = UnitName(unit) |
||
347 | if name and roster[name] then |
||
348 | return roster[name].unitid |
||
349 | else |
||
350 | return nil |
||
351 | end |
||
352 | end |
||
353 | |||
354 | |||
355 | function RosterLib:GetUnitObjectFromName(name) |
||
356 | if roster[name] then |
||
357 | return roster[name] |
||
358 | else |
||
359 | return nil |
||
360 | end |
||
361 | end |
||
362 | |||
363 | |||
364 | function RosterLib:GetUnitObjectFromUnit(unit) |
||
365 | local name = UnitName(unit) |
||
366 | if roster[name] then |
||
367 | return roster[name] |
||
368 | else |
||
369 | return nil |
||
370 | end |
||
371 | end |
||
372 | |||
373 | |||
374 | function RosterLib:IterateRoster(pets) |
||
375 | local key |
||
376 | return function() |
||
377 | repeat |
||
378 | key = next(roster, key) |
||
379 | until (roster[key] == nil or pets or roster[key].class ~= "PET") |
||
380 | |||
381 | return roster[key] |
||
382 | end |
||
383 | end |
||
384 | |||
385 | |||
386 | AceLibrary:Register(RosterLib, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) |