You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
8.6 KiB

3 years ago
if not WeakAuras.IsLibsOK() then return end
if not WeakAuras.IsCataOrRetail() then return end
---@type string
local AddonName = ...
---@class Private
local Private = select(2, ...)
3 years ago
--- @class LibSpecialization
--- @field Register fun(self: LibSpecialization, name: string, callback: function)
--- @field MySpecialization fun(): number, string, string
3 years ago
local LibSpec = LibStub("LibSpecialization")
--- @alias specData {[1]: number, [2]: string, [3]: string, [4]: string}
--- @type table<string, specData>
3 years ago
local nameToSpecMap = {}
local nameToTalents = {}
--- @type table<string, string>
3 years ago
local nameToUnitMap = {
[GetUnitName("player", true)] = "player"
}
--- @type function[]
3 years ago
local subscribers = {}
--- @class LibSpecWrapper
--- @field Register fun(callback: fun(unit: string))
--- @field SpecForUnit fun(unit: string): number?
--- @field SpecRolePositionForUnit fun(unit: string): number?, string?, string?
--- @field CheckTalentForUnit fun(unit: string, talentId: number): boolean?
Private.LibSpecWrapper = {
Register = function(callback) end,
SpecForUnit = function(unit) end,
SpecRolePositionForUnit = function(unit) end,
CheckTalentForUnit = function(unit) end,
}
3 years ago
if LibSpec then
local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("GROUP_ROSTER_UPDATE")
frame:SetScript("OnEvent", function()
--- @type string
3 years ago
local ownName = GetUnitName("player", true)
nameToUnitMap = {}
nameToUnitMap[ownName] = "player"
if IsInRaid() then
local max = GetNumGroupMembers()
for i = 1, max do
local name = GetUnitName(WeakAuras.raidUnits[i], true)
nameToUnitMap[name] = WeakAuras.raidUnits[i]
end
else
local max = GetNumSubgroupMembers()
for i = 1, max do
local name = GetUnitName(WeakAuras.partyUnits[i], true)
nameToUnitMap[name] = WeakAuras.partyUnits[i]
end
end
for name in pairs(nameToSpecMap) do
if not nameToUnitMap[name] then
nameToSpecMap[name] = nil
end
end
end)
--- LibSpecialization callback
---@param specId number
---@param role string
---@param position string
---@param sender string
---@param talentString string
local function LibSpecCallback(specId, role, position, sender, talentString)
if nameToSpecMap[sender]
and nameToSpecMap[sender][1] == specId
and nameToSpecMap[sender][2] == role
and nameToSpecMap[sender][3] == position
and nameToSpecMap[sender][4] == talentString
then
3 years ago
return
end
if not nameToUnitMap[sender] then
return
end
nameToSpecMap[sender] = {specId, role, position, talentString}
nameToTalents[sender] = nil
3 years ago
for _, f in ipairs(subscribers) do
f(nameToUnitMap[sender])
end
end
LibSpec:Register("WeakAuras", LibSpecCallback)
function Private.LibSpecWrapper.Register(f)
tinsert(subscribers, f)
end
function Private.LibSpecWrapper.SpecForUnit(unit)
if UnitIsUnit(unit, "player") then
return (LibSpec:MySpecialization())
3 years ago
end
if nameToSpecMap[GetUnitName(unit, true)] then
return nameToSpecMap[GetUnitName(unit, true)][1]
end
end
function Private.LibSpecWrapper.SpecRolePositionForUnit(unit)
if UnitIsUnit(unit, "player") then
return LibSpec:MySpecialization()
end
local data = nameToSpecMap[GetUnitName(unit, true)]
if data then
return unpack(data)
else
return nil
end
3 years ago
end
local function ReadLoadoutHeader(importStream)
local bitWidthHeaderVersion = 8
local bitWidthSpecID = 16
local headerBitWidth = bitWidthHeaderVersion + bitWidthSpecID + 128;
local importStreamTotalBits = importStream:GetNumberOfBits();
if( importStreamTotalBits < headerBitWidth) then
return false, 0, 0, 0;
end
local serializationVersion = importStream:ExtractValue(bitWidthHeaderVersion);
local specID = importStream:ExtractValue(bitWidthSpecID);
-- treeHash is a 128bit hash, passed as an array of 16, 8-bit values
local treeHash = {};
for i=1,16,1 do
treeHash[i] = importStream:ExtractValue(8);
end
return true, serializationVersion, specID, treeHash;
end
local validSerializationVersions = {
[1] = true,
[2] = true
}
function Private.LibSpecWrapper.CheckTalentForUnit(unit, talentId)
if UnitIsUnit(unit, "player") then
return select(4, WeakAuras.GetTalentById(talentId))
end
local unitName = GetUnitName(unit, true)
if not nameToTalents[unitName] then
-- Parse Talent String once and store which talents are selected
if not nameToSpecMap[unitName] then return nil end
local talentString = nameToSpecMap[unitName][4]
if not talentString then return nil end
local importStream = CreateAndInitFromMixin(ImportDataStreamMixin, talentString)
local headerValid, serializationVersion, specID, treeHash = ReadLoadoutHeader(importStream);
local currentSerializationVersion = C_Traits.GetLoadoutSerializationVersion();
if(not headerValid) then
return nil
end
if(serializationVersion ~= currentSerializationVersion or not validSerializationVersions[serializationVersion]) then
return nil
end
local treeID = C_ClassTalents.GetTraitTreeForSpec(specID)
local results = {};
local bitWidthRanksPurchased = 6
local _, _, talentsData = Private.GetTalentData(specID)
local treeNodes = C_Traits.GetTreeNodes(treeID);
for _, nodeId in ipairs(treeNodes) do
local nodeSelectedValue = importStream:ExtractValue(1)
local isNodeSelected = nodeSelectedValue == 1
local isPartiallyRanked = false
local partialRanksPurchased = 0
local isChoiceNode = false
local choiceNodeSelection = 1
if(isNodeSelected) then
if serializationVersion == 2 then
local nodePurchasedValue = importStream:ExtractValue(1)
local isNodePurchased = nodePurchasedValue == 1
if(isNodePurchased) then
local isPartiallyRankedValue = importStream:ExtractValue(1)
isPartiallyRanked = isPartiallyRankedValue == 1
if(isPartiallyRanked) then
partialRanksPurchased = importStream:ExtractValue(bitWidthRanksPurchased)
end
local isChoiceNodeValue = importStream:ExtractValue(1)
isChoiceNode = isChoiceNodeValue == 1
if(isChoiceNode) then
choiceNodeSelection = importStream:ExtractValue(2) + 1
end
end
else
local isPartiallyRankedValue = importStream:ExtractValue(1)
isPartiallyRanked = isPartiallyRankedValue == 1
if(isPartiallyRanked) then
partialRanksPurchased = importStream:ExtractValue(bitWidthRanksPurchased)
end
local isChoiceNodeValue = importStream:ExtractValue(1)
isChoiceNode = isChoiceNodeValue == 1
if(isChoiceNode) then
choiceNodeSelection = importStream:ExtractValue(2) + 1
end
end
end
local talentData = talentsData and talentsData[nodeId] and talentsData[nodeId][choiceNodeSelection]
if talentData then
if isPartiallyRanked then
results[talentData[1]] = partialRanksPurchased
else
results[talentData[1]] = nodeSelectedValue == 1 and talentData[5] or 0
end
end
if isChoiceNode then
local unselectedChoiceNodeIdx = choiceNodeSelection == 1 and 2 or 1
local unselectedTalentData = talentsData and talentsData[nodeId] and talentsData[nodeId][unselectedChoiceNodeIdx]
if unselectedTalentData then
results[unselectedTalentData[1]] = 0
end
end
end
nameToTalents[unitName] = results
end
if nameToTalents[unitName] then
return nameToTalents[unitName][talentId]
end
end
3 years ago
else -- non retail
function Private.LibSpecWrapper.Register(f)
end
function Private.LibSpecWrapper.SpecForUnit(unit)
return nil
end
function Private.LibSpecWrapper.SpecRolePositionForUnit(unit)
return nil
end
function Private.LibSpecWrapper.CheckTalentForUnit(unit)
return nil
end
3 years ago
end
-- Export for GenericTrigger
WeakAuras.SpecForUnit = Private.LibSpecWrapper.SpecForUnit
WeakAuras.SpecRolePositionForUnit = Private.LibSpecWrapper.SpecRolePositionForUnit
WeakAuras.CheckTalentForUnit = Private.LibSpecWrapper.CheckTalentForUnit