Skip to content

Commit 38fbd82

Browse files
committed
Initial support for leveling builds
1 parent 46ef024 commit 38fbd82

File tree

5 files changed

+316
-53
lines changed

5 files changed

+316
-53
lines changed

TalentTreeViewer/ImportExport.lua

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ local TalentViewer = ns.TalentViewer
88
local L = LibStub("AceLocale-3.0"):GetLocale(name);
99

1010
local LOADOUT_SERIALIZATION_VERSION = 1;
11+
local LEVELING_BUILD_SERIALIZATION_VERSION = 1;
12+
local LEVELING_EXPORT_STRING_PATERN = "%s-LVL-%s";
1113

1214
local getNodeInfo = function(nodeId) return TalentViewer:GetTalentFrame():GetAndCacheNodeInfo(nodeId) end
1315

@@ -18,6 +20,9 @@ function ImportExport:GetSpecId()
1820
return TalentViewer.selectedSpecId;
1921
end
2022

23+
ImportExport.levelingBitWidthVersion = 5;
24+
ImportExport.levelingBitWidthData = 7; -- allows for 128 order indexes
25+
2126
----- copied and adapted from Blizzard_ClassTalentImportExport.lua -----
2227

2328
ImportExport.bitWidthHeaderVersion = 8;
@@ -116,6 +121,30 @@ function ImportExport:ReadLoadoutContent(importStream, treeID)
116121
return results;
117122
end
118123

124+
function ImportExport:WriteLevelingExportHeader(exportStream, serializationVersion)
125+
exportStream:AddValue(self.levelingBitWidthVersion, serializationVersion);
126+
end
127+
128+
--- @param treeID number
129+
--- @param levelingBuild TalentViewer_LevelingBuildEntry[]
130+
function ImportExport:WriteLevelingBuildContent(exportStream, treeID, levelingBuild)
131+
--- @type table<number, number[]>
132+
local byNodes = {};
133+
for index, entry in ipairs(levelingBuild) do
134+
byNodes[entry.nodeID] = byNodes[entry.nodeID] or {};
135+
table.insert(byNodes[entry.nodeID], index);
136+
end
137+
138+
local treeNodes = C_Traits.GetTreeNodes(treeID);
139+
for _, treeNodeID in ipairs(treeNodes) do
140+
local entries = byNodes[treeNodeID];
141+
if entries then
142+
for _, entry in ipairs(entries) do
143+
exportStream:AddValue(7, entry);
144+
end
145+
end
146+
end
147+
end
119148

120149
function ImportExport:GetLoadoutExportString()
121150
local exportStream = ExportUtil.MakeExportDataStream();
@@ -125,7 +154,19 @@ function ImportExport:GetLoadoutExportString()
125154
self:WriteLoadoutHeader(exportStream, LOADOUT_SERIALIZATION_VERSION, currentSpecID);
126155
self:WriteLoadoutContent(exportStream, treeId);
127156

128-
return exportStream:GetExportString();
157+
local loadoutString = exportStream:GetExportString();
158+
159+
local levelingBuildID = TalentViewer:GetCurrentLevelingBuildID();
160+
local levelingBuild = TalentViewer:GetLevelingBuild(levelingBuildID);
161+
if not levelingBuild or not next(levelingBuild) then
162+
return loadoutString;
163+
end
164+
165+
local levelingExportStream = ExportUtil.MakeExportDataStream();
166+
self:WriteLevelingExportHeader(levelingExportStream, LEVELING_BUILD_SERIALIZATION_VERSION);
167+
self:WriteLevelingBuildContent(levelingExportStream, treeId, levelingBuild);
168+
169+
return LEVELING_EXPORT_STRING_PATERN:format(loadoutString, levelingExportStream:GetExportString());
129170
end
130171

131172
function ImportExport:ShowImportError(errorString)
@@ -157,8 +198,15 @@ function ImportExport:ImportLoadout(importText)
157198
local loadoutContent = self:ReadLoadoutContent(importStream, treeId);
158199
local loadoutEntryInfo = self:ConvertToImportLoadoutEntryInfo(treeId, loadoutContent);
159200

201+
local hasLevelingBuildData, recordingIsActive = false, TalentViewer:IsRecordingLevelingBuild();
202+
if not hasLevelingBuildData then
203+
TalentViewer.recordingInfo.active = false
204+
end
205+
160206
TalentViewer:GetTalentFrame():ImportLoadout(loadoutEntryInfo);
161207

208+
TalentViewer.recordingInfo.active = recordingIsActive;
209+
162210
return true;
163211
end
164212

TalentTreeViewer/TalentViewer.lua

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ function TalentViewer:ResetTree()
111111
talentFrame:UpdateClassVisuals();
112112
talentFrame:UpdateSpecBackground();
113113
talentFrame:UpdateLevelingBuildHighlights();
114+
self:ClearLevelingBuild();
115+
self:StartRecordingLevelingBuild();
114116
end
115117

