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.

599 lines
19 KiB

3 years ago
local _, addon = ...
local DataProvider = {};
addon.TalentTreeDataProvider = DataProvider;
local C_ClassTalents = C_ClassTalents;
local C_Traits = C_Traits;
local GetNodeInfo = C_Traits and C_Traits.GetNodeInfo;
local GetEntryInfo = C_Traits and C_Traits.GetEntryInfo;
3 years ago
local GetSpecialization = GetSpecialization;
local GetSpecializationInfo = GetSpecializationInfo;
-- Should use C_Traits.GetConditionInfo, conditionInfo.ranksGranted and conditionInfo.isMet to check if the talent is granted for free
-- But the API returns a table so I'd like to use this fast but less adaptive approach.
local AUTO_GRANTED_NODES = {
--[specID] = {[nodeID] = true},
--https://wowpedia.fandom.com/wiki/SpecializationID
--/dump GetMouseFocus().nodeID
[250] = {76071}, --Blood
[251] = {76081}, --Frost
[252] = {76072}, --Unholy
[577] = {90942}, --Havoc
[581] = {90943}, --Vengeance
[102] = {82201, 82202}, --Balance
[103] = {82199, 82223}, --Feral
[104] = {82220, 82223}, --Guardian
[105] = {82217, 82216}, --Restoration
[1467] = {68681}, --Devastation
[1468] = {68689}, --Preservation
[253] = {79935}, --Beast Mastery
[254] = {79834}, --Marksmanship
[255] = {79839}, --Survival
[62] = {62121}, --Arcane
[63] = {62119}, --Fire
[64] = {62117}, --Frost
[268] = {80689}, --Brewmaster
[270] = {80691}, --Mistweaver
[269] = {80690}, --Windwalker
[65] = {81597, 81599}, --Holy
[66] = {81597, 81599}, --Protection
[70] = {81510, 81601}, --Retribution
[256] = {82717, 82713}, --Discipline
[257] = {82717, 82718}, --Holy
[258] = {82713, 82712}, --Shadow
[259] = {90740}, --Assassination
[260] = {90684}, --Outlaw
[261] = {90685}, --Subtlety
[262] = {81061, 81062}, --Elemental
[263] = {81060, 81061}, --Enhancement
[264] = {81062, 81063}, --Restoration
[265] = {71933}, --Affliction All The Same?
[266] = {71933}, --Demonology
[267] = {71933}, --Destruction
[71] = {90327}, --Arms
[72] = {90325}, --Fury
[73] = {90261, 90330}, --Protection
};
do
local total;
for specID, grantedNodeIDs in pairs(AUTO_GRANTED_NODES) do
total = #grantedNodeIDs;
for i = 1, total do
AUTO_GRANTED_NODES[specID][grantedNodeIDs[i]] = true;
AUTO_GRANTED_NODES[specID][i] = nil;
end
end
end
function DataProvider:IsAutoGrantedTalent(nodeID)
return self.autoGrantedNodes[nodeID]
end
function DataProvider:UpdateSpecInfo()
local specIndex = GetSpecialization() or 1;
local specID, specName = GetSpecializationInfo(specIndex);
self.specID = specID;
self.specName = specName;
self.autoGrantedNodes = AUTO_GRANTED_NODES[specID] or {};
end
function DataProvider:GetCurrentSpecID()
if not self.specID then
self:UpdateSpecInfo();
end
return self.specID
end
function DataProvider:GetCurrentSpecName()
if not self.specName then
self:UpdateSpecInfo();
end
return self.specName
end
function DataProvider:SetInspectSpecID(inspectSpecID)
self.inspectSpecID = inspectSpecID;
end
function DataProvider:GetInspectSpecID()
return self.inspectSpecID;
end
function DataProvider:IsInpsectSameSpec()
if self.inspectSpecID and self.inspectSpecID == self.specID then
return true
end
end
function DataProvider:SetInspectMode(state)
self.inspectMode = state;
if state then
self.GetEntryInfo = self.GetComparisonEntryInfo;
self.GetNodeInfo = self.GetComparisonNodeInfo;
else
self.GetEntryInfo = self.GetPlayerEntryInfo;
self.GetNodeInfo = self.GetPlayerNodeInfo;
end
end
3 years ago
function DataProvider:GetActiveLoadoutName()
local specID = self:GetCurrentSpecID();
local configs = C_ClassTalents.GetConfigIDsBySpecID(specID);
local total = #configs;
if total == 0 then
return TALENT_FRAME_DROP_DOWN_DEFAULT or "Default Loadout";
3 years ago
else
local selectedID = C_ClassTalents.GetLastSelectedSavedConfigID(specID);
local name;
if selectedID then
local info = C_Traits.GetConfigInfo(selectedID);
name = info and info.name;
end
return name or TALENT_FRAME_DROP_DOWN_DEFAULT or "Default Loadout"
3 years ago
end
end
function DataProvider:RefreshConfigIDs()
self.configNames = {};
self.configIDs = C_ClassTalents.GetConfigIDsBySpecID(self:GetCurrentSpecID());
end
function DataProvider:GetConfigIDs()
if not self.configIDs then
self:RefreshConfigIDs();
end
return self.configIDs
end
function DataProvider:GetConfigName(configID)
if not self.configNames[configID] then
local info = C_Traits.GetConfigInfo(configID);
self.configNames[configID] = (info and info.name) or "Unnamed Loadout";
end
return self.configNames[configID]
end
function DataProvider:IsConfigIDValid(configID)
if not self.configIDs then
self:RefreshConfigIDs();
end
if self.configIDs then
for i = 1, #self.configIDs do
if configID == self.configIDs[i] then
return true
end
end
end
return false
end
3 years ago
function DataProvider:GetSelecetdConfigID()
local specID = self:GetCurrentSpecID();
local selectedID = C_ClassTalents.GetLastSelectedSavedConfigID(specID);
if self:IsConfigIDValid(selectedID) then
return selectedID
else
return C_ClassTalents.GetActiveConfigID();
end
end
local NodeInfoCache = {};
local EntryInfoCache = {};
local ComparisonNodeInfoCache = {};
local ComparisonEntryInfoCache = {};
local PLAYER_ACTIVE_CONFIG_ID;
function DataProvider:SetPlayerActiveConfigID(configID)
if not configID then
configID = self:GetSelecetdConfigID();
end
if configID ~= PLAYER_ACTIVE_CONFIG_ID then
PLAYER_ACTIVE_CONFIG_ID = configID;
self:ClearPlayerCache();
end
end
function DataProvider.GetPlayerNodeInfo(nodeID)
if not NodeInfoCache[nodeID] then
NodeInfoCache[nodeID] = GetNodeInfo(PLAYER_ACTIVE_CONFIG_ID, nodeID);
end
return NodeInfoCache[nodeID]
end
function DataProvider.GetPlayerEntryInfo(entryID)
if not EntryInfoCache[entryID] then
EntryInfoCache[entryID] = GetEntryInfo(PLAYER_ACTIVE_CONFIG_ID, entryID);
end
return EntryInfoCache[entryID];
end
function DataProvider:ClearPlayerCache()
NodeInfoCache = {};
EntryInfoCache = {};
end
function DataProvider:ClearComparisonCache()
ComparisonNodeInfoCache = {};
ComparisonEntryInfoCache = {};
end
function DataProvider:ClearAllCache()
self:ClearPlayerCache();
self:ClearComparisonCache();
end
function DataProvider.GetComparisonNodeInfo(nodeID)
if not ComparisonNodeInfoCache[nodeID] then
ComparisonNodeInfoCache[nodeID] = GetNodeInfo(-1, nodeID);
end
return ComparisonNodeInfoCache[nodeID]
end
function DataProvider.GetComparisonEntryInfo(entryID)
if not ComparisonEntryInfoCache[entryID] then
ComparisonEntryInfoCache[entryID] = GetEntryInfo(-1, entryID);
end
return ComparisonEntryInfoCache[entryID]
end
DataProvider:SetInspectMode(false);
local CountdownFrame;
function DataProvider:StartCacheWipingCountdown()
if not CountdownFrame then
CountdownFrame = CreateFrame("Frame");
CountdownFrame:Hide();
CountdownFrame:SetScript("OnUpdate", function(f, elapsed)
f.t = f.t + elapsed;
if f.t >= 2 then
f:Hide();
self:ClearAllCache();
end
end);
end
CountdownFrame.t = 0;
CountdownFrame:Show();
end
function DataProvider:StopCacheWipingCountdown()
if CountdownFrame then
CountdownFrame:Hide();
end
end
function DataProvider:CanCreateNewConfig()
return C_ClassTalents.CanCreateNewConfig()
end
function DataProvider:IsLoadoutNameValid(newLoadoutName)
--capped at 30 characters
if not newLoadoutName then return end;
newLoadoutName = strtrim(newLoadoutName);
if newLoadoutName == "" then return end;
local configIDs = self:GetConfigIDs();
local name;
for i, configID in ipairs(configIDs) do
name = self:GetConfigName(configID);
if name == newLoadoutName then
return
end
end
return true
end
function DataProvider:SaveInpsectLoadout(newLoadoutName)
--/run DP:SaveInpsectLoadout()
if not self:IsInpsectSameSpec() then return false, "Wrong Spec" end;
if not self:CanCreateNewConfig() then
return false, "No Save Slot"
end
if not self:IsLoadoutNameValid(newLoadoutName) then
return false, "Invalid Name"
end
local configID = -1;
local configInfo = C_Traits.GetConfigInfo(configID);
local treeID = configInfo.treeIDs[1]
local nodeIDs = C_Traits.GetTreeNodes(treeID);
local nodeInfo;
local loadoutEntryInfo = {};
local count = 1;
local GetComparisonNodeInfo = self.GetComparisonNodeInfo;
for i, nodeID in ipairs(nodeIDs) do
nodeInfo = GetComparisonNodeInfo(nodeID);
if nodeInfo.ranksPurchased > 0 then
local result = {};
result.nodeID = nodeInfo.ID;
result.ranksPurchased = nodeInfo.ranksPurchased;
result.selectionEntryID = nodeInfo.activeEntry and nodeInfo.activeEntry.entryID or nil;
loadoutEntryInfo[count] = result;
count = count + 1;
end
end
--local requestResult = C_ClassTalents.RequestNewConfig(newLoadoutName);
configID = C_ClassTalents.GetActiveConfigID();
local success, errorString = C_ClassTalents.ImportLoadout(configID, loadoutEntryInfo, newLoadoutName);
return success, errorString
end
function DataProvider:GetLoadoutExportString()
--/run DP:GetLoadoutExportString()
local exportStream = ExportUtil.MakeExportDataStream();
local configID, specID;
if self.inspectMode then
configID = -1;
specID = self:GetInspectSpecID();
else
configID = self:GetSelecetdConfigID();
specID = self:GetCurrentSpecID();
end
local configInfo = C_Traits.GetConfigInfo(configID);
local treeID = configInfo.treeIDs[1];
local treeInfo = C_Traits.GetTreeInfo(configID, treeID);
local treeHash = C_Traits.GetTreeHash(treeInfo.ID);
local serializationVersion = (C_Traits.GetLoadoutSerializationVersion ~= nil and C_Traits.GetLoadoutSerializationVersion()) or 1;
--print("SpecID: ", specID, "ConfigID: ", configID, "treeID: ", treeID);
if ClassTalentImportExportMixin then
ClassTalentImportExportMixin:WriteLoadoutHeader(exportStream, serializationVersion, specID, treeHash);
ClassTalentImportExportMixin:WriteLoadoutContent(exportStream, configID, treeInfo.ID);
else
--copy past from Blizzard_ClassTalentImportExport.lua
local function GetActiveEntryIndex(treeNode)
for i, entryID in ipairs(treeNode.entryIDs) do
if(entryID == treeNode.activeEntry.entryID) then
return i;
end
end
return 0;
end
local bitWidthHeaderVersion = 8;
local bitWidthSpecID = 16;
local bitWidthRanksPurchased = 6;
--ClassTalentImportExportMixin.WriteLoadoutHeader
exportStream:AddValue(bitWidthHeaderVersion, serializationVersion);
exportStream:AddValue(bitWidthSpecID, specID);
for i, hashVal in ipairs(treeHash) do
exportStream:AddValue(8, hashVal);
end
--WriteLoadoutContent(exportStream, configID, treeID)
local treeNodes = C_Traits.GetTreeNodes(treeID);
local typeSelection = Enum.TraitNodeType.Selection;
for i, nodeID in ipairs(treeNodes) do
local treeNode = C_Traits.GetNodeInfo(configID, nodeID);
local isNodeSelected = treeNode.ranksPurchased > 0;
local isPartiallyRanked = treeNode.ranksPurchased ~= treeNode.maxRanks;
local isChoiceNode = treeNode.type == typeSelection;
exportStream:AddValue(1, isNodeSelected and 1 or 0);
if(isNodeSelected) then
exportStream:AddValue(1, isPartiallyRanked and 1 or 0);
if(isPartiallyRanked) then
exportStream:AddValue(bitWidthRanksPurchased, treeNode.ranksPurchased);
end
exportStream:AddValue(1, isChoiceNode and 1 or 0);
if(isChoiceNode) then
local entryIndex = GetActiveEntryIndex(treeNode);
exportStream:AddValue(2, entryIndex - 1);
end
end
end
end
local exportString = exportStream:GetExportString();
return exportString or "ERROR";
end
--[[
function DataProvider:EncodeActiveLoadout()
local configID = C_ClassTalents.GetActiveConfigID();
local configInfo = C_Traits.GetConfigInfo(configID);
local treeID = configInfo.treeIDs[1]
local nodeIDs = C_Traits.GetTreeNodes(treeID);
local nodeInfo, activeEntryID, entryInfo, talentType, entryIDs;
local n = 0;
local state;
local states = {};
local numInvisible = 0;
local nodeBits = {};
local maxRanks
local numBits = 0;
local definitionIDs = {};
table.sort(nodeIDs);
--print("ConfigID: "..configID)
for i, nodeID in ipairs(nodeIDs) do
nodeInfo = GetNodeInfo(configID, nodeID);
if nodeInfo.isVisible then
n = n + 1;
activeEntryID = nodeInfo.activeEntry and nodeInfo.activeEntry.entryID or nil;
entryInfo = (activeEntryID ~= nil) and GetEntryInfo(configID, activeEntryID) or nil;
talentType = (entryInfo ~= nil) and entryInfo.type or nil;
if entryInfo then
definitionIDs[n] = entryInfo.definitionID;
NI = nodeInfo
else
print(n.." Missing EntryInfo Node: "..nodeID)
end
maxRanks = nodeInfo.maxRanks or 1;
if maxRanks > 1 or nodeInfo.type == 2 then
numBits = 2;
else
numBits = 1;
end
if (nodeInfo.ranksPurchased > 0) then
if nodeInfo.type == 2 then
if activeEntryID == nodeInfo.entryIDs[1] then
state = 1;
elseif activeEntryID == nodeInfo.entryIDs[2] then
state = 2;
else
state = 0;
end
else
if talentType == 1 then --square
state = 1;
else
state = nodeInfo.ranksPurchased;
end
end
else
state = 0;
end
states[n] = state;
nodeBits[n] = numBits;
else
numInvisible = numInvisible + 1;
end
end
local str1 = "";
local str2 = "";
local method = 3;
if method == 1 then
for i = 1, n do
state = states[i];
if state > 1 then
state = state - 1;
str1 = str1.."1";
str2 = str2.."1";
else
str1 = str1..state;
str2 = str2.."0";
end
end
TestEditBox:SetText(str1.."/"..str2);
elseif method == 2 then
for i = 1, n do
str1 = str1 .. states[i];
end
TestEditBox:SetText(str1);
else
local nodeID, defID;
for i = 1, n do
state = states[i];
if nodeBits[i] > 1 then
if state == 0 then
str1 = str1.."00";
elseif state == 1 then
str1 = str1.."01";
elseif state == 2 then
str1 = str1.."10";
elseif state == 3 then
str1 = str1.."11";
else
print(n, "Error", state)
end
else
if state == 0 then
str1 = str1.."0";
elseif state == 1 then
str1 = str1.."1";
else
nodeID = nodeIDs[i];
defID = definitionIDs[i];
print(string.format("Error: #%d NodeID: %d DefID: %d State: %d", i, nodeID, defID, state));
end
end
end
TestEditBox:SetText(str1);
end
print("Num Nodes: "..#nodeIDs);
print("Visible: "..n);
print("Invisible: "..numInvisible)
print("Length: "..string.len(str1));
--/run DP:EncodeActiveLoadout()
-- WoW: BYQAfcj78nJtvjmejSqe5Zhm9AAAAAAg0SpUSSJJhDkIJFAkkkDAAAAAAAlIBKJRJFgIlEJNQ0SCcAA
-- A+B: NUglRmSSDZxxJru,BqOmv4JxOqzPzgY
-- Method3: 6OkckwLRJTeZtXuaYDe
-- Base4: pWLnmG8bWFZq6qT4rBwGNbKeZBLLYk
-- Traverse: 2WMvI9gucZR,1Pk9JYiTVE
--(49,31) (40, 30)
--11554258485616
--Tier Choices 25, 40
--0000111101100010-1101001101011000-0011010000010100-1101011111000110-1100001110011101-1000000011111110-0000010111011000-00
--000011110110001011010011010110000011010000010100110101111100011011000011100111011000000011111110000001011011100000
--000011110110001011010011011010000011010000010100110101111100011011000011100111011000000011111110000001011011100000
--BYGAGX1kx6Mci9Zl2t+S+sRoPCAAAAAAAAAAAAAAAAAAAoBkkkIJSSAQSSCIpkQSkDkGiEJJJtkSkEkAA
--010000110111100111111110000000000011111110000000011011100011010010011100000101100110111011011011011100011000
--sWg63isv9pnSt1xNwI
end
DP = DataProvider;
local TestEditBox = CreateFrame("EditBox", "TestEditBox");
TestEditBox:SetSize(120, 24);
TestEditBox:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
TestEditBox:SetFontObject("GameFontNormal");
TestEditBox:SetAutoFocus(false);
TestEditBox:SetScript("OnEscapePressed", function(self)
self:ClearFocus();
end);
TestEditBox.Background = TestEditBox:CreateTexture(nil, "BACKGROUND");
TestEditBox.Background:SetAllPoints(true);
TestEditBox.Background:SetColorTexture(0, 0, 0, 0.5);
function CalculateCombo(m, n)
local v = 1.0;
local p;
for i = 1.0, n, 1.0 do
p = (m - i + 1.0) / i
v = v * p ;
print(i, v)
end
TestEditBox:SetText(v)
3 years ago
end
--]]