comparison CrossRealmAssist.lua @ 3:5e23a92dcde1

Layout once again
author ShadowTheAge
date Wed, 04 Mar 2015 22:07:43 +0300
parents 9fa8442dd547
children 421508c17712
comparison
equal deleted inserted replaced
2:c73a7706861e 3:5e23a92dcde1
1 CrossRealmAssist = LibStub("AceAddon-3.0"):NewAddon("CrossRealmAssist", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0")
2 local AceGUI = LibStub("AceGUI-3.0")
3 local addon = CrossRealmAssist;
4 local wholib = LibStub:GetLibrary('LibWho-2.0'):Library()
5
6 local hgroup, lfgContainer, currealm, partyrealm, recrealm, curRealmStat, homeRealm, realmSep, gui, leavebtn
7
8 local scanstate=0
9 local recentRealms={}
10 local active=false
11
12 local lfgGroups={
13 6, -- Custom
14 10, -- Ashran
15 1, -- Quests
16 3, -- Raids
17 8 -- BGs
18 }
19
20 local lfgTabs
21 local curLfgGroup
22 local sheduledScan
23 local wasInGroup
24 local lfgScanInProgress=false
25
26 function addon:OnInitialize()
27
28 end
29
30 function addon:OnEnable()
31 local tabCount = table.getn(lfgGroups)
32 lfgTabs = {}
33 for i=1,tabCount do
34 local cat = lfgGroups[i]
35 table.insert(lfgTabs,{value=cat,text=(C_LFGList.GetCategoryInfo(cat))})
36 end
37 realmSep = _G.REALM_SEPARATORS
38 homeRealm = GetRealmName()
39 addon:RegisterChatCommand("cra", "Activate")
40 addon:RegisterChatCommand("crossrealmassist", "Activate")
41 end
42
43 function addon:OnDisable()
44 addon:Deactivate()
45 end
46
47 function addon:Activate()
48 if active then return end
49 active=true
50 wasInGroup = IsInGroup()
51 addon:CreateUI()
52 addon:ScanRealm()
53 addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", "SheduleScan")
54 addon:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED", "LfgResponseData")
55 addon:RegisterEvent("LFG_LIST_SEARCH_FAILED", "LfgScanFailed")
56 addon:RegisterEvent("GROUP_ROSTER_UPDATE", "updatePartyInfo")
57 addon:RegisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED", "updateAppStatus")
58 end
59
60 function addon:Deactivate()
61 if not active then return end
62 active = false
63 scanstate = 0
64 lfgScanInProgress = false
65 gui:Release();
66 gui, lfgContainer, hgroup, currealm, partyrealm, recrealm, leavebtn = nil,nil,nil,nil,nil,nil,nil
67 addon:UnregisterEvent("ZONE_CHANGED_NEW_AREA")
68 addon:UnregisterEvent("PLAYER_REGEN_ENABLED")
69 addon:UnregisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED")
70 addon:UnregisterEvent("LFG_LIST_SEARCH_FAILED")
71 addon:UnregisterEvent("GROUP_ROSTER_UPDATE")
72 addon:UnregisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED")
73 end
74
75 function addon:CreateUI()
76 gui = addon:AddUI(nil,"Window",{SetTitle="Cross Realm Assist",EnableResize=false,SetLayout="Flow"},true,{OnClose=addon.Deactivate})
77
78 local tabgroup = addon:AddUI(gui,"TabGroup",{SetFullHeight=true,SetTabs=lfgTabs,SetLayout="Fill"},true,{OnGroupSelected=addon.LfgScan})
79 tabgroup:SelectTab(lfgGroups[1])
80 lfgContainer = addon:AddUI(tabgroup,"ScrollFrame")
81
82 local hgroupc = addon:AddUI(gui,"InlineGroup",{SetLayout="Fill",SetFullHeight=true,SetTitle="Realm info"},true)
83 hgroup = addon:AddUI(hgroupc,"ScrollFrame")
84
85 addon:AddUI(hgroup,"Heading",{SetText="Current realm"})
86 currealm = addon:AddUI(hgroup,"SimpleGroup");
87 addon:AddUI(hgroup,"Button",{SetText="Refresh",SetRelativeWidth=0.5,SetHeight=20},true,{OnClick=addon.ScanRealm})
88
89 addon:AddUI(hgroup,"Heading",{SetText="Party statistics"})
90 partyrealm = addon:AddUI(hgroup,"SimpleGroup");
91 leavebtn = addon:AddUI(hgroup,"Button",{SetText="Leave",SetRelativeWidth=0.5,SetHeight=20,SetDisabled=not IsInGroup()},true,{OnClick=LeaveParty})
92
93 addon:AddUI(hgroup,"Heading",{SetText="Recent realms"})
94 recrealm = addon:AddUI(hgroup,"SimpleGroup");
95 addon:AddUI(hgroup,"Button",{SetText="Clear",SetRelativeWidth=0.5,SetHeight=20},true,{OnClick=addon.ClearRecentRealms})
96
97 gui:DoLayout()
98 gui:PauseLayout()
99
100 tabgroup:SetPoint("BOTTOMRIGHT", gui.content, "BOTTOMRIGHT", -200, 0)
101 hgroupc:SetPoint("TOPLEFT", gui.content, "TOPRIGHT", -200, 0)
102 hgroupc:SetPoint("BOTTOMRIGHT", gui.content, "BOTTOMRIGHT")
103
104 if curRealmStat then addon:updateCurrentRealm() end
105 addon:updatePartyInfo()
106 addon:updateRecentRealms()
107 end
108
109 -- LFG scanning routine
110
111 function addon.refreshLfgCurrent()
112 addon.LfgScan(nil,nil,curLfgGroup)
113 end
114
115 function addon.LfgScan(widget, callback, tab)
116 if not tab then return end
117 lfgScanInProgress = true
118 if lfgContainer then lfgContainer:ReleaseChildren() end
119 curLfgGroup = tab
120 C_LFGList.Search(curLfgGroup,"")
121 end
122
123 function addon:LfgScanFailed(event, reason)
124 print("scan failed "..reason)
125 if reason == "throttled" then
126 addon:ScheduleTimer(addon.LfgScan, 2, nil, nil, curLfgGroup)
127 end
128 end
129
130 local function WeightLfgItem(item)
131 local leaderRealm = 3
132 if (item.realm ~= "???") then leaderRealm = (5 - (recentRealms[item.realm] or 0)) end
133 local weight =
134 (item.autoinv and 5 or 2) *
135 ((item.friends > 0) and 2 or 3) *
136 ((item.ilvl > 0) and 2 or 3) *
137 ((item.voice ~= "") and 2 or 4)
138 local count = item.pcount;
139 local countWeight
140 if count >= 39 or count <= 1 then countWeight = 1
141 elseif count >= 35 or count <= 4 then countWeight = 2
142 elseif count >= 30 or count <= 10 then countWeight = 3
143 else countWeight = 4 end
144 return weight * leaderRealm * countWeight;
145 end
146
147 function addon:LfgResponseData()
148 lfgScanInProgress = false;
149 addon:UpdateCurrentLfgInfo()
150 end
151
152 function addon:UpdateCurrentLfgInfo(repeated)
153 if lfgScanInProgress then return end
154 local count, list = C_LFGList.GetSearchResults()
155 local lfgList = {}
156 local lfgEntries = 0
157 local hasUnknowns = false
158 for i = 1,count do
159 local rid = list[i];
160 if not rid then break end
161 local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rid)
162 if not fullname then
163 fullname = "???-???"
164 hasUnknowns = true
165 end
166 if not delisted then
167 local pname, realm = strsplit(realmSep, fullname)
168 realm = realm or homeRealm
169 local item = {
170 rid=rid,
171 action=action,
172 caption=caption,
173 desc=desc,
174 ilvl=ilvl,
175 voice=voice,
176 time=time,
177 friends=bnetfr+charfr+guild,
178 name=pname,
179 realm = realm,
180 pcount=pcount,
181 autoinv=autoinv
182 }
183 item.weight = WeightLfgItem(item)
184 table.insert(lfgList, item)
185 lfgEntries = lfgEntries + 1
186 end
187 end
188 addon:refreshLFGList(lfgList, lfgEntries);
189 if hasUnknowns and repeated ~= true then addon:ScheduleTimer("UpdateCurrentLfgInfo", 1, true) end
190 end
191
192 function addon:refreshLFGList(list, count)
193 if not lfgContainer then return end
194 lfgContainer:PauseLayout()
195 lfgContainer:ReleaseChildren()
196 table.sort(list, addon.SortLfgItems)
197
198 local canJoin = addon.canJoinGroup()
199
200 for i=1,count do
201 local data = list[i];
202 local renderer = addon:AddUI(lfgContainer,"SimpleGroup",{SetLayout="Flow",SetHeight=20,SetAutoAdjustHeight=false});
203
204 addon:AddUI(renderer,"Label",{SetText=data.caption,SetRelativeWidth=0.4},true)
205 addon:AddUI(renderer,"Label",{SetText=data.pcount,SetRelativeWidth=0.05},true)
206 local realm = addon:AddUI(renderer,"Label",{SetText=data.realm,SetRelativeWidth=0.25},true)
207 if recentRealms[data.realm] then
208 local r,g,b = GetItemQualityColor(recentRealms[data.realm]);
209 realm:SetColor(r,g,b)
210 end
211
212 local tooltip = {}
213 if data.voice ~= "" then table.insert(tooltip,"Voice: "..data.voice) end
214 if data.friends > 0 then table.insert(tooltip,"Friends: "..data.friends) end
215 if data.ilvl > 0 then table.insert(tooltip,"Min. Ilvl: "..data.ilvl) end
216 addon:AddIcon(renderer, "Interface/GossipFrame/ActiveQuestIcon", 16, tooltip[1] ~= nil, tooltip)
217 addon:AddIcon(renderer, READY_CHECK_READY_TEXTURE, 16, data.autoinv, {"Auto invite!"})
218 local btn = addon:AddUI(renderer,"Button",{SetText="Join",SetRelativeWidth=0.2,SetHeight=20,SetDisabled=not canJoin},true,{OnClick=addon.joinGroup})
219 btn:SetUserData('rid',data.rid)
220 end
221 addon:AddUI(lfgContainer,"Button",{SetText="Refresh",SetWidth=100,SetHeight=20},true,{OnClick=addon.refreshLfgCurrent})
222
223 lfgContainer:ResumeLayout()
224 lfgContainer:DoLayout()
225 end
226
227 function addon.SortLfgItems(a,b)
228 return a.weight > b.weight
229 end
230
231 function addon.canJoinGroup()
232 return (not IsInGroup()) or (UnitIsGroupLeader('player') and not IsInRaid())
233 end
234
235 function addon.joinGroup(widget)
236 if not addon.canJoinGroup() then return end
237 local rid = widget:GetUserData('rid');
238 widget:SetDisabled(true)
239 C_LFGList.ApplyToGroup(rid, "", C_LFGList.GetAvailableRoles())
240 end
241
242 function addon:updateAppStatus(event, id, status, oldstatus)
243 if status == "invited" then
244 LFGListInviteDialog_Accept(LFGListInviteDialog)
245 end
246 end
247
248 -- Zone scanning routine
249
250 function addon:LeaveCombat()
251 addon:UnregisterEvent("PLAYER_REGEN_ENABLED")
252 scanstate = 0
253 addon:ScanRealm();
254 end
255
256 function addon:ScanRealm()
257 if scanstate > 0 then return end
258 if InCombatLockdown() then
259 addon:RegisterEvent("PLAYER_REGEN_ENABLED","LeaveCombat")
260 scanstate = 1
261 addon:AddLabel(currealm, "Scan sheduled after combat...", 3);
262 return
263 end
264 scanstate = 2
265 addon:AddLabel(currealm, "Scanning...", 3);
266 local searchString = _G.WHO_TAG_ZONE .. '"' .. GetZoneText() .. '"';
267 wholib:Who(searchString, {callback = "ScanResult", handler=addon})
268 end
269
270 function addon:ScanResult(query, results, complete)
271 local realms = {}
272 for _, player in ipairs(results) do
273 addon:AddRealmStat(player.Name, realms);
274 end
275 curRealmStat = addon:GetRealmStat(realms);
276 addon:updateCurrentRealm();
277 local rescan = scanstate == 3
278 scanstate = 0;
279 if rescan then addon:ScanRealm() end
280 end
281
282 function addon:AddRealmStat(name, realms)
283 local _, realm = strsplit(realmSep, name) -- TODO exclude self
284 realm = realm or homeRealm
285 realms[realm] = (realms[realm] or 0) + 1
286 end
287
288 function addon:AddUnitIdStat(unitid, realms)
289 local name, realm = UnitName(unitid);
290 if not name then return end
291 if realm == "" then realm = homeRealm end
292 realm = realm or homeRealm
293 realms[realm] = (realms[realm] or 0) + 1
294 end
295
296 function addon:GetRealmStat(realms)
297 local rcount = 0;
298 local stat = {};
299 local pcount = 0;
300 for realm,count in pairs(realms) do
301 table.insert(stat,{realm=realm,count=count})
302 rcount = rcount + 1;
303 pcount = pcount + count;
304 end
305 if rcount > 1 then
306 table.sort(stat, function(a,b) return a.count > b.count end)
307 stat.max = stat[1].count
308 else stat.max = 0 end
309 stat.players = pcount;
310 stat.realms = rcount;
311 return stat;
312 end
313
314 function addon:updateCurrentRealm()
315 if not currealm then return end
316 currealm:ReleaseChildren()
317 if curRealmStat.players < 5 then
318 addon:AddLabel(currealm, "Not enough players", 0);
319 end
320 local sureplayers = curRealmStat.players/2
321 local maybeplayers = math.max(curRealmStat.max/4, 3)
322 local recentRealmUpdated = false
323 for i=1,curRealmStat.realms do
324 local data = curRealmStat[i]
325 if data.count >= maybeplayers then
326 local realm = data.realm
327 local rvalue = (data.count >= sureplayers) and 4 or 2
328 if (rvalue > (recentRealms[realm] or 0)) then
329 recentRealmUpdated = true
330 recentRealms[realm] = rvalue
331 end
332 end
333 end
334 addon:addLabels(currealm, curRealmStat, sureplayers, maybeplayers, 3, "Realm unknown");
335 if recentRealmUpdated then
336 addon:UpdateCurrentLfgInfo()
337 addon:updateRecentRealms()
338 end
339 end
340
341 function addon:addLabels(container, stats, epict, whitet, grayt, emptytext)
342 if stats.realms == 0 then
343 addon:AddLabel(container, emptytext)
344 else
345 local players = stats.players
346 local pleft = players;
347 for i=1,stats.realms do
348 local data = stats[i]
349 local count = data.count;
350 local percent = math.ceil(100 * count / players - 0.5)
351 local label = data.realm .. " (" .. percent .. "%)";
352 local color
353 if count < grayt then break
354 elseif count < whitet then color = 1
355 elseif count < epict then color = 2
356 else color = 4 end
357 pleft = pleft - count
358 addon:AddLabel(container, label, color);
359 end
360 if pleft > 0 then
361 addon:AddLabel(container, "Other" .. " (" .. math.ceil(100 * pleft / players - 0.5) .. "%)", 0);
362 end
363 end
364 end
365
366 function addon:updateRecentRealms()
367 if not recrealm then return end
368 recrealm:ReleaseChildren()
369 local nothing = true;
370 for realm,color in pairs(recentRealms) do
371 addon:AddLabel(recrealm, realm,color);
372 nothing = false;
373 end
374 if nothing then
375 addon:AddLabel(recrealm, "No recent realms");
376 end
377 end
378
379 function addon:ClearRecentRealms()
380 recentRealms = {}
381 addon:UpdateCurrentLfgInfo()
382 addon:updateRecentRealms()
383 end
384
385 function addon:SheduleScan()
386 if scanstate == 0 then
387 addon:ScanRealm()
388 elseif scanstate == 2 then
389 scanstate = 3
390 end
391 end
392
393 function addon:updatePartyInfo()
394 if not partyrealm then return end
395 partyrealm:ReleaseChildren()
396 local realms = {}
397 local inGroup = IsInGroup()
398 if IsInGroup() then
399 if IsInRaid() then
400 for i=1, MAX_RAID_MEMBERS do
401 addon:AddUnitIdStat("raid"..i, realms)
402 end
403 else
404 for i=1, MAX_PARTY_MEMBERS do
405 addon:AddUnitIdStat("party"..i, realms)
406 end
407 end
408 end
409 if inGroup ~= wasInGroup then
410 addon:SheduleScan()
411 wasInGroup = inGroup
412 addon:UpdateCurrentLfgInfo()
413 leavebtn:SetDisabled(not inGroup)
414 end
415 local partyStat = addon:GetRealmStat(realms);
416 addon:addLabels(partyrealm, partyStat, partyStat.players/2, 2, 0, "Not in party");
417 end
418
419 -- Utils functions
420
421 function addon:AddUI(owner, type, parameters, manual, callbacks)
422 local ui = AceGUI:Create(type)
423 if parameters then
424 for key,value in pairs(parameters) do ui[key](ui,value) end
425 end
426 if callbacks then
427 for key,value in pairs(callbacks) do ui:SetCallback(key,value) end
428 end
429 if not manual then ui:SetFullWidth(true) end
430 if owner then owner:AddChild(ui) end
431 return ui
432 end
433
434 function addon:AddLabel(owner, text, color, icon)
435 local label = AceGUI:Create("Label")
436 label:SetText(text)
437 label:SetFullWidth(true)
438 if color ~= nil then
439 local r,g,b = GetItemQualityColor(color);
440 label:SetColor(r,g,b)
441 end
442 owner:AddChild(label)
443 return label
444 end
445
446 function addon:AddIcon(owner, image, size, visible, tooltip)
447 if visible ~= false then
448 local icon = addon:AddUI(owner,"Icon",{SetWidth=size,SetHeight=size},true)
449 icon:SetImage(image)
450 icon:SetImageSize(size,size)
451 if tooltip then
452 icon:SetUserData('tooltip',tooltip)
453 icon:SetCallback("OnEnter",addon.ShowTooltip)
454 icon:SetCallback("OnLeave",addon.HideTooltip)
455 end
456 else -- add placeholder
457 addon:AddUI(owner,"Label",{SetWidth=size,SetHeight=size},true)
458 end
459 end
460
461 function addon.ShowTooltip(widget)
462 GameTooltip:SetOwner(widget.frame, "ANCHOR_TOP")
463 local tooltip = widget:GetUserData('tooltip')
464 for i=1,#tooltip do
465 GameTooltip:AddLine(tooltip[i], 1, 1, 1)
466 end
467 GameTooltip:Show()
468 end
469
470 function addon.HideTooltip(widget)
471 GameTooltip:Hide()
472 end