116118
function TalentViewer:GetActiveRank(nodeID)
@@ -137,18 +139,40 @@ end
137139
function TalentViewer:PurchaseRank(nodeID)
138140
self:ReduceCurrency(nodeID)
139141
self.purchasedRanks[nodeID] = (self.purchasedRanks[nodeID] or 0) + 1
142+
143+
if self:IsRecordingLevelingBuild() then
144+
self:RecordLevelingEntry(nodeID, self.purchasedRanks[nodeID])
145+
end
140146
end
141147

142148
function TalentViewer:RefundRank(nodeID)
143149
self:RestoreCurrency(nodeID)
144150
self.purchasedRanks[nodeID] = (self.purchasedRanks[nodeID] or 0) - 1
151+
152+
if self:IsRecordingLevelingBuild() then
153+
self:RemoveLastRecordedLevelingEntry(nodeID)
154+
end
145155
end
146156

147157
function TalentViewer:SetSelection(nodeID, entryID)
148-
if (entryID and not self.selectedEntries[nodeID]) then
158+
local hasPreviousSelection = self.selectedEntries[nodeID] ~= nil
159+
160+
if (entryID and hasPreviousSelection and entryID ~= self.selectedEntries[nodeID]) then
161+
if self:IsRecordingLevelingBuild() then
162+
self:UpdateRecordedLevelingChoiceEntry(nodeID, entryID)
163+
end
164+
elseif (entryID and not hasPreviousSelection) then
149165
self:ReduceCurrency(nodeID)
150-
elseif (not entryID and self.selectedEntries[nodeID]) then
166+
167+
if self:IsRecordingLevelingBuild() then
168+
self:RecordLevelingEntry(nodeID, 1, entryID)
169+
end
170+
elseif (not entryID and hasPreviousSelection) then
151171
self:RestoreCurrency(nodeID)
172+
173+
if self:IsRecordingLevelingBuild() then
174+
self:RemoveLastRecordedLevelingEntry(nodeID)
175+
end
152176
end
153177

154178
self.selectedEntries[nodeID] = entryID
@@ -393,13 +417,101 @@ end
393417
-----------------------
394418
--- Leveling builds ---
395419
-----------------------
420+
local defaultRecordingInfo = {
421+
active = true,
422+
buildID = 0, -- matches #levelingBuilds, effectively an auto increment
423+
currentIndex = 0,
424+
entries = {},
425+
}
426+
--- @type table<number, TalentViewer_LevelingBuildEntry[]> # [buildID] = entries
427+
TalentViewer.levelingBuilds = {};
428+
TalentViewer.recordingInfo = CreateFromMixins(defaultRecordingInfo);
429+
430+
function TalentViewer:GetCurrentLevelingBuildID()
431+
return self.recordingInfo.buildID;
432+
end
433+
434+
--- @param buildID number
435+
--- @return nil|TalentViewer_LevelingBuildEntry[]
396436
function TalentViewer:GetLevelingBuild(buildID)
397-
return; -- TODO
437+
return self.levelingBuilds[buildID] or nil;
398438
end
399439

400440
function TalentViewer:ApplyLevelingBuild(buildID, level)
401-
self:GetTalentFrame():SetLevelingBuildID(buildID)
402-
self:GetTalentFrame():ApplyLevelingBuild(level)
441+
local buildEntries = self:GetLevelingBuild(buildID);
442+
if (not buildEntries or not next(buildEntries)) then
443+
return;
444+
end
445+
446+
self.recordingInfo.active = false; -- todo: fix
447+
448+
self:GetTalentFrame():SetLevelingBuildID(buildID);
449+
self:GetTalentFrame():ApplyLevelingBuild(level);
450+
self.recordingInfo.active = true;
451+
end
452+
453+
function TalentViewer:StartRecordingLevelingBuild()
454+
self.recordingInfo.active = true;
455+
self:GetTalentFrame().StartRecordingButton:Hide();
456+
self:GetTalentFrame().StopRecordingButton:Show();
457+
end
458+
459+
function TalentViewer:StopRecordingLevelingBuild()
460+
self.recordingInfo.active = false;
461+
self:GetTalentFrame().StartRecordingButton:Show();
462+
self:GetTalentFrame().StopRecordingButton:Hide();
463+
end
464+
465+
function TalentViewer:ClearLevelingBuild()
466+
for _, button in ipairs(self:GetTalentFrame().levelingOrderButtons) do
467+
button:SetOrder({});
468+
end
469+
self.recordingInfo = CopyTable(defaultRecordingInfo);
470+
self:StopRecordingLevelingBuild();
471+
table.insert(self.levelingBuilds, self.recordingInfo.entries);
472+
self.recordingInfo.buildID = #self.levelingBuilds;
473+
end
474+
475+
function TalentViewer:IsRecordingLevelingBuild()
476+
return self.recordingInfo.active;
477+
end
478+
479+
--- @param nodeID number
480+
--- @param targetRank number
481+
--- @param entryID ?number
482+
function TalentViewer:RecordLevelingEntry(nodeID, targetRank, entryID)
483+
local currentIndex = self.recordingInfo.currentIndex + 1;
484+
self.recordingInfo.entries[currentIndex] = {
485+
nodeID = nodeID,
486+
targetRank = targetRank,
487+
entryID = entryID,
488+
};
489+
self.recordingInfo.currentIndex = currentIndex;
490+
491+
self:GetTalentFrame():GetTalentButtonByNodeID(nodeID).LevelingOrder:AppendToOrder(currentIndex);
492+
end
493+
494+
function TalentViewer:RemoveLastRecordedLevelingEntry(nodeID)
495+
local currentIndex = self.recordingInfo.currentIndex;
496+
for i = currentIndex, 1, -1 do
497+
local entry = self.recordingInfo.entries[i];
498+
if (entry.nodeID == nodeID) then
499+
table.remove(self.recordingInfo.entries, i);
500+
self.recordingInfo.currentIndex = i - 1;
501+
return;
502+
end
503+
end
504+
end
505+
506+
function TalentViewer:UpdateRecordedLevelingChoiceEntry(nodeID, entryID)
507+
local currentIndex = self.recordingInfo.currentIndex;
508+
for i = currentIndex, 1, -1 do
509+
local entry = self.recordingInfo.entries[i];
510+
if (entry.nodeID == nodeID) then
511+
entry.entryID = entryID;
512+
return;
513+
end
514+
end
403515
end
404516

405517
-------------------------

TalentTreeViewer/TalentViewerUI.xml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,55 @@
324324
<HitRectInsets left="0" right="-100" top="0" bottom="0"/>
325325
</CheckButton>
326326

327+
<Button parentKey="StartRecordingButton" inherits="UIPanelButtonTemplate, UIButtonTemplate" text="Start Leveling Build Recording" hidden="true"> <!-- text="TALENT_TREE_VIEWER_LOCALE_START_RECORDING" -->
328+
<KeyValues>
329+
<!-- <KeyValue key="tooltipText" value="TALENT_FRAME_DISCARD_CHANGES_BUTTON_TOOLTIP" type="global"/>-->
330+
<KeyValue key="tooltipText" value="Start recording a leveling build, starting with the current build"/>
331+
<KeyValue key="tooltipTextColor" value="HIGHLIGHT_FONT_COLOR" type="global"/>
332+
</KeyValues>
333+
<Size x="220" y="25"/>
334+
<Anchors>
335+
<Anchor point="RIGHT" relativeKey="$parent.BottomBar" relativePoint="RIGHT" x="-10" y="3"/>
336+
</Anchors>
337+
<Scripts>
338+
<OnClick>
339+
self:GetParent():GetTalentViewer():StartRecordingLevelingBuild()
340+
</OnClick>
341+
</Scripts>
342+
</Button>
343+
<Button parentKey="StopRecordingButton" inherits="UIPanelButtonTemplate, UIButtonTemplate" text="Stop Leveling Build Recording" hidden="true"> <!-- text="TALENT_TREE_VIEWER_LOCALE_STOP_RECORDING" -->
344+
<KeyValues>
345+
<!-- <KeyValue key="tooltipText" value="TALENT_FRAME_DISCARD_CHANGES_BUTTON_TOOLTIP" type="global"/>-->
346+
<KeyValue key="tooltipText" value="Stop recording the leveling build"/>
347+
<KeyValue key="tooltipTextColor" value="HIGHLIGHT_FONT_COLOR" type="global"/>
348+
</KeyValues>
349+
<Size x="220" y="25"/>
350+
<Anchors>
351+
<Anchor point="RIGHT" relativeKey="$parent.BottomBar" relativePoint="RIGHT" x="-10" y="3"/>
352+
</Anchors>
353+
<Scripts>
354+
<OnClick>
355+
self:GetParent():GetTalentViewer():StopRecordingLevelingBuild()
356+
</OnClick>
357+
</Scripts>
358+
</Button>
359+
<Button parentKey="ResetRecordingButton" inherits="UIPanelButtonTemplate, UIButtonTemplate" text="Reset Leveling Build Recording"> <!-- text="TALENT_TREE_VIEWER_LOCALE_STOP_RECORDING" -->
360+
<KeyValues>
361+
<!-- <KeyValue key="tooltipText" value="TALENT_FRAME_DISCARD_CHANGES_BUTTON_TOOLTIP" type="global"/>-->
362+
<KeyValue key="tooltipText" value="Reset leveling build recording"/>
363+
<KeyValue key="tooltipTextColor" value="HIGHLIGHT_FONT_COLOR" type="global"/>
364+
</KeyValues>
365+
<Size x="220" y="25"/>
366+
<Anchors>
367+
<Anchor point="TOPRIGHT" relativeKey="$parent.StopRecordingButton" relativePoint="BOTTOMRIGHT" x="0" y="-3"/>
368+
</Anchors>
369+
<Scripts>
370+
<OnClick>
371+
self:GetParent():GetTalentViewer():ClearLevelingBuild()
372+
</OnClick>
373+
</Scripts>
374+
</Button>
375+
327376
<Button parentKey="UndoButton" inherits="IconButtonTemplate" hidden="true">
328377
<KeyValues>
329378
<KeyValue key="iconAtlas" value="talents-button-undo" type="string"/>

0 commit comments

Comments
 (0)