Mercurial > wow > crossrealmassist
changeset 0:9fa8442dd547
Initial beta release
| author | ShadowTheAge |
|---|---|
| date | Wed, 04 Mar 2015 21:37:31 +0300 |
| parents | |
| children | 3f83977570fb |
| files | .pkgmeta CrossRealmAssist.lua CrossRealmAssist.toc embeds.xml |
| diffstat | 4 files changed, 504 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.pkgmeta Wed Mar 04 21:37:31 2015 +0300 @@ -0,0 +1,15 @@ +externals: + libs/AceAddon-3.0: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk + libs/AceConsole-3.0: + url: svn://svn.wowace.com/wow/ace3/mainline/trunk + libs/AceEvent-3.0: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk + libs/AceGUI-3.0: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk + libs/AceTimer-3.0: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk + libs/LibStub: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk + libs/LibWho-2.0: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CrossRealmAssist.lua Wed Mar 04 21:37:31 2015 +0300 @@ -0,0 +1,472 @@ +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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CrossRealmAssist.toc Wed Mar 04 21:37:31 2015 +0300 @@ -0,0 +1,8 @@ +## Interface: 60100 +## Title: Cross Realm Assist +## Notes: Easy tool for cross-realm hoping +## Author: ShadowTheAge +## Version: 0.1 + +embeds.xml +CrossRealmAssist.lua \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/embeds.xml Wed Mar 04 21:37:31 2015 +0300 @@ -0,0 +1,9 @@ +<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> + <Script file="libs\LibStub\LibStub.lua"/> + <Include file="Libs\AceAddon-3.0\AceAddon-3.0.xml"/> + <Include file="libs\AceGUI-3.0\AceGUI-3.0.xml"/> + <Include file="Libs\AceConsole-3.0\AceConsole-3.0.xml"/> + <Include file="Libs\AceEvent-3.0\AceEvent-3.0.xml"/> + <Include file="Libs\AceTimer-3.0\AceTimer-3.0.xml"/> + <Script file="Libs\LibWho-2.0\LibWho-2.0\LibWho-2.0.lua"/> +</Ui> \ No newline at end of file
