Skip to content

Commit d497d4f

Browse files
committed
Add options to only copy used items and to reuse existing items
1 parent bf21642 commit d497d4f

File tree

4 files changed

+122
-35
lines changed

4 files changed

+122
-35
lines changed

Form1.Designer.cs

Lines changed: 44 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Form1.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using System.Windows.Forms;
2-
31
namespace PathOfBuildingMerge
42
{
53
public partial class Form1 : Form
@@ -98,9 +96,12 @@ private void buttonMerge_Click(object sender, EventArgs e)
9896
if (string.IsNullOrWhiteSpace(outputPob))
9997
outputPob = mainPob;
10098

99+
bool onlyAddUsedItems = checkBoxOnlyAddUsedItems.Checked;
100+
bool reuseExistingItems = checkBoxReuseExisitngItems.Checked;
101+
101102
try
102103
{
103-
PobMergeUtils.Merge(mainPob, pobToMerge, newLoadoutName, outputPob);
104+
PobMergeUtils.Merge(mainPob, pobToMerge, newLoadoutName, outputPob, onlyAddUsedItems: onlyAddUsedItems, reuseExistingItems: reuseExistingItems);
104105
}
105106
catch (Exception ex)
106107
{

Form1.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
121+
<value>291, 17</value>
122+
</metadata>
123+
<data name="label3.ToolTip" xml:space="preserve">
124+
<value>The name of the new loadout to add to the main PoB file. If any sets (tree, item, skill, config) of the same name already exist in the PoB, they will be removed. If this field is left blank the name of the PoB merge file above will be used as the new loadout name.</value>
125+
</data>
120126
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
121127
<value>17, 17</value>
122128
</metadata>

PobMergeUtils.cs

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-

2-
using System.Linq;
3-
using System.Reflection.Metadata;
4-
using System.Reflection.Metadata.Ecma335;
5-
using System.Text;
6-
using System.Windows.Forms;
7-
using System.Xml.Linq;
8-
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox;
1+
using System.Xml.Linq;
92

103
namespace PathOfBuildingMerge
114
{
@@ -24,26 +17,35 @@ internal struct SetType
2417
static SetType Tree = new() { Node = "Tree", Element = "Spec", Active = "activeSpec" };
2518

2619

27-
internal static void Merge(string mainPob, string pobToAdd, string newLoadoutName, string pobResult)
20+
internal static void Merge(string mainPob, string pobToAdd, string newLoadoutName, string pobResult, bool onlyAddUsedItems = true, bool reuseExistingItems = true)
2821
{
2922
var baseFileName = Path.GetFileName(mainPob);
3023
var baseDoc = XDocument.Load(mainPob);
3124

3225
var baseTreeNode = GetRootNode(baseDoc, baseFileName, Tree.Node);
3326
var baseSkillsNode = GetRootNode(baseDoc, baseFileName, Skills.Node);
34-
var baseConfigNode = GetRootNode(baseDoc, baseFileName, Config.Node);
3527
var baseItemsNode = GetRootNode(baseDoc, baseFileName, Items.Node);
28+
var baseConfigNode = GetRootNode(baseDoc, baseFileName, Config.Node);
3629

3730
RemoveTreeSpec(baseTreeNode, newLoadoutName);
3831
RemoveSkillSet(baseSkillsNode, newLoadoutName);
39-
RemoveConfigSet(baseConfigNode, newLoadoutName);
4032
RemoveItemSet(baseItemsNode, newLoadoutName);
33+
RemoveConfigSet(baseConfigNode, newLoadoutName);
4134

4235
var addFileName = Path.GetFileName(pobToAdd);
4336
var docToAdd = XDocument.Load(pobToAdd);
4437
var addItemsNode = GetRootNode(docToAdd, addFileName, Items.Node);
4538
var itemsToAdd = addItemsNode.Elements("Item");
4639

40+
List<int> usedItemIds = [];
41+
if (onlyAddUsedItems)
42+
{
43+
CollectUsedItemIds(usedItemIds, GetActiveTreeSpec(docToAdd, addFileName));
44+
CollectUsedItemIds(usedItemIds, GetActiveSkillSet(docToAdd, addFileName));
45+
CollectUsedItemIds(usedItemIds, GetActiveItemSet(docToAdd, addFileName));
46+
CollectUsedItemIds(usedItemIds, GetActiveConfigSet(docToAdd, addFileName));
47+
}
48+
4749
var addedItemsIdDictionary = new Dictionary<int, int>();
4850

4951
var normalizedBaseItems = baseItemsNode.Elements("Item").Select(x => XmlUtils.NormalizeElement(x, false));
@@ -63,16 +65,22 @@ internal static void Merge(string mainPob, string pobToAdd, string newLoadoutNam
6365
var id = (int?)item.Attribute("id") ?? 0;
6466
if (id <= 0) continue;
6567

66-
// check if item is a duplicate and if so continue
67-
//
68+
if (onlyAddUsedItems && !usedItemIds.Contains(id))
69+
continue;
70+
6871
var normalizedItem = XmlUtils.NormalizeElement(item, false);
6972
normalizedItem.SetAttributeValue("id", null);
7073

71-
var foundItem = normalizedItemsDictionary.FirstOrDefault(x => (XNode.DeepEquals(x.Value, normalizedItem)));
72-
if (foundItem.Value != null)
74+
// check if item is a duplicate and if so continue
75+
//
76+
if (reuseExistingItems)
7377
{
74-
addedItemsIdDictionary[id] = foundItem.Key;
75-
continue;
78+
var foundItem = normalizedItemsDictionary.FirstOrDefault(x => (XNode.DeepEquals(x.Value, normalizedItem)));
79+
if (foundItem.Value != null)
80+
{
81+
addedItemsIdDictionary[id] = foundItem.Key;
82+
continue;
83+
}
7684
}
7785

7886
// renumber ids of added items so they don't clash with existing items.
@@ -91,14 +99,25 @@ internal static void Merge(string mainPob, string pobToAdd, string newLoadoutNam
9199
baseItemsNode.Add(item);
92100
}
93101

94-
AddConfigSet(docToAdd, addFileName, baseConfigNode, newLoadoutName, addedItemsIdDictionary);
102+
AddTreeSpec(docToAdd, addFileName, baseTreeNode, newLoadoutName, addedItemsIdDictionary);
95103
AddSkillSet(docToAdd, addFileName, baseSkillsNode, newLoadoutName, addedItemsIdDictionary);
96104
AddItemSet(docToAdd, addFileName, baseItemsNode, newLoadoutName, addedItemsIdDictionary);
97-
AddTreeSpec(docToAdd, addFileName, baseTreeNode, newLoadoutName, addedItemsIdDictionary);
105+
AddConfigSet(docToAdd, addFileName, baseConfigNode, newLoadoutName, addedItemsIdDictionary);
98106

99107
XmlUtils.SaveXDocumentWithoutBom(baseDoc, pobResult);
100108
}
101109

110+
private static void CollectUsedItemIds(List<int> usedItemIds, XElement node)
111+
{
112+
foreach (var child in node.Descendants())
113+
{
114+
if (!child.HasAttributes) continue;
115+
var itemId = (int?)child.Attribute("itemId") ?? 0;
116+
if (itemId > 0)
117+
usedItemIds.Add(itemId);
118+
}
119+
}
120+
102121
private static void UpdateItemIds(XElement node, Dictionary<int, int> idDictionary)
103122
{
104123
foreach (var child in node.Descendants())
@@ -111,29 +130,50 @@ private static void UpdateItemIds(XElement node, Dictionary<int, int> idDictiona
111130
}
112131

113132
private static void AddTreeSpec(XDocument doc, string fileName, XElement destinationNode, string newLoadoutName, Dictionary<int, int> idDictionary)
133+
{
134+
XElement found = GetActiveTreeSpec(doc, fileName);
135+
found.SetAttributeValue("title", newLoadoutName);
136+
UpdateItemIds(found, idDictionary);
137+
destinationNode.Add(found);
138+
}
139+
140+
private static XElement GetActiveTreeSpec(XDocument doc, string fileName)
114141
{
115142
var treeNode = GetRootNode(doc, fileName, Tree.Node);
116-
var activeSpec = (int?) treeNode.Attribute(Tree.Active) ?? 1;
143+
var activeSpec = (int?)treeNode.Attribute(Tree.Active) ?? 1;
117144

118145
var specs = treeNode.Elements(Tree.Element);
119146

120147
if (activeSpec > 1 && specs.Count() >= activeSpec) specs = specs.Skip(activeSpec - 1);
121-
var found = specs.FirstOrDefault() ?? throw new Exception($"No tree spec found in '{fileName}' to add") ;
122-
found.SetAttributeValue("title", newLoadoutName);
123-
UpdateItemIds(found, idDictionary);
124-
destinationNode.Add(found);
148+
var found = specs.FirstOrDefault() ?? throw new Exception($"No tree spec found in '{fileName}' to add");
149+
return found;
125150
}
126151

127-
private static void AddItemSet(XDocument doc, string fileName, XElement destinationNode, string newLoadoutName, Dictionary<int, int> idDictionary)
152+
private static XElement GetActiveSkillSet(XDocument doc, string fileName)
128153
{
129-
AddNodeWithUniqueId(doc, fileName, destinationNode, newLoadoutName, idDictionary, Items);
154+
return GetChildByActiveIndex(doc, fileName, Skills);
155+
}
156+
157+
private static XElement GetActiveItemSet(XDocument doc, string fileName)
158+
{
159+
return GetChildByActiveIndex(doc, fileName, Items);
160+
}
161+
162+
private static XElement GetActiveConfigSet(XDocument doc, string fileName)
163+
{
164+
return GetChildByActiveIndex(doc, fileName, Config);
130165
}
131166

132167
private static void AddSkillSet(XDocument doc, string fileName, XElement destinationNode, string newLoadoutName, Dictionary<int, int> idDictionary)
133168
{
134169
AddNodeWithUniqueId(doc, fileName, destinationNode, newLoadoutName, idDictionary, Skills);
135170
}
136171

172+
private static void AddItemSet(XDocument doc, string fileName, XElement destinationNode, string newLoadoutName, Dictionary<int, int> idDictionary)
173+
{
174+
AddNodeWithUniqueId(doc, fileName, destinationNode, newLoadoutName, idDictionary, Items);
175+
}
176+
137177
private static void AddConfigSet(XDocument doc, string fileName, XElement destinationNode, string newLoadoutName, Dictionary<int, int> idDictionary)
138178
{
139179
AddNodeWithUniqueId(doc, fileName, destinationNode, newLoadoutName, idDictionary, Config);
@@ -142,10 +182,10 @@ private static void AddConfigSet(XDocument doc, string fileName, XElement destin
142182
private static void AddNodeWithUniqueId(XDocument doc, string fileName, XElement destinationNode, string newLoadoutName, Dictionary<int, int> idDictionary, SetType setType)
143183
{
144184
var result = GetChildByActiveIndex(doc, fileName, setType);
185+
UpdateItemIds(result, idDictionary);
186+
result.SetAttributeValue("title", newLoadoutName);
145187
var newId = GetFirstAvailableId(destinationNode, setType.Element);
146188
result.SetAttributeValue("id", newId);
147-
result.SetAttributeValue("title", newLoadoutName);
148-
UpdateItemIds(result, idDictionary);
149189
destinationNode.Add(result);
150190
}
151191

0 commit comments

Comments
 (0)