From 084ada492907fd528f2aa3374240e519596447f7 Mon Sep 17 00:00:00 2001 From: David Allen Date: Sun, 17 Oct 2021 23:01:47 -0700 Subject: [PATCH 1/6] Option on passive tree tab to show order of passive allocation. Useful for build guides --- src/Classes/PassiveSpec.lua | 92 +++++++++++++++++++++++++++++++-- src/Classes/PassiveTreeView.lua | 18 +++++++ src/Classes/TreeTab.lua | 9 +++- 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index 9ee45f4762..55343b30a1 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -58,6 +58,11 @@ local PassiveSpecClass = newClass("PassiveSpec", "UndoHandler", function(self, b -- Keys are mastery node IDs, values are mastery effect IDs self.masterySelections = { } + -- List of node allocation order + -- Keys are order indexes, values are node IDs + self.allocationOrder = { } + self.ascendancyAllocationOrder = { } + self:SelectClass(0) end) @@ -116,6 +121,14 @@ function PassiveSpecClass:Load(xml, dbFileName) end end self:ImportFromNodeList(tonumber(xml.attrib.classId), tonumber(xml.attrib.ascendClassId), hashList, masteryEffects) + for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do + table.insert(self.allocationOrder, tonumber(nodeId)) + end + for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do + table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) + end + self:ReIndexAllocationOrder("allocationOrder") + self:ReIndexAllocationOrder("ascendancyAllocationOrder") elseif url then self:DecodeURL(url) end @@ -201,7 +214,9 @@ function PassiveSpecClass:Save(xml) classId = tostring(self.curClassId), ascendClassId = tostring(self.curAscendClassId), nodes = table.concat(allocNodeIdList, ","), - masteryEffects = table.concat(masterySelections, ",") + masteryEffects = table.concat(masterySelections, ","), + allocationOrder = table.concat(self.allocationOrder, ","), + ascendancyAllocationOrder = table.concat(self.ascendancyAllocationOrder, ",") } t_insert(xml, { -- Legacy format @@ -382,6 +397,32 @@ function PassiveSpecClass:ResetNodes() wipeTable(self.masterySelections) end +function PassiveSpecClass:SetAllocationOrder(node) + if node.ascendancyName then + t_insert(self.ascendancyAllocationOrder, node.id) + node.ascendancyAllocationOrder = #self.ascendancyAllocationOrder + else + t_insert(self.allocationOrder, node.id) + node.allocationOrder = #self.allocationOrder + end +end + +function PassiveSpecClass:RemoveFromAllocationOrder(node) + if node.ascendancyName then + t_remove(self.ascendancyAllocationOrder, node.ascendancyAllocationOrder) + node.ascendancyAllocationOrder = nil + else + t_remove(self.allocationOrder, node.allocationOrder) + node.allocationOrder = nil + end +end + +function PassiveSpecClass:ReIndexAllocationOrder(allocationOrder) + for i, nodeId in ipairs(self[allocationOrder]) do + self.nodes[nodeId][allocationOrder] = i + end +end + -- Allocate the given node, if possible, and all nodes along the path to the node -- An alternate path to the node may be provided, otherwise the default path will be used -- The path must always contain the given node, as will be the case for the default path @@ -395,10 +436,14 @@ function PassiveSpecClass:AllocNode(node, altPath) if node.dependsOnIntuitiveLeapLike then node.alloc = true self.allocNodes[node.id] = node + self:SetAllocationOrder(node) else - for _, pathNode in ipairs(altPath or node.path) do + local path = altPath or node.path + for i = #(path), 1, -1 do + local pathNode = path[i] pathNode.alloc = true self.allocNodes[pathNode.id] = pathNode + self:SetAllocationOrder(pathNode) end end @@ -407,8 +452,12 @@ function PassiveSpecClass:AllocNode(node, altPath) local parent = node.linked[1] for _, optNode in ipairs(parent.linked) do if optNode.isMultipleChoiceOption and optNode.alloc and optNode ~= node then - optNode.alloc = false - self.allocNodes[optNode.id] = nil + self.DeallocSingleNode(optNode) + if optNode.ascendancyName then + self:ReIndexAllocationOrder("ascendancyAllocationOrder") + else + self:ReIndexAllocationOrder("allocationOrder") + end end end end @@ -424,14 +473,47 @@ function PassiveSpecClass:DeallocSingleNode(node) self:AddMasteryEffectOptionsToNode(node) self.masterySelections[node.id] = nil end + if self.allocationOrder[node.allocationOrder] or self.ascendancyAllocationOrder[node.ascendancyAllocationOrder] then + self:RemoveFromAllocationOrder(node) + end end -- Deallocate the given node, and all nodes which depend on it (i.e. which are only connected to the tree through this node) function PassiveSpecClass:DeallocNode(node) - local effect + if node.ascendancyName then + table.sort(node.depends, function(a, b) + if a.ascendancyAllocationOrder == nil and b.ascendancyAllocationOrder == nil then + return false + elseif a.ascendancyAllocationOrder == nil then + return true + elseif b.ascendancyAllocationOrder == nil then + return false + else + return a.ascendancyAllocationOrder > b.ascendancyAllocationOrder + end + end) + else + table.sort(node.depends, function(a, b) + if a.allocationOrder == nil and b.allocationOrder == nil then + return false + elseif a.allocationOrder == nil then + return true + elseif b.allocationOrder == nil then + return false + else + return a.allocationOrder > b.allocationOrder + end + end) + end + for _, depNode in ipairs(node.depends) do self:DeallocSingleNode(depNode) end + if node.ascendancyName then + self:ReIndexAllocationOrder("ascendancyAllocationOrder") + else + self:ReIndexAllocationOrder("allocationOrder") + end -- Rebuild all paths and dependencies for all allocated nodes self:BuildAllDependsAndPaths() diff --git a/src/Classes/PassiveTreeView.lua b/src/Classes/PassiveTreeView.lua index 1cfdef49ca..1b2c1dcc62 100644 --- a/src/Classes/PassiveTreeView.lua +++ b/src/Classes/PassiveTreeView.lua @@ -75,6 +75,9 @@ function PassiveTreeViewClass:Load(xml, fileName) if xml.attrib.searchStr then self.searchStr = xml.attrib.searchStr end + if xml.attrib.showAllocationOrder then + self.showAllocationOrder = xml.attrib.showAllocationOrder == "true" + end if xml.attrib.showHeatMap then self.showHeatMap = xml.attrib.showHeatMap == "true" end @@ -89,6 +92,7 @@ function PassiveTreeViewClass:Save(xml) zoomX = tostring(self.zoomX), zoomY = tostring(self.zoomY), searchStr = self.searchStr, + showAllocationOrder = tostring(self.showAllocationOrder), showHeatMap = tostring(self.showHeatMap), showStatDifferences = tostring(self.showStatDifferences), } @@ -670,6 +674,20 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) local size = 175 * scale / self.zoom ^ 0.4 DrawImage(self.highlightRing, scrX - size, scrY - size, size * 2, size * 2) end + if self.showAllocationOrder and node.allocationOrder ~= nil then + SetDrawLayer(nile, 29) + SetDrawColor(1, 0, 0) + local size = 100 * scale + local offset = node.size * 1.8 * scale + DrawString(m_floor(scrX - offset), m_floor(scrY - offset), "LEFT", size, "VAR", tostring(node.allocationOrder)) + end + if self.showAllocationOrder and node.ascendancyAllocationOrder ~= nil then + SetDrawLayer(nile, 29) + SetDrawColor(1, 0, 0) + local size = 100 * scale + local offset = node.size * 1.8 * scale + DrawString(m_floor(scrX - offset), m_floor(scrY - offset), "LEFT", size, "VAR", tostring(node.ascendancyAllocationOrder)) + end if node == hoverNode and (node.type ~= "Socket" or not IsKeyDown("SHIFT")) and (node.type ~= "Mastery" or node.masteryEffects) and not IsKeyDown("CTRL") and not main.popups[1] then -- Draw tooltip SetDrawLayer(nil, 100) diff --git a/src/Classes/TreeTab.lua b/src/Classes/TreeTab.lua index af41f5588c..a4db52b7b5 100644 --- a/src/Classes/TreeTab.lua +++ b/src/Classes/TreeTab.lua @@ -107,8 +107,11 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build) self.controls.treeSearch = new("EditControl", {"LEFT",self.controls.export,"RIGHT"}, 8, 0, main.portraitMode and 200 or 300, 20, "", "Search", "%c%(%)", 100, function(buf) self.viewer.searchStr = buf end) - self.controls.treeSearch.tooltipText = "Uses Lua pattern matching for complex searches" - self.controls.treeHeatMap = new("CheckBoxControl", {"LEFT",self.controls.treeSearch,"RIGHT"}, 130, 0, 20, "Show Node Power:", function(state) + self.controls.treeSearch.tooltipText = "Uses Lua pattern matching for complex searches" + self.controls.treeAllocationOrder = new("CheckBoxControl", {"LEFT",self.controls.treeSearch,"RIGHT"}, 194, 0, 20, "Show Node Allocation Order:", function(state) + self.viewer.showAllocationOrder = state + end) + self.controls.treeHeatMap = new("CheckBoxControl", {"LEFT",self.controls.treeAllocationOrder,"RIGHT"}, 130, 0, 20, "Show Node Power:", function(state) self.viewer.showHeatMap = state self.controls.treeHeatMapStatSelect.shown = state end) @@ -228,6 +231,8 @@ function TreeTabClass:Draw(viewPort, inputEvents) self.controls.treeSearch:SetText(self.viewer.searchStr) end + self.controls.treeAllocationOrder.state = self.viewer.showAllocationOrder + self.controls.treeHeatMap.state = self.viewer.showHeatMap self.controls.treeHeatMapStatSelect.list = self.powerStatList self.controls.treeHeatMapStatSelect.selIndex = 1 From f3b42f39556db359f3f54b47ae83e6c77013f50d Mon Sep 17 00:00:00 2001 From: David Allen Date: Sun, 17 Oct 2021 23:49:19 -0700 Subject: [PATCH 2/6] Now properly removes node allocation order on changing class or ascendancy, and resetting tree. --- src/Classes/PassiveSpec.lua | 85 +++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index 55343b30a1..118abfedd9 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -120,15 +120,19 @@ function PassiveSpecClass:Load(xml, dbFileName) masteryEffects[tonumber(mastery)] = tonumber(effect) end end - self:ImportFromNodeList(tonumber(xml.attrib.classId), tonumber(xml.attrib.ascendClassId), hashList, masteryEffects) - for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do - table.insert(self.allocationOrder, tonumber(nodeId)) - end - for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do - table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) + self:ImportFromNodeList(tonumber(xml.attrib.classId), tonumber(xml.attrib.ascendClassId), hashList) + if xml.attrib.allocationOrder then + for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do + table.insert(self.allocationOrder, tonumber(nodeId)) + end + self:ReIndexAllocationOrder("allocationOrder") + end + if xml.attrib.ascendancyAllocationOrder then + for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do + table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) + end + self:ReIndexAllocationOrder("ascendancyAllocationOrder") end - self:ReIndexAllocationOrder("allocationOrder") - self:ReIndexAllocationOrder("ascendancyAllocationOrder") elseif url then self:DecodeURL(url) end @@ -347,8 +351,10 @@ function PassiveSpecClass:SelectAscendClass(ascendClassId) if node.ascendancyName and node.ascendancyName ~= ascendClass.name then node.alloc = false self.allocNodes[id] = nil + self:RemoveFromAllocationOrder(node) end end + self:ReIndexAllocationOrder("ascendancyAllocationOrder") if ascendClass.startNodeId then -- Allocate the new ascendancy class's start node @@ -388,13 +394,18 @@ end -- Clear the allocated status of all non-class-start nodes function PassiveSpecClass:ResetNodes() + ConPrintf("reset") for id, node in pairs(self.nodes) do if node.type ~= "ClassStart" and node.type ~= "AscendClassStart" then node.alloc = false + node.allocationOrder = nil + node.ascendancyAllocationOrder = nil self.allocNodes[id] = nil end end wipeTable(self.masterySelections) + self.allocationOrder = { } + self.ascendancyAllocationOrder = { } end function PassiveSpecClass:SetAllocationOrder(node) @@ -423,10 +434,39 @@ function PassiveSpecClass:ReIndexAllocationOrder(allocationOrder) end end +function PassiveSpecClass:SortNodesForRemovingFromAllocationOrder(node, depNodes) + if node.ascendancyName then + table.sort(depNodes, function(a, b) + if a.ascendancyAllocationOrder == nil and b.ascendancyAllocationOrder == nil then + return false + elseif a.ascendancyAllocationOrder == nil then + return true + elseif b.ascendancyAllocationOrder == nil then + return false + else + return a.ascendancyAllocationOrder > b.ascendancyAllocationOrder + end + end) + else + table.sort(depNodes, function(a, b) + if a.allocationOrder == nil and b.allocationOrder == nil then + return false + elseif a.allocationOrder == nil then + return true + elseif b.allocationOrder == nil then + return false + else + return a.allocationOrder > b.allocationOrder + end + end) + end +end + -- Allocate the given node, if possible, and all nodes along the path to the node -- An alternate path to the node may be provided, otherwise the default path will be used -- The path must always contain the given node, as will be the case for the default path function PassiveSpecClass:AllocNode(node, altPath) + ConPrintTable(self.allocationOrder) if not node.path then -- Node cannot be connected to the tree as there is no possible path return @@ -480,31 +520,7 @@ end -- Deallocate the given node, and all nodes which depend on it (i.e. which are only connected to the tree through this node) function PassiveSpecClass:DeallocNode(node) - if node.ascendancyName then - table.sort(node.depends, function(a, b) - if a.ascendancyAllocationOrder == nil and b.ascendancyAllocationOrder == nil then - return false - elseif a.ascendancyAllocationOrder == nil then - return true - elseif b.ascendancyAllocationOrder == nil then - return false - else - return a.ascendancyAllocationOrder > b.ascendancyAllocationOrder - end - end) - else - table.sort(node.depends, function(a, b) - if a.allocationOrder == nil and b.allocationOrder == nil then - return false - elseif a.allocationOrder == nil then - return true - elseif b.allocationOrder == nil then - return false - else - return a.allocationOrder > b.allocationOrder - end - end) - end + self:SortNodesForRemovingFromAllocationOrder(node, node.depends) for _, depNode in ipairs(node.depends) do self:DeallocSingleNode(depNode) @@ -856,6 +872,7 @@ function PassiveSpecClass:BuildAllDependsAndPaths() if not anyStartFound then -- No start nodes were found through ANY nodes -- Therefore this node and all nodes depending on it are orphans and should be pruned + self:SortNodesForRemovingFromAllocationOrder(node, node.depends) for _, depNode in ipairs(node.depends) do local prune = true for nodeId, itemId in pairs(self.jewels) do @@ -882,6 +899,8 @@ function PassiveSpecClass:BuildAllDependsAndPaths() self:DeallocSingleNode(depNode) end end + self:ReIndexAllocationOrder("allocationOrder") + self:ReIndexAllocationOrder("ascendancyAllocationOrder") end end From 5d830620a6425913b4f3af02a3473fc44f766d37 Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 18 Oct 2021 01:21:03 -0700 Subject: [PATCH 3/6] Added support for swapping out cluster jewels --- src/Classes/PassiveSpec.lua | 38 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index 118abfedd9..c81d747db2 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -121,18 +121,18 @@ function PassiveSpecClass:Load(xml, dbFileName) end end self:ImportFromNodeList(tonumber(xml.attrib.classId), tonumber(xml.attrib.ascendClassId), hashList) - if xml.attrib.allocationOrder then - for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do - table.insert(self.allocationOrder, tonumber(nodeId)) - end - self:ReIndexAllocationOrder("allocationOrder") - end - if xml.attrib.ascendancyAllocationOrder then - for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do - table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) - end - self:ReIndexAllocationOrder("ascendancyAllocationOrder") - end + -- if xml.attrib.allocationOrder then + -- for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do + -- table.insert(self.allocationOrder, tonumber(nodeId)) + -- end + -- self:ReIndexAllocationOrder("allocationOrder") + -- end + -- if xml.attrib.ascendancyAllocationOrder then + -- for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do + -- table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) + -- end + -- self:ReIndexAllocationOrder("ascendancyAllocationOrder") + -- end elseif url then self:DecodeURL(url) end @@ -394,7 +394,6 @@ end -- Clear the allocated status of all non-class-start nodes function PassiveSpecClass:ResetNodes() - ConPrintf("reset") for id, node in pairs(self.nodes) do if node.type ~= "ClassStart" and node.type ~= "AscendClassStart" then node.alloc = false @@ -466,7 +465,6 @@ end -- An alternate path to the node may be provided, otherwise the default path will be used -- The path must always contain the given node, as will be the case for the default path function PassiveSpecClass:AllocNode(node, altPath) - ConPrintTable(self.allocationOrder) if not node.path then -- Node cannot be connected to the tree as there is no possible path return @@ -955,7 +953,11 @@ end function PassiveSpecClass:BuildClusterJewelGraphs() -- Remove old subgraphs for id, subGraph in pairs(self.subGraphs) do + if type(subGraph.nodes) == "tree" then + self:SortNodesForRemovingFromAllocationOrder(subGraph.nodes) + end for _, node in ipairs(subGraph.nodes) do + self:RemoveFromAllocationOrder(node) if node.id then self.nodes[node.id] = nil if self.allocNodes[node.id] then @@ -965,6 +967,7 @@ function PassiveSpecClass:BuildClusterJewelGraphs() end end end + self:ReIndexAllocationOrder("allocationOrder") local index = isValueInArray(subGraph.parentSocket.linked, subGraph.entranceNode) assert(index, "Entrance for subGraph not linked to parent socket???") t_remove(subGraph.parentSocket.linked, index) @@ -995,7 +998,11 @@ function PassiveSpecClass:BuildClusterJewelGraphs() end -- (Re-)allocate subgraph nodes - for _, nodeId in ipairs(self.allocSubgraphNodes) do + local sortedAllocSubgraphNodes = {} + for i=#self.allocSubgraphNodes, 1, -1 do + sortedAllocSubgraphNodes[#sortedAllocSubgraphNodes+1] = self.allocSubgraphNodes[i] + end + for _, nodeId in ipairs(sortedAllocSubgraphNodes) do local node = self.nodes[nodeId] if node then node.alloc = true @@ -1003,6 +1010,7 @@ function PassiveSpecClass:BuildClusterJewelGraphs() self.allocNodes[nodeId] = node t_insert(self.allocExtendedNodes, nodeId) end + self:SetAllocationOrder(node) end end wipeTable(self.allocSubgraphNodes) From 9a2f7cb23ca9056c6bc3763365179e1dac38009b Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 18 Oct 2021 10:44:22 -0700 Subject: [PATCH 4/6] Added support for undo/redo --- src/Classes/PassiveSpec.lua | 54 +++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index c81d747db2..f66ac764ed 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -120,19 +120,19 @@ function PassiveSpecClass:Load(xml, dbFileName) masteryEffects[tonumber(mastery)] = tonumber(effect) end end - self:ImportFromNodeList(tonumber(xml.attrib.classId), tonumber(xml.attrib.ascendClassId), hashList) - -- if xml.attrib.allocationOrder then - -- for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do - -- table.insert(self.allocationOrder, tonumber(nodeId)) - -- end - -- self:ReIndexAllocationOrder("allocationOrder") - -- end - -- if xml.attrib.ascendancyAllocationOrder then - -- for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do - -- table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) - -- end - -- self:ReIndexAllocationOrder("ascendancyAllocationOrder") - -- end + self:ImportFromNodeList(tonumber(xml.attrib.classId), tonumber(xml.attrib.ascendClassId), hashList, masteryEffects) + if xml.attrib.allocationOrder then + for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do + table.insert(self.allocationOrder, tonumber(nodeId)) + end + self:ReIndexNodeAllocationOrder("allocationOrder") + end + if xml.attrib.ascendancyAllocationOrder then + for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do + table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) + end + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") + end elseif url then self:DecodeURL(url) end @@ -354,7 +354,7 @@ function PassiveSpecClass:SelectAscendClass(ascendClassId) self:RemoveFromAllocationOrder(node) end end - self:ReIndexAllocationOrder("ascendancyAllocationOrder") + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") if ascendClass.startNodeId then -- Allocate the new ascendancy class's start node @@ -427,7 +427,7 @@ function PassiveSpecClass:RemoveFromAllocationOrder(node) end end -function PassiveSpecClass:ReIndexAllocationOrder(allocationOrder) +function PassiveSpecClass:ReIndexNodeAllocationOrder(allocationOrder) for i, nodeId in ipairs(self[allocationOrder]) do self.nodes[nodeId][allocationOrder] = i end @@ -492,9 +492,9 @@ function PassiveSpecClass:AllocNode(node, altPath) if optNode.isMultipleChoiceOption and optNode.alloc and optNode ~= node then self.DeallocSingleNode(optNode) if optNode.ascendancyName then - self:ReIndexAllocationOrder("ascendancyAllocationOrder") + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") else - self:ReIndexAllocationOrder("allocationOrder") + self:ReIndexNodeAllocationOrder("allocationOrder") end end end @@ -524,9 +524,9 @@ function PassiveSpecClass:DeallocNode(node) self:DeallocSingleNode(depNode) end if node.ascendancyName then - self:ReIndexAllocationOrder("ascendancyAllocationOrder") + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") else - self:ReIndexAllocationOrder("allocationOrder") + self:ReIndexNodeAllocationOrder("allocationOrder") end -- Rebuild all paths and dependencies for all allocated nodes @@ -897,8 +897,8 @@ function PassiveSpecClass:BuildAllDependsAndPaths() self:DeallocSingleNode(depNode) end end - self:ReIndexAllocationOrder("allocationOrder") - self:ReIndexAllocationOrder("ascendancyAllocationOrder") + self:ReIndexNodeAllocationOrder("allocationOrder") + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") end end @@ -967,7 +967,7 @@ function PassiveSpecClass:BuildClusterJewelGraphs() end end end - self:ReIndexAllocationOrder("allocationOrder") + self:ReIndexNodeAllocationOrder("allocationOrder") local index = isValueInArray(subGraph.parentSocket.linked, subGraph.entranceNode) assert(index, "Entrance for subGraph not linked to parent socket???") t_remove(subGraph.parentSocket.linked, index) @@ -1428,16 +1428,24 @@ function PassiveSpecClass:CreateUndoState() for mastery, effect in pairs(self.masterySelections) do selections[mastery] = effect end + local allocationOrder = copyTable(self.allocationOrder) + local ascendancyAllocationOrder = copyTable(self.ascendancyAllocationOrder) return { classId = self.curClassId, ascendClassId = self.curAscendClassId, hashList = allocNodeIdList, - masteryEffects = selections + masteryEffects = selections, + allocationOrder = allocationOrder, + ascendancyAllocationOrder = ascendancyAllocationOrder } end function PassiveSpecClass:RestoreUndoState(state) self:ImportFromNodeList(state.classId, state.ascendClassId, state.hashList, state.masteryEffects) + self.allocationOrder = state.allocationOrder + self.ascendancyAllocationOrder = state.ascendancyAllocationOrder + self:ReIndexNodeAllocationOrder("allocationOrder") + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") self:SetWindowTitleWithBuildClass() end From 7152b1d8c6b6c4de2116208041f0903775676a6d Mon Sep 17 00:00:00 2001 From: David Allen Date: Thu, 21 Oct 2021 15:20:19 -0700 Subject: [PATCH 5/6] Fixes after rebase for ascendencies and cluster jewels --- src/Classes/PassiveSpec.lua | 40 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index f66ac764ed..3b7224a26f 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -349,9 +349,7 @@ function PassiveSpecClass:SelectAscendClass(ascendClassId) -- Deallocate any allocated ascendancy nodes that don't belong to the new ascendancy class for id, node in pairs(self.allocNodes) do if node.ascendancyName and node.ascendancyName ~= ascendClass.name then - node.alloc = false - self.allocNodes[id] = nil - self:RemoveFromAllocationOrder(node) + self:DeallocNode(node) end end self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") @@ -428,12 +426,18 @@ function PassiveSpecClass:RemoveFromAllocationOrder(node) end function PassiveSpecClass:ReIndexNodeAllocationOrder(allocationOrder) - for i, nodeId in ipairs(self[allocationOrder]) do - self.nodes[nodeId][allocationOrder] = i + for i=#self[allocationOrder],1,-1 do + nodeId = self[allocationOrder][i] + if self.nodes[nodeId] then + self.nodes[nodeId][allocationOrder] = i + else + t_remove(self[allocationOrder], i) + end end end -function PassiveSpecClass:SortNodesForRemovingFromAllocationOrder(node, depNodes) +function PassiveSpecClass:SortNodesForRemovingFromAllocationOrder(node) + depNodes = node.depends if node.ascendancyName then table.sort(depNodes, function(a, b) if a.ascendancyAllocationOrder == nil and b.ascendancyAllocationOrder == nil then @@ -518,7 +522,7 @@ end -- Deallocate the given node, and all nodes which depend on it (i.e. which are only connected to the tree through this node) function PassiveSpecClass:DeallocNode(node) - self:SortNodesForRemovingFromAllocationOrder(node, node.depends) + self:SortNodesForRemovingFromAllocationOrder(node) for _, depNode in ipairs(node.depends) do self:DeallocSingleNode(depNode) @@ -870,7 +874,7 @@ function PassiveSpecClass:BuildAllDependsAndPaths() if not anyStartFound then -- No start nodes were found through ANY nodes -- Therefore this node and all nodes depending on it are orphans and should be pruned - self:SortNodesForRemovingFromAllocationOrder(node, node.depends) + self:SortNodesForRemovingFromAllocationOrder(node) for _, depNode in ipairs(node.depends) do local prune = true for nodeId, itemId in pairs(self.jewels) do @@ -894,7 +898,7 @@ function PassiveSpecClass:BuildAllDependsAndPaths() end end if prune then - self:DeallocSingleNode(depNode) + self:DeallocNode(depNode) end end self:ReIndexNodeAllocationOrder("allocationOrder") @@ -953,12 +957,22 @@ end function PassiveSpecClass:BuildClusterJewelGraphs() -- Remove old subgraphs for id, subGraph in pairs(self.subGraphs) do - if type(subGraph.nodes) == "tree" then - self:SortNodesForRemovingFromAllocationOrder(subGraph.nodes) - end + table.sort(subGraph.nodes, function(a, b) + if a.allocationOrder == nil and b.allocationOrder == nil then + return false + elseif a.allocationOrder == nil then + return true + elseif b.allocationOrder == nil then + return false + else + return a.allocationOrder > b.allocationOrder + end + end) for _, node in ipairs(subGraph.nodes) do - self:RemoveFromAllocationOrder(node) if node.id then + if node.alloc then + self:RemoveFromAllocationOrder(node) + end self.nodes[node.id] = nil if self.allocNodes[node.id] then -- Reserve the allocation in case the node is regenerated From 06ee2cecde115b634a053534826cdf1f1c5a8bb7 Mon Sep 17 00:00:00 2001 From: David Allen Date: Thu, 21 Oct 2021 17:18:25 -0700 Subject: [PATCH 6/6] Made clusters swap in place for allocation order, rather than swapping them adding the nodes to the end of allocation order --- src/Classes/PassiveSpec.lua | 41 ++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index 3b7224a26f..028109e9f0 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -63,6 +63,12 @@ local PassiveSpecClass = newClass("PassiveSpec", "UndoHandler", function(self, b self.allocationOrder = { } self.ascendancyAllocationOrder = { } + -- Keys are mastery node IDs, values are mastery effect IDs + self.masterySelections = { } + + --for postload handler + self.initialLoad = true + self:SelectClass(0) end) @@ -125,13 +131,11 @@ function PassiveSpecClass:Load(xml, dbFileName) for nodeId in string.gmatch(xml.attrib.allocationOrder, ("%d+")) do table.insert(self.allocationOrder, tonumber(nodeId)) end - self:ReIndexNodeAllocationOrder("allocationOrder") end if xml.attrib.ascendancyAllocationOrder then for nodeId in string.gmatch(xml.attrib.ascendancyAllocationOrder, ("%d+")) do table.insert(self.ascendancyAllocationOrder, tonumber(nodeId)) end - self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") end elseif url then self:DecodeURL(url) @@ -245,6 +249,9 @@ end function PassiveSpecClass:PostLoad() self:BuildClusterJewelGraphs() + self:ReIndexNodeAllocationOrder("allocationOrder") + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") + self.initialLoad = false end -- Import passive spec from the provided class IDs and node hash list @@ -901,8 +908,11 @@ function PassiveSpecClass:BuildAllDependsAndPaths() self:DeallocNode(depNode) end end - self:ReIndexNodeAllocationOrder("allocationOrder") - self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") + if node.ascendancyName then + self:ReIndexNodeAllocationOrder("ascendancyAllocationOrder") + else + self:ReIndexNodeAllocationOrder("allocationOrder") + end end end @@ -956,6 +966,7 @@ end function PassiveSpecClass:BuildClusterJewelGraphs() -- Remove old subgraphs + local reserverdAllocationOrders = {} for id, subGraph in pairs(self.subGraphs) do table.sort(subGraph.nodes, function(a, b) if a.allocationOrder == nil and b.allocationOrder == nil then @@ -971,7 +982,10 @@ function PassiveSpecClass:BuildClusterJewelGraphs() for _, node in ipairs(subGraph.nodes) do if node.id then if node.alloc then - self:RemoveFromAllocationOrder(node) + if node.allocationOrder ~= nil then + reserverdAllocationOrders[node.id] = node.allocationOrder + node.allocationOrder = nil + end end self.nodes[node.id] = nil if self.allocNodes[node.id] then @@ -981,7 +995,6 @@ function PassiveSpecClass:BuildClusterJewelGraphs() end end end - self:ReIndexNodeAllocationOrder("allocationOrder") local index = isValueInArray(subGraph.parentSocket.linked, subGraph.entranceNode) assert(index, "Entrance for subGraph not linked to parent socket???") t_remove(subGraph.parentSocket.linked, index) @@ -1011,6 +1024,7 @@ function PassiveSpecClass:BuildClusterJewelGraphs() end end + ConPrintTable(reserverdAllocationOrders) -- (Re-)allocate subgraph nodes local sortedAllocSubgraphNodes = {} for i=#self.allocSubgraphNodes, 1, -1 do @@ -1024,9 +1038,22 @@ function PassiveSpecClass:BuildClusterJewelGraphs() self.allocNodes[nodeId] = node t_insert(self.allocExtendedNodes, nodeId) end - self:SetAllocationOrder(node) + if not self.initialLoad then + if reserverdAllocationOrders[nodeId] then + self.allocationOrder[reserverdAllocationOrders[nodeId]] = nodeId + node.allocationOrder = reserverdAllocationOrders[nodeId] + reserverdAllocationOrders[nodeId] = nil + else + self:SetAllocationOrder(node) + end + end end end + for nodeId, unallocated in pairs(reserverdAllocationOrders) do + self:RemoveFromAllocationOrder(self.nodes[nodeId]) + end + ConPrintTable(self.allocationOrder) + self:ReIndexNodeAllocationOrder("allocationOrder") wipeTable(self.allocSubgraphNodes) -- Rebuild paths to account for new/removed nodes