Skip to content

Commit dd547c7

Browse files
authored
fix: Reversible craft tree nodes (#562)
* chore: Consolidate CraftTreeHandler overloads. * fix: Opposing CraftTree changes properly cancel each other out.
1 parent 68109eb commit dd547c7

File tree

1 file changed

+59
-37
lines changed

1 file changed

+59
-37
lines changed

Nautilus/Handlers/CraftTreeHandler.cs

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
namespace Nautilus.Handlers;
22

3+
using System;
34
using System.Collections.Generic;
5+
using System.Linq;
46
using Nautilus.Crafting;
57
using Nautilus.Patchers;
8+
using Nautilus.Utility;
69

710
/// <summary>
811
/// A handler class for creating and modifying crafting trees.
@@ -29,23 +32,27 @@ public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingIt
2932

3033
nodes.Add(new CraftingNode(stepsToTab, craftTree, craftingItem));
3134
CraftTreePatcher.CraftingNodes[craftTree] = nodes;
35+
36+
// If this node had previously been slated for removal, undo that instruction.
37+
if (CraftTreePatcher.NodesToRemove.TryGetValue(craftTree, out List<Node> queuedNodes))
38+
{
39+
var fullPath = stepsToTab.Append(craftingItem.AsString(false));
40+
int removedNodes = queuedNodes.RemoveAll(node => node.Path.SequenceEqual(fullPath));
41+
if (removedNodes > 0)
42+
{
43+
InternalLogger.Debug($"Removal of CraftNode at {string.Join("/", fullPath)} overwritten by new custom CraftNode.");
44+
}
45+
}
3246
}
3347

3448
/// <summary>
3549
/// Adds a new crafting node to the root of the specified crafting tree
3650
/// </summary>
3751
/// <param name="craftTree">The target craft tree to edit.</param>
3852
/// <param name="craftingItem">The item to craft.</param>
39-
4053
public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingItem)
4154
{
42-
if (!CraftTreePatcher.CraftingNodes.TryGetValue(craftTree, out var nodes))
43-
{
44-
nodes = new List<CraftingNode>();
45-
}
46-
47-
nodes.Add(new CraftingNode(new string[0], craftTree, craftingItem));
48-
CraftTreePatcher.CraftingNodes[craftTree] = nodes;
55+
AddCraftingNode(craftTree, craftingItem, Array.Empty<string>());
4956
}
5057

5158
#if SUBNAUTICA
@@ -58,13 +65,7 @@ public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingIt
5865
/// <param name="sprite">The sprite of the tab.</param>
5966
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, Atlas.Sprite sprite)
6067
{
61-
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
62-
{
63-
craftTreeTabNodes = new List<TabNode>();
64-
}
65-
66-
craftTreeTabNodes.Add(new TabNode(new string[0], craftTree, sprite, name, displayName));
67-
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
68+
AddTabNode(craftTree, name, displayName, sprite, Array.Empty<string>());
6869
}
6970

7071
/// <summary>
@@ -74,16 +75,9 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
7475
/// <param name="name">The ID of the tab node. Must be unique!</param>
7576
/// <param name="displayName">The display name of the tab, which will show up when you hover your mouse on the tab. If null or empty, this will use the language line "{craftTreeName}_{tabName}" instead.</param>
7677
/// <param name="sprite">The sprite of the tab.</param>
77-
7878
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite)
7979
{
80-
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
81-
{
82-
craftTreeTabNodes = new List<TabNode>();
83-
}
84-
85-
craftTreeTabNodes.Add(new TabNode(new string[0], craftTree, new Atlas.Sprite(sprite), name, displayName));
86-
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
80+
AddTabNode(craftTree, name, displayName, new Atlas.Sprite(sprite), Array.Empty<string>());
8781
}
8882

8983
/// <summary>
@@ -108,6 +102,17 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
108102

109103
craftTreeTabNodes.Add(new TabNode(stepsToTab, craftTree, sprite, name, displayName));
110104
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
105+
106+
// If this node had previously been slated for removal, undo that instruction.
107+
if (CraftTreePatcher.NodesToRemove.TryGetValue(craftTree, out List<Node> queuedNodes))
108+
{
109+
var fullPath = stepsToTab.Append(name);
110+
int removedNodes = queuedNodes.RemoveAll(node => node.Path.SequenceEqual(fullPath));
111+
if (removedNodes > 0)
112+
{
113+
InternalLogger.Debug($"Removal of TabNode at {string.Join("/", fullPath)} overwritten by new custom TabNode.");
114+
}
115+
}
111116
}
112117

113118
/// <summary>
@@ -125,13 +130,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
125130
/// </param>
126131
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite, params string[] stepsToTab)
127132
{
128-
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
129-
{
130-
craftTreeTabNodes = new List<TabNode>();
131-
}
132-
133-
craftTreeTabNodes.Add(new TabNode(stepsToTab, craftTree, new Atlas.Sprite(sprite), name, displayName));
134-
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
133+
AddTabNode(craftTree, name, displayName, new Atlas.Sprite(sprite), stepsToTab);
135134
}
136135

137136
#elif BELOWZERO
@@ -144,13 +143,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
144143
/// <param name="sprite">The sprite of the tab.</param>
145144
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite)
146145
{
147-
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
148-
{
149-
craftTreeTabNodes = new List<TabNode>();
150-
}
151-
152-
craftTreeTabNodes.Add(new TabNode(new string[0], craftTree, sprite, name, displayName));
153-
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
146+
AddTabNode(craftTree, name, displayName, sprite, Array.Empty<string>());
154147
}
155148

156149
/// <summary>
@@ -175,6 +168,17 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
175168

176169
craftTreeTabNodes.Add(new TabNode(stepsToTab, craftTree, sprite, name, displayName));
177170
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
171+
172+
// If this node had previously been slated for removal, undo that instruction.
173+
if (CraftTreePatcher.NodesToRemove.TryGetValue(craftTree, out List<Node> queuedNodes))
174+
{
175+
var fullPath = stepsToTab.Append(name);
176+
int removedNodes = queuedNodes.RemoveAll(node => node.Path.SequenceEqual(fullPath));
177+
if (removedNodes > 0)
178+
{
179+
InternalLogger.Debug($"Removal of TabNode at {string.Join("/", fullPath)} overwritten by new custom TabNode.");
180+
}
181+
}
178182
}
179183

180184
#endif
@@ -201,6 +205,24 @@ public static void RemoveNode(CraftTree.Type craftTree, params string[] stepsToN
201205

202206
nodesToRemove.Add(new Node(stepsToNode, craftTree));
203207
CraftTreePatcher.NodesToRemove[craftTree] = nodesToRemove;
208+
209+
// If this is a previously registered custom node, undo that instruction.
210+
// This avoids accumulation of instructions that cancel each other out.
211+
int removedNodes = 0;
212+
if (CraftTreePatcher.CraftingNodes.TryGetValue(craftTree, out List<CraftingNode> craftingNodes))
213+
{
214+
removedNodes += craftingNodes.RemoveAll(node => node.Path.Append(node.TechType.ToString()).SequenceEqual(stepsToNode));
215+
}
216+
217+
if (CraftTreePatcher.TabNodes.TryGetValue(craftTree, out List<TabNode> tabNodes))
218+
{
219+
removedNodes += tabNodes.RemoveAll(node => node.Path.Append(node.Id).SequenceEqual(stepsToNode));
220+
}
221+
222+
if (removedNodes > 0)
223+
{
224+
InternalLogger.Debug($"Removed another mod's custom node at {string.Join("/", stepsToNode)} from future craft trees.");
225+
}
204226
}
205227

206228
/// <summary>

0 commit comments

Comments
 (0)