Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reversible craft tree nodes #562

Merged
merged 2 commits into from
Nov 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 59 additions & 37 deletions Nautilus/Handlers/CraftTreeHandler.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
namespace Nautilus.Handlers;

using System;
using System.Collections.Generic;
using System.Linq;
using Nautilus.Crafting;
using Nautilus.Patchers;
using Nautilus.Utility;

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

nodes.Add(new CraftingNode(stepsToTab, craftTree, craftingItem));
CraftTreePatcher.CraftingNodes[craftTree] = nodes;

// If this node had previously been slated for removal, undo that instruction.
if (CraftTreePatcher.NodesToRemove.TryGetValue(craftTree, out List<Node> queuedNodes))
{
var fullPath = stepsToTab.Append(craftingItem.AsString(false));
int removedNodes = queuedNodes.RemoveAll(node => node.Path.SequenceEqual(fullPath));
if (removedNodes > 0)
{
InternalLogger.Debug($"Removal of CraftNode at {string.Join("/", fullPath)} overwritten by new custom CraftNode.");
}
}
}

/// <summary>
/// Adds a new crafting node to the root of the specified crafting tree
/// </summary>
/// <param name="craftTree">The target craft tree to edit.</param>
/// <param name="craftingItem">The item to craft.</param>

public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingItem)
{
if (!CraftTreePatcher.CraftingNodes.TryGetValue(craftTree, out var nodes))
{
nodes = new List<CraftingNode>();
}

nodes.Add(new CraftingNode(new string[0], craftTree, craftingItem));
CraftTreePatcher.CraftingNodes[craftTree] = nodes;
AddCraftingNode(craftTree, craftingItem, Array.Empty<string>());
}

#if SUBNAUTICA
Expand All @@ -58,13 +65,7 @@ public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingIt
/// <param name="sprite">The sprite of the tab.</param>
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, Atlas.Sprite sprite)
{
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
{
craftTreeTabNodes = new List<TabNode>();
}

craftTreeTabNodes.Add(new TabNode(new string[0], craftTree, sprite, name, displayName));
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
AddTabNode(craftTree, name, displayName, sprite, Array.Empty<string>());
}

/// <summary>
Expand All @@ -74,16 +75,9 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
/// <param name="name">The ID of the tab node. Must be unique!</param>
/// <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>
/// <param name="sprite">The sprite of the tab.</param>

public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite)
{
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
{
craftTreeTabNodes = new List<TabNode>();
}

craftTreeTabNodes.Add(new TabNode(new string[0], craftTree, new Atlas.Sprite(sprite), name, displayName));
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
AddTabNode(craftTree, name, displayName, new Atlas.Sprite(sprite), Array.Empty<string>());
}

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

craftTreeTabNodes.Add(new TabNode(stepsToTab, craftTree, sprite, name, displayName));
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;

// If this node had previously been slated for removal, undo that instruction.
if (CraftTreePatcher.NodesToRemove.TryGetValue(craftTree, out List<Node> queuedNodes))
{
var fullPath = stepsToTab.Append(name);
int removedNodes = queuedNodes.RemoveAll(node => node.Path.SequenceEqual(fullPath));
if (removedNodes > 0)
{
InternalLogger.Debug($"Removal of TabNode at {string.Join("/", fullPath)} overwritten by new custom TabNode.");
}
}
}

/// <summary>
Expand All @@ -125,13 +130,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
/// </param>
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite, params string[] stepsToTab)
{
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
{
craftTreeTabNodes = new List<TabNode>();
}

craftTreeTabNodes.Add(new TabNode(stepsToTab, craftTree, new Atlas.Sprite(sprite), name, displayName));
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
AddTabNode(craftTree, name, displayName, new Atlas.Sprite(sprite), stepsToTab);
}

#elif BELOWZERO
Expand All @@ -144,13 +143,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp
/// <param name="sprite">The sprite of the tab.</param>
public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite)
{
if (!CraftTreePatcher.TabNodes.TryGetValue(craftTree, out var craftTreeTabNodes))
{
craftTreeTabNodes = new List<TabNode>();
}

craftTreeTabNodes.Add(new TabNode(new string[0], craftTree, sprite, name, displayName));
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;
AddTabNode(craftTree, name, displayName, sprite, Array.Empty<string>());
}

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

craftTreeTabNodes.Add(new TabNode(stepsToTab, craftTree, sprite, name, displayName));
CraftTreePatcher.TabNodes[craftTree] = craftTreeTabNodes;

// If this node had previously been slated for removal, undo that instruction.
if (CraftTreePatcher.NodesToRemove.TryGetValue(craftTree, out List<Node> queuedNodes))
{
var fullPath = stepsToTab.Append(name);
int removedNodes = queuedNodes.RemoveAll(node => node.Path.SequenceEqual(fullPath));
if (removedNodes > 0)
{
InternalLogger.Debug($"Removal of TabNode at {string.Join("/", fullPath)} overwritten by new custom TabNode.");
}
}
}

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

nodesToRemove.Add(new Node(stepsToNode, craftTree));
CraftTreePatcher.NodesToRemove[craftTree] = nodesToRemove;

// If this is a previously registered custom node, undo that instruction.
// This avoids accumulation of instructions that cancel each other out.
int removedNodes = 0;
if (CraftTreePatcher.CraftingNodes.TryGetValue(craftTree, out List<CraftingNode> craftingNodes))
{
removedNodes += craftingNodes.RemoveAll(node => node.Path.Append(node.TechType.ToString()).SequenceEqual(stepsToNode));
}

if (CraftTreePatcher.TabNodes.TryGetValue(craftTree, out List<TabNode> tabNodes))
{
removedNodes += tabNodes.RemoveAll(node => node.Path.Append(node.Id).SequenceEqual(stepsToNode));
}

if (removedNodes > 0)
{
InternalLogger.Debug($"Removed another mod's custom node at {string.Join("/", stepsToNode)} from future craft trees.");
}
}

/// <summary>
Expand Down
Loading