mirror of
https://github.com/NovaElysium/CawDPSMeter.git
synced 2026-11-10 20:17:34 +00:00
95 lines
5.0 KiB
Lua
95 lines
5.0 KiB
Lua
-- Complete local talent rank layouts, independent of class-specific threat rules.
|
|
-- Each slot carries rank/maxRank; tab/slot identities are client-layout specific.
|
|
local D=CAW_DPS_METER
|
|
local digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
D.talentProfiles={}; D.talentIncoming={}
|
|
|
|
function D.readTalentLayout()
|
|
if not GetNumTalentTabs or not GetNumTalents or not GetTalentInfo then return nil end
|
|
local ok,n=pcall(GetNumTalentTabs)
|
|
if not ok or type(n)~="number" or n<1 or n>8 or n~=math.floor(n) then return nil end
|
|
local tabs={}; local tab,i
|
|
for tab=1,n do
|
|
local good,count=pcall(GetNumTalents,tab)
|
|
if not good or type(count)~="number" or count<1 or count>64 or count~=math.floor(count) then return nil end
|
|
local encoded=""
|
|
for i=1,count do
|
|
local success,name,icon,tier,column,rank,maxRank=pcall(GetTalentInfo,tab,i)
|
|
if not success or not name or type(rank)~="number" or type(maxRank)~="number" or rank<0 or maxRank<1 or maxRank>35 or rank>maxRank or rank~=math.floor(rank) or maxRank~=math.floor(maxRank) then return nil end
|
|
encoded=encoded..string.sub(digits,rank+1,rank+1)..string.sub(digits,maxRank+1,maxRank+1)
|
|
end
|
|
tabs[tab]=encoded
|
|
end
|
|
return tabs
|
|
end
|
|
|
|
function D.talentProfileFor(actor)
|
|
if not actor or not actor.guid then return nil end
|
|
local p=actor and D.talentProfiles[actor.guid]
|
|
if p and GetTime()-p.time<=90 and D.threatPeerUnit(actor.guid,p.name) then return p end
|
|
if actor then D.talentProfiles[actor.guid]=nil end
|
|
end
|
|
|
|
function D.talentSyncReceive(sender,p,channel)
|
|
if channel~="PARTY" and channel~="RAID" then return end
|
|
local guid=p[3]
|
|
if p[2]~="1" or not guid or not D.threatPeerUnit(guid,sender) then return end
|
|
local rev,tab,total=tonumber(p[4]),tonumber(p[5]),tonumber(p[6])
|
|
if not rev or rev<0 or rev~=math.floor(rev) or not tab or not total then return end
|
|
local current=D.talentProfiles[guid]; local pending=D.talentIncoming[guid]
|
|
if current and rev<=current.revision then return end
|
|
if pending and rev<pending.revision then return end
|
|
if tab==0 and total==0 and p[7]=="-" then
|
|
D.talentProfiles[guid]={name=sender,revision=rev,time=GetTime(),available=false,tabs={}}
|
|
D.talentIncoming[guid]=nil
|
|
return
|
|
end
|
|
local data=p[7]
|
|
if total<1 or total>8 or tab<1 or tab>total or total~=math.floor(total) or tab~=math.floor(tab) or not data or string.len(data)<2 or string.len(data)>128 or math.mod(string.len(data),2)~=0 then return end
|
|
local ranks={}; local i
|
|
for i=1,string.len(data),2 do
|
|
local rank=string.find(digits,string.sub(data,i,i),1,true)
|
|
local maxRank=string.find(digits,string.sub(data,i+1,i+1),1,true)
|
|
if not rank or not maxRank or maxRank<=1 or rank>maxRank then return end
|
|
table.insert(ranks,{rank=rank-1,maxRank=maxRank-1})
|
|
end
|
|
if not pending or pending.revision~=rev then pending={name=sender,revision=rev,time=GetTime(),total=total,tabs={},codes={}}; D.talentIncoming[guid]=pending end
|
|
if pending.total~=total then return end
|
|
pending.tabs[tab]=ranks
|
|
pending.codes[tab]=data
|
|
for i=1,total do if not pending.tabs[i] then return end end
|
|
pending.signature=table.concat(pending.codes,"/"); pending.codes=nil
|
|
pending.available=true; pending.time=GetTime()
|
|
D.talentProfiles[guid]=pending; D.talentIncoming[guid]=nil
|
|
end
|
|
|
|
function D.talentSyncTick(send,channel)
|
|
local now=GetTime()
|
|
if now>=(D.talentNextRead or 0) then
|
|
D.talentNextRead=now+1
|
|
local guid,p
|
|
for guid,p in D.talentProfiles do if not channel or now-p.time>90 or not D.threatPeerUnit(guid,p.name) then D.talentProfiles[guid]=nil end end
|
|
for guid,p in D.talentIncoming do if not channel or now-p.time>10 or not D.threatPeerUnit(guid,p.name) then D.talentIncoming[guid]=nil end end
|
|
if not channel then D.talentOut=nil; D.talentLastLayout=nil; D.talentLastChannel=nil; return end
|
|
local exists,pg=UnitExists("player")
|
|
if not exists or not pg then return end
|
|
local tabs=D.readTalentLayout()
|
|
local signature=tabs and table.concat(tabs,"/") or "unknown"
|
|
if signature~=D.talentLastLayout or channel~=D.talentLastChannel or now-(D.talentLastCycle or 0)>=30 then
|
|
local rev=math.floor(now*1000); local packets={}; local i
|
|
if tabs then
|
|
for i=1,table.getn(tabs) do packets[i]="K~1~"..pg.."~"..rev.."~"..i.."~"..table.getn(tabs).."~"..tabs[i] end
|
|
else packets[1]="K~1~"..pg.."~"..rev.."~0~0~-" end
|
|
D.talentOut={packets=packets,index=1,channel=channel}
|
|
D.talentLastLayout=signature; D.talentLastChannel=channel; D.talentLastCycle=now
|
|
end
|
|
end
|
|
local out=D.talentOut
|
|
if not channel or not out or out.channel~=channel or now<(D.talentNextSend or 0) then return end
|
|
D.talentNextSend=now+0.2
|
|
if send(out.packets[out.index],channel) then
|
|
out.index=out.index+1
|
|
if out.index>table.getn(out.packets) then D.talentOut=nil end
|
|
end
|
|
end
|