comparison gd.lua @ 1:f7c747904387

adding pkgmeta
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Mon, 01 Nov 2010 18:36:46 +0000
parents
children fb9a91642a60
comparison
equal deleted inserted replaced
0:a3b67ffe00a0 1:f7c747904387
1
2 local addon = CreateFrame("Frame") --select(2,...)
3 local SV
4
5 local DEFAULT_CHAT = 2 -- combat log (no constant predefined for that)
6
7 local l10n
8 --if GetLocale() == "enUS" then
9 l10n= {
10 ["LEFT"] = "Players who have left the guild: ",
11 ["JOINED"] = "Players who have joined the guild: ",
12 ["RANK"] = "Players whose rank has changed:",
13 ["LEVEL"] = "Players whose level has changed:",
14 ["NOTES"] = "Players whose notes have changed:",
15
16 ["Oabbrev"] = "O", -- abbreviation for "Officer", specifically the non-public note
17 ["FIELD_rank"] = "Rank",
18 ["FIELD_level"] = "Level",
19 ["FIELD_notes"] = "Player/Officer notes",
20
21 -- Something needs to be done about the walls of description text below.
22 }
23 --elseif .... end
24
25 local guild_selection, log_ever_shown
26 addon.options = {
27 name = "Guild Delta",
28 type = 'group',
29 handler = addon, -- functions listed as strings called as addon:func
30 args = {
31 version = {
32 --name = filled in during OnEnable
33 type = 'description',
34 fontSize = "large",
35 --image = "Interface\\AddOns\\GuildDelta\\test2",
36 cmdHidden = true,
37 order = 1,
38 },
39 note = {
40 --name = filled in locals section
41 type = 'description',
42 cmdHidden = true,
43 width = 'full',
44 order = 2,
45 },
46 reset = {
47 name = "Reset Output",
48 desc = "Restores default output settings",
49 type = 'execute',
50 order = 5,
51 func = "SetChat",
52 arg = DEFAULT_CHAT,
53 },
54 spacer2 = {
55 name = '',
56 type = 'description',
57 cmdHidden = true,
58 width = 'full',
59 order = 6,
60 },
61 print_chatframes = {
62 name = "Print Chatframe Numbers",
63 desc = "Print each chat window number in its frame, for easy reference in the next slider option",
64 type = 'execute',
65 --func = print_chatframes filled in below
66 order = 10,
67 },
68 chatframe_num = {
69 name = "Output Chatframe",
70 desc = "Which chat window to use for printing all the output during login",
71 type = 'range',
72 min = 1,
73 max = NUM_CHAT_WINDOWS,
74 step = 1,
75 get = function() return tonumber(SV.chatframe) or --[[in case of custom name]]DEFAULT_CHAT end,
76 set = "SetChat",
77 order = 15,
78 },
79 chatframe_name = {
80 name = "Chatframe Override",
81 desc = "<Advanced> If blank, uses the numerical slider. If set, it is the NAME of a frame with AddMessage capability to use for output.",
82 type = 'input',
83 get = function()
84 return type(SV.chatframe) == 'string' and SV.chatframe or nil
85 end,
86 set = "SetChat",
87 order = 16,
88 },
89 fields = {
90 name = "Fields",
91 desc = "Track changes to these player fields",
92 type = 'multiselect',
93 order = 20,
94 -- these need to be of function type rather than string keys of members
95 values = function(info) return addon:MakeFieldList() end,
96 get = function(info,x) return SV.fields[x] end,
97 set = function(info,x,val) SV.fields[x] = val end,
98 },
99 spacer1 = {
100 name = '',
101 type = 'description',
102 cmdHidden = true,
103 width = 'full',
104 order = 29,
105 },
106 guilds = {
107 name = "Guilds",
108 desc = "Guilds for which a roster is known",
109 type = 'select',
110 order = 30,
111 width = 'double',
112 values = function(info) return addon:MakeGuildList() end,
113 get = function(info) return guild_selection end,
114 set = function(info,val) guild_selection = val end,
115 },
116 clearguild = {
117 name = "Reset Guild",
118 desc = "Erase stored data for selected guild; information will be scanned from scratch on next login.",
119 type = 'execute',
120 order = 32,
121 disabled = function() return not guild_selection end,
122 func = function()
123 assert(type(guild_selection)=='string')
124 local g,r = guild_selection:match("<([^>]+)> %- (.*)")
125 local m = SV.members[r]
126 if m then
127 m[g] = nil
128 else
129 addon:Print("Hm, error.", r, "can't be matched as a realm name. Please report this as a bug, including the name of the realm and guild.")
130 end
131 end,
132 },
133 persist = {
134 name = "Logging",
135 type = 'group',
136 inline = true,
137 order = 60,
138 args = {
139 note = {
140 --name = filled in locals section
141 type = 'description',
142 cmdHidden = true,
143 width = 'full',
144 order = 1,
145 },
146 enable = {
147 name = "Enable Logging",
148 desc = [[Accumulate all deltas, including a timestamp. |cffFF0000WARNING|r: if logging was enabled and you turn it off, the log itself will not be saved when exiting the game.]],
149 type = 'toggle',
150 order = 2,
151 get = function() return SV.logging end,
152 set = function(i,v)
153 SV.logging = v
154 log_ever_shown = SV.logging or log_ever_shown
155 end,
156 },
157 clearlog = {
158 name = "Reset Log",
159 desc = "Erase accumulated deltas.",
160 type = 'execute',
161 order = 3,
162 hidden = function() return not (SV.logging or log_ever_shown) end,
163 disabled = function() return not SV.logging end,
164 func = function()
165 SV.logtext = nil
166 end,
167 },
168 log = {
169 name = "Log",
170 desc = "If you make changes, don't forget to click 'Accept' to save them.",
171 type = 'input',
172 order = 10,
173 multiline = 15,
174 width = 'full',
175 hidden = function() return not (SV.logging or log_ever_shown) end,
176 disabled = function() return not SV.logging end,
177 get = function() return SV.logtext end,
178 set = function(i,t) SV.logtext = t end,
179 },
180 },
181 },
182 }
183 }
184
185
186 -----------------------------------------------------------------------------
187 -- other locals
188 local tinsert, GetGuildRosterInfo = _G.table.insert, _G.GetGuildRosterInfo
189 local chatframe, fieldlist
190 local function prt (...)
191 return chatframe:AddMessage(...)
192 end
193 local function cprt (txt)
194 if SV.logging then addon:AddLogNote(txt) end
195 return prt(txt, 255/255, 26/255, 160/255)
196 end
197
198 function addon:current_guild_info (N)
199 local ret = {}
200 for i = 1, N do
201 local name,rank_as_string,_,level,_,_,publicnote,officernote = GetGuildRosterInfo(i)
202 -- This technically does not work out to the same as A?B:C, combined
203 -- with the logic below. It does, however, still result in the entry
204 -- not appearing in the returned table.
205 publicnote = publicnote ~= "" and publicnote or nil
206 officernote = officernote ~= "" and officernote or nil
207 if name then -- redundant, but apparently happens on extreme lag
208 tinsert(ret,
209 {name = name,
210 rank = SV.fields.rank and rank_as_string or nil,
211 level = SV.fields.level and level or nil,
212 pnote = SV.fields.notes and publicnote or nil,
213 onote = SV.fields.notes and officernote or nil,
214 })
215 end
216 end
217 table.sort(ret, function (l,r) return l.name < r.name end)
218 return ret
219 end
220
221 function addon.options.args.print_chatframes.func()
222 for i = 1, NUM_CHAT_WINDOWS do
223 local cf = _G["ChatFrame"..i]
224 if not cf then break end
225 addon:Print(cf, "This is frame number", i)
226 end
227 end
228
229 addon.options.args.note.name =
230 "You can use the '/guilddelta' command to open the options window.\n\n"..
231 "The guild roster has already been scanned by the time you see this. Therefore, "..
232 "if you make any changes to the Fields section below, you should probably relog "..
233 "immediately to begin tracking the changed fields. Changes to the contents *OF* "..
234 "those fields will not be noticed until the first login after *that*.\n\n"
235
236 addon.options.args.persist.args.note.name =
237 "Enabling logging will accumulate the text of the 'deltas' as you see them. "..
238 "This can grow large over time, depending on the activity of your guilds, so you "..
239 "should use the Reset Log button below from time to time.\n\n"..
240 "If you click inside the text area below, you can use Control-A to select all "..
241 "the text, and Control-C to copy it to your computer's clipboard. If you make "..
242 "any changes to the text, they will be preserved. (You can remove uninteresting "..
243 "changes, add reminders to yourself, and so forth.)\n\n"
244
245
246 -----------------------------------------------------------------------------
247 addon = LibStub("AceAddon-3.0"):NewAddon(addon, "GuildDelta",
248 "AceConsole-3.0")
249
250 function addon:OnInitialize()
251 if _G.GuildDeltaSV == nil then
252 -- Defaults need to transition from potential older savedvars
253 _G.GuildDeltaSV = {
254 chatframe = _G.GuildDelta_chatframe or DEFAULT_CHAT,
255 fields = _G.GuildDelta_fields or { rank = true, level = false, notes = true },
256 members = _G.GuildDelta_memberdata or {}
257 }
258 end
259 SV = _G.GuildDeltaSV
260 end
261
262 -- Remove anything that normal operation doesn't need after finishing its work.
263 function addon:cleanup()
264 prt = nil; cprt = nil
265 self.current_guild_info = nil
266 self.cleanup = nil
267 self.unload = nil
268 self.logquay = nil
269 self.AddLogNote = nil
270 self.FinishLog = nil
271 end
272 function addon:unload()
273 self:cleanup()
274 LibStub("AceAddon-3.0").addons["GuildDelta"] = nil
275 l10n = nil; addon = nil;
276 -- put the userdata back so it counts as a Frame object again
277 local ud = self[0]
278 table.wipe(self)
279 self[0] = ud
280 end
281
282 function addon:OnEnable()
283 if not IsInGuild() then
284 self:Print("You are not in a guild, not loading.")
285 return self:unload()
286 end
287
288 AutoCompleteInfoDelayer:HookScript("OnFinished",
289 function() self:RegisterEvent("GUILD_ROSTER_UPDATE") end)
290 self:SetScript("OnEvent", self.GuildUpdate)
291
292 self.options.args.version.name =
293 "|cff30adffVersion " .. (GetAddOnMetadata("GuildDelta", "Version") or "?") .. "|r"
294 LibStub("AceConfig-3.0"):RegisterOptionsTable("GuildDelta", self.options)
295 --[[self.optionsFrame =]] LibStub("AceConfigDialog-3.0"):AddToBlizOptions("GuildDelta", "Guild Delta")
296 self:RegisterChatCommand("guilddelta", "OnChatCommand")
297 self:SetChat(false)
298 log_ever_shown = SV.logging
299 self.OnEnable = nil
300 end
301
302
303 function addon:OnChatCommand (input)
304 if not input or input:trim() == "" then
305 LibStub("AceConfigDialog-3.0"):Open("GuildDelta")
306 else
307 LibStub("AceConfigCmd-3.0").HandleCommand(self, "guilddelta", "GuildDelta", input)
308 end
309 end
310
311
312 -- 0 args: called during startup to initialize
313 -- 1 arg: resetting via menus to defaults (see arg field)
314 -- 2 args: setting via menus to new value, number or custom name
315 function addon:SetChat (info, value)
316 local n, nframe
317 if info then -- coming via menu
318 n = info.arg or value
319 else
320 n = SV.chatframe
321 end
322 if type(n) == 'number' then
323 nframe = _G["ChatFrame"..n]
324 else
325 nframe = _G[n]
326 end
327 if type(nframe) == 'table' and type(nframe.AddMessage) == 'function' then
328 if type(info) ~= 'boolean' then
329 self:Print("Now printing to chat frame", n,
330 (type(nframe.name)=='string' and ("(".. nframe.name .. ")") or ""))
331 end
332 SV.chatframe = n
333 chatframe = nframe
334 else
335 self:Printf("EEEEEEEK! '%s' was not a valid chat frame number/name, no change has been made.", n)
336 end
337 end
338
339
340 -- Not a "normal" PLAYER_LOGOUT handler; this only fires if the player is in
341 -- a guild and the update has already run.
342 function addon:PLAYER_LOGOUT()
343 if not SV.logging then
344 SV.logtext = nil
345 end
346 end
347
348
349 function addon:GuildUpdate()
350 local current_n = GetNumGuildMembers(true)
351 if current_n <= 0 then
352 -- catch the hell up, servers...
353 return GuildRoster()
354 end
355 self:UnregisterEvent("GUILD_ROSTER_UPDATE")
356 self:SetScript("OnEvent", self.PLAYER_LOGOUT) -- keepin' it real^H^H^H^Hsmall and kludgey
357 self:RegisterEvent("PLAYER_LOGOUT")
358 self.GuildUpdate = nil
359
360 local guild, realm = (GetGuildInfo("player")), GetRealmName()
361 local members = SV.members
362 if members[realm]
363 and members[realm][guild]
364 and #(members[realm][guild]) > 0
365 then
366 -- moved the normal case below
367 else
368 -- new user, or new guild, or any number of things
369 self:Print("GuildDelta initializing roster...")
370 members[realm] = members[realm] or {}
371 members[realm][guild] = self:current_guild_info(current_n)
372 return
373 end
374
375 -- table.insert with notes if available
376 -- concatentation of all strings faster than string.format
377 local function tins (t, x)
378 local s = x.name
379 if x.onote and (x.onote ~= "") then
380 s = s .. "(" .. l10n.Oabbrev .. ": " .. x.onote .. ")"
381 end
382 if x.pnote and (x.pnote ~= "") then
383 s = s .. "(" .. x.pnote .. ")"
384 end
385 tinsert(t, s)
386 end
387
388 -- build the current list
389 local previous, current = members[realm][guild],
390 self:current_guild_info(current_n)
391 local previous_n = #previous
392
393 -- walk both and do equivalence comparison
394 local joined, left, rank, level, notes = {}, {}, {}, {}, {}
395 local p, c = 1, 1
396 while p <= previous_n and c <= current_n do
397 local P, C = previous[p], current[c]
398
399 if P.name == C.name then
400 -- normal case
401 p = p + 1
402 c = c + 1
403 -- but can now compare details
404 if C.rank and P.rank and (P.rank ~= C.rank) then
405 tinsert(rank, {C.name, P.rank.." --> "..C.rank})
406 end
407 if C.level and P.level and (P.level ~= C.level) then
408 tinsert(level, {C.name, P.level.." --> "..C.level})
409 end
410 if C.pnote and (P.pnote ~= C.pnote) then
411 tinsert(notes, {C.name, C.pnote})
412 end
413 if C.onote and (P.onote ~= C.onote) then
414 tinsert(notes, {C.name, "["..l10n.Oabbrev.."]: "..C.onote})
415 end
416
417 elseif P.name < C.name then
418 -- entry at index p not at c -> somebody has left
419 tins (left, P)
420 p = p + 1
421
422 else
423 -- entry at index c not at p -> somebody has joined
424 tins (joined, C)
425 c = c + 1
426 end
427 end
428
429 -- leftovers
430 for i = p, previous_n do
431 tins (left, previous[i])
432 end
433 for i = c, current_n do
434 tins (joined, current[i])
435 end
436
437 -- show results
438 if SV.logging then self.logquay = {} end
439 local m
440 if #left > 0 then
441 m = l10n.LEFT .. table.concat(left, ", ")
442 cprt(m)
443 end
444
445 if #joined > 0 then
446 m = l10n.JOINED .. table.concat(joined, ", ")
447 cprt(m)
448 end
449
450 if #rank > 0 then
451 cprt(l10n.RANK)
452 for i = 1, #rank do
453 cprt(rank[i][1]..': '..rank[i][2])
454 end
455 end
456
457 if #level > 0 then
458 cprt(l10n.LEVEL)
459 for i = 1, #level do
460 cprt(level[i][1]..': '..level[i][2])
461 end
462 end
463
464 if #notes > 0 then
465 cprt(l10n.NOTES)
466 for i = 1, #notes do
467 cprt(notes[i][1]..': "'..notes[i][2]..'"')
468 end
469 end
470
471 if SV.logging then self:FinishLog(guild,realm) end
472 members[realm][guild] = current
473 end
474
475
476 function addon:MakeFieldList()
477 if not fieldlist then
478 fieldlist = {}
479 for name in pairs(SV.fields) do
480 fieldlist[name] = l10n["FIELD_"..name]
481 end
482 end
483 return fieldlist
484 end
485
486 function addon:MakeGuildList()
487 local list = {}
488 local K
489 for rname,rdata in pairs(SV.members) do
490 for g in pairs(rdata) do
491 K = ("<%s> - %s"):format(g,rname)
492 list[K] = K
493 end
494 end
495 return list
496 end
497
498 function addon:AddLogNote (txt)
499 tinsert(self.logquay,txt)
500 end
501
502 function addon:FinishLog(g,r)
503 if #self.logquay > 0 then
504 Calendar_LoadUI()
505 local _,M,D,Y = CalendarGetDate()
506 local h,m = GetGameTime()
507 local timestamp = ("%.4d/%.2d/%.2d %.2d:%.2d <%s> - %s\n"):format(Y,M,D,h,m,g,r)
508 SV.logtext = timestamp
509 .. table.concat(self.logquay, '\n')
510 .. (SV.logtext and ('\n\n'..SV.logtext) or '')
511 end
512 end
513
514 -- vim:noet