Mercurial > wow > crossrealmassist
view CrossRealmAssist.lua @ 7:b562a71dd109 beta-0.2
Moved tag beta to changeset a50099264aef (from changeset 5ea36b85fc0c)
| author | ShadowTheAge |
|---|---|
| date | Wed, 04 Mar 2015 22:47:52 +0300 |
| parents | 9fa8442dd547 |
| children | 421508c17712 |
line wrap: on
line source
CrossRealmAssist = LibStub("AceAddon-3.0"):NewAddon("CrossRealmAssist", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0") local AceGUI = LibStub("AceGUI-3.0") local addon = CrossRealmAssist; local wholib = LibStub:GetLibrary('LibWho-2.0'):Library() local hgroup, lfgContainer, currealm, partyrealm, recrealm, curRealmStat, homeRealm, realmSep, gui, leavebtn local scanstate=0 local recentRealms={} local active=false local lfgGroups={ 6, -- Custom 10, -- Ashran 1, -- Quests 3, -- Raids 8 -- BGs } local lfgTabs local curLfgGroup local sheduledScan local wasInGroup local lfgScanInProgress=false function addon:OnInitialize() end function addon:OnEnable() local tabCount = table.getn(lfgGroups) lfgTabs = {} for i=1,tabCount do local cat = lfgGroups[i] table.insert(lfgTabs,{value=cat,text=(C_LFGList.GetCategoryInfo(cat))}) end realmSep = _G.REALM_SEPARATORS homeRealm = GetRealmName() addon:RegisterChatCommand("cra", "Activate") addon:RegisterChatCommand("crossrealmassist", "Activate") end function addon:OnDisable() addon:Deactivate() end function addon:Activate() if active then return end active=true wasInGroup = IsInGroup() addon:CreateUI() addon:ScanRealm() addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", "SheduleScan") addon:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED", "LfgResponseData") addon:RegisterEvent("LFG_LIST_SEARCH_FAILED", "LfgScanFailed") addon:RegisterEvent("GROUP_ROSTER_UPDATE", "updatePartyInfo") addon:RegisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED", "updateAppStatus") end function addon:Deactivate() if not active then return end active = false scanstate = 0 lfgScanInProgress = false gui:Release(); gui, lfgContainer, hgroup, currealm, partyrealm, recrealm, leavebtn = nil,nil,nil,nil,nil,nil,nil addon:UnregisterEvent("ZONE_CHANGED_NEW_AREA") addon:UnregisterEvent("PLAYER_REGEN_ENABLED") addon:UnregisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED") addon:UnregisterEvent("LFG_LIST_SEARCH_FAILED") addon:UnregisterEvent("GROUP_ROSTER_UPDATE") addon:UnregisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED") end function addon:CreateUI() gui = addon:AddUI(nil,"Window",{SetTitle="Cross Realm Assist",EnableResize=false,SetLayout="Flow"},true,{OnClose=addon.Deactivate}) local tabgroup = addon:AddUI(gui,"TabGroup",{SetFullHeight=true,SetTabs=lfgTabs,SetLayout="Fill"},true,{OnGroupSelected=addon.LfgScan}) tabgroup:SelectTab(lfgGroups[1]) lfgContainer = addon:AddUI(tabgroup,"ScrollFrame") local hgroupc = addon:AddUI(gui,"InlineGroup",{SetLayout="Fill",SetFullHeight=true,SetTitle="Realm info"},true) hgroup = addon:AddUI(hgroupc,"ScrollFrame") addon:AddUI(hgroup,"Heading",{SetText="Current realm"}) currealm = addon:AddUI(hgroup,"SimpleGroup"); addon:AddUI(hgroup,"Button",{SetText="Refresh",SetRelativeWidth=0.5,SetHeight=20},true,{OnClick=addon.ScanRealm}) addon:AddUI(hgroup,"Heading",{SetText="Party statistics"}) partyrealm = addon:AddUI(hgroup,"SimpleGroup"); leavebtn = addon:AddUI(hgroup,"Button",{SetText="Leave",SetRelativeWidth=0.5,SetHeight=20,SetDisabled=not IsInGroup()},true,{OnClick=LeaveParty}) addon:AddUI(hgroup,"Heading",{SetText="Recent realms"}) recrealm = addon:AddUI(hgroup,"SimpleGroup"); addon:AddUI(hgroup,"Button",{SetText="Clear",SetRelativeWidth=0.5,SetHeight=20},true,{OnClick=addon.ClearRecentRealms}) gui:DoLayout() gui:PauseLayout() tabgroup:SetPoint("BOTTOMRIGHT", gui.content, "BOTTOMRIGHT", -200, 0) hgroupc:SetPoint("TOPLEFT", gui.content, "TOPRIGHT", -200, 0) hgroupc:SetPoint("BOTTOMRIGHT", gui.content, "BOTTOMRIGHT") if curRealmStat then addon:updateCurrentRealm() end addon:updatePartyInfo() addon:updateRecentRealms() end -- LFG scanning routine function addon.refreshLfgCurrent() addon.LfgScan(nil,nil,curLfgGroup) end function addon.LfgScan(widget, callback, tab) if not tab then return end lfgScanInProgress = true if lfgContainer then lfgContainer:ReleaseChildren() end curLfgGroup = tab C_LFGList.Search(curLfgGroup,"") end function addon:LfgScanFailed(event, reason) print("scan failed "..reason) if reason == "throttled" then addon:ScheduleTimer(addon.LfgScan, 2, nil, nil, curLfgGroup) end end local function WeightLfgItem(item) local leaderRealm = 3 if (item.realm ~= "???") then leaderRealm = (5 - (recentRealms[item.realm] or 0)) end local weight = (item.autoinv and 5 or 2) * ((item.friends > 0) and 2 or 3) * ((item.ilvl > 0) and 2 or 3) * ((item.voice ~= "") and 2 or 4) local count = item.pcount; local countWeight if count >= 39 or count <= 1 then countWeight = 1 elseif count >= 35 or count <= 4 then countWeight = 2 elseif count >= 30 or count <= 10 then countWeight = 3 else countWeight = 4 end return weight * leaderRealm * countWeight; end function addon:LfgResponseData() lfgScanInProgress = false; addon:UpdateCurrentLfgInfo() end function addon:UpdateCurrentLfgInfo(repeated) if lfgScanInProgress then return end local count, list = C_LFGList.GetSearchResults() local lfgList = {} local lfgEntries = 0 local hasUnknowns = false for i = 1,count do local rid = list[i]; if not rid then break end local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rid) if not fullname then fullname = "???-???" hasUnknowns = true end if not delisted then local pname, realm = strsplit(realmSep, fullname) realm = realm or homeRealm local item = { rid=rid, action=action, caption=caption, desc=desc, ilvl=ilvl, voice=voice, time=time, friends=bnetfr+charfr+guild, name=pname, realm = realm, pcount=pcount, autoinv=autoinv } item.weight = WeightLfgItem(item) table.insert(lfgList, item) lfgEntries = lfgEntries + 1 end end addon:refreshLFGList(lfgList, lfgEntries); if hasUnknowns and repeated ~= true then addon:ScheduleTimer("UpdateCurrentLfgInfo", 1, true) end end function addon:refreshLFGList(list, count) if not lfgContainer then return end lfgContainer:PauseLayout() lfgContainer:ReleaseChildren() table.sort(list, addon.SortLfgItems) local canJoin = addon.canJoinGroup() for i=1,count do local data = list[i]; local renderer = addon:AddUI(lfgContainer,"SimpleGroup",{SetLayout="Flow",SetHeight=20,SetAutoAdjustHeight=false}); addon:AddUI(renderer,"Label",{SetText=data.caption,SetRelativeWidth=0.4},true) addon:AddUI(renderer,"Label",{SetText=data.pcount,SetRelativeWidth=0.05},true) local realm = addon:AddUI(renderer,"Label",{SetText=data.realm,SetRelativeWidth=0.25},true) if recentRealms[data.realm] then local r,g,b = GetItemQualityColor(recentRealms[data.realm]); realm:SetColor(r,g,b) end local tooltip = {} if data.voice ~= "" then table.insert(tooltip,"Voice: "..data.voice) end if data.friends > 0 then table.insert(tooltip,"Friends: "..data.friends) end if data.ilvl > 0 then table.insert(tooltip,"Min. Ilvl: "..data.ilvl) end addon:AddIcon(renderer, "Interface/GossipFrame/ActiveQuestIcon", 16, tooltip[1] ~= nil, tooltip) addon:AddIcon(renderer, READY_CHECK_READY_TEXTURE, 16, data.autoinv, {"Auto invite!"}) local btn = addon:AddUI(renderer,"Button",{SetText="Join",SetRelativeWidth=0.2,SetHeight=20,SetDisabled=not canJoin},true,{OnClick=addon.joinGroup}) btn:SetUserData('rid',data.rid) end addon:AddUI(lfgContainer,"Button",{SetText="Refresh",SetWidth=100,SetHeight=20},true,{OnClick=addon.refreshLfgCurrent}) lfgContainer:ResumeLayout() lfgContainer:DoLayout() end function addon.SortLfgItems(a,b) return a.weight > b.weight end function addon.canJoinGroup() return (not IsInGroup()) or (UnitIsGroupLeader('player') and not IsInRaid()) end function addon.joinGroup(widget) if not addon.canJoinGroup() then return end local rid = widget:GetUserData('rid'); widget:SetDisabled(true) C_LFGList.ApplyToGroup(rid, "", C_LFGList.GetAvailableRoles()) end function addon:updateAppStatus(event, id, status, oldstatus) if status == "invited" then LFGListInviteDialog_Accept(LFGListInviteDialog) end end -- Zone scanning routine function addon:LeaveCombat() addon:UnregisterEvent("PLAYER_REGEN_ENABLED") scanstate = 0 addon:ScanRealm(); end function addon:ScanRealm() if scanstate > 0 then return end if InCombatLockdown() then addon:RegisterEvent("PLAYER_REGEN_ENABLED","LeaveCombat") scanstate = 1 addon:AddLabel(currealm, "Scan sheduled after combat...", 3); return end scanstate = 2 addon:AddLabel(currealm, "Scanning...", 3); local searchString = _G.WHO_TAG_ZONE .. '"' .. GetZoneText() .. '"'; wholib:Who(searchString, {callback = "ScanResult", handler=addon}) end function addon:ScanResult(query, results, complete) local realms = {} for _, player in ipairs(results) do addon:AddRealmStat(player.Name, realms); end curRealmStat = addon:GetRealmStat(realms); addon:updateCurrentRealm(); local rescan = scanstate == 3 scanstate = 0; if rescan then addon:ScanRealm() end end function addon:AddRealmStat(name, realms) local _, realm = strsplit(realmSep, name) -- TODO exclude self realm = realm or homeRealm realms[realm] = (realms[realm] or 0) + 1 end function addon:AddUnitIdStat(unitid, realms) local name, realm = UnitName(unitid); if not name then return end if realm == "" then realm = homeRealm end realm = realm or homeRealm realms[realm] = (realms[realm] or 0) + 1 end function addon:GetRealmStat(realms) local rcount = 0; local stat = {}; local pcount = 0; for realm,count in pairs(realms) do table.insert(stat,{realm=realm,count=count}) rcount = rcount + 1; pcount = pcount + count; end if rcount > 1 then table.sort(stat, function(a,b) return a.count > b.count end) stat.max = stat[1].count else stat.max = 0 end stat.players = pcount; stat.realms = rcount; return stat; end function addon:updateCurrentRealm() if not currealm then return end currealm:ReleaseChildren() if curRealmStat.players < 5 then addon:AddLabel(currealm, "Not enough players", 0); end local sureplayers = curRealmStat.players/2 local maybeplayers = math.max(curRealmStat.max/4, 3) local recentRealmUpdated = false for i=1,curRealmStat.realms do local data = curRealmStat[i] if data.count >= maybeplayers then local realm = data.realm local rvalue = (data.count >= sureplayers) and 4 or 2 if (rvalue > (recentRealms[realm] or 0)) then recentRealmUpdated = true recentRealms[realm] = rvalue end end end addon:addLabels(currealm, curRealmStat, sureplayers, maybeplayers, 3, "Realm unknown"); if recentRealmUpdated then addon:UpdateCurrentLfgInfo() addon:updateRecentRealms() end end function addon:addLabels(container, stats, epict, whitet, grayt, emptytext) if stats.realms == 0 then addon:AddLabel(container, emptytext) else local players = stats.players local pleft = players; for i=1,stats.realms do local data = stats[i] local count = data.count; local percent = math.ceil(100 * count / players - 0.5) local label = data.realm .. " (" .. percent .. "%)"; local color if count < grayt then break elseif count < whitet then color = 1 elseif count < epict then color = 2 else color = 4 end pleft = pleft - count addon:AddLabel(container, label, color); end if pleft > 0 then addon:AddLabel(container, "Other" .. " (" .. math.ceil(100 * pleft / players - 0.5) .. "%)", 0); end end end function addon:updateRecentRealms() if not recrealm then return end recrealm:ReleaseChildren() local nothing = true; for realm,color in pairs(recentRealms) do addon:AddLabel(recrealm, realm,color); nothing = false; end if nothing then addon:AddLabel(recrealm, "No recent realms"); end end function addon:ClearRecentRealms() recentRealms = {} addon:UpdateCurrentLfgInfo() addon:updateRecentRealms() end function addon:SheduleScan() if scanstate == 0 then addon:ScanRealm() elseif scanstate == 2 then scanstate = 3 end end function addon:updatePartyInfo() if not partyrealm then return end partyrealm:ReleaseChildren() local realms = {} local inGroup = IsInGroup() if IsInGroup() then if IsInRaid() then for i=1, MAX_RAID_MEMBERS do addon:AddUnitIdStat("raid"..i, realms) end else for i=1, MAX_PARTY_MEMBERS do addon:AddUnitIdStat("party"..i, realms) end end end if inGroup ~= wasInGroup then addon:SheduleScan() wasInGroup = inGroup addon:UpdateCurrentLfgInfo() leavebtn:SetDisabled(not inGroup) end local partyStat = addon:GetRealmStat(realms); addon:addLabels(partyrealm, partyStat, partyStat.players/2, 2, 0, "Not in party"); end -- Utils functions function addon:AddUI(owner, type, parameters, manual, callbacks) local ui = AceGUI:Create(type) if parameters then for key,value in pairs(parameters) do ui[key](ui,value) end end if callbacks then for key,value in pairs(callbacks) do ui:SetCallback(key,value) end end if not manual then ui:SetFullWidth(true) end if owner then owner:AddChild(ui) end return ui end function addon:AddLabel(owner, text, color, icon) local label = AceGUI:Create("Label") label:SetText(text) label:SetFullWidth(true) if color ~= nil then local r,g,b = GetItemQualityColor(color); label:SetColor(r,g,b) end owner:AddChild(label) return label end function addon:AddIcon(owner, image, size, visible, tooltip) if visible ~= false then local icon = addon:AddUI(owner,"Icon",{SetWidth=size,SetHeight=size},true) icon:SetImage(image) icon:SetImageSize(size,size) if tooltip then icon:SetUserData('tooltip',tooltip) icon:SetCallback("OnEnter",addon.ShowTooltip) icon:SetCallback("OnLeave",addon.HideTooltip) end else -- add placeholder addon:AddUI(owner,"Label",{SetWidth=size,SetHeight=size},true) end end function addon.ShowTooltip(widget) GameTooltip:SetOwner(widget.frame, "ANCHOR_TOP") local tooltip = widget:GetUserData('tooltip') for i=1,#tooltip do GameTooltip:AddLine(tooltip[i], 1, 1, 1) end GameTooltip:Show() end function addon.HideTooltip(widget) GameTooltip:Hide() end
