From f28f96c27f2d7091b1e498b6ebec6e14118a1ebb Mon Sep 17 00:00:00 2001 From: Jon Kunkee Date: Sat, 27 Jun 2020 16:52:19 -0700 Subject: [PATCH 1/3] Split find and act operations to allow deletion This change splits CanProcess into a separate loop from Process so that Process can perform actions like deletion that cause NbtPathEnumerator to throw an exception. It also caches targetNode.Root before Process because Process can cause targetNode to be invalid. --- NBTUtil/ConsoleRunner.cs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/NBTUtil/ConsoleRunner.cs b/NBTUtil/ConsoleRunner.cs index 0f94ba1..c0f07fc 100644 --- a/NBTUtil/ConsoleRunner.cs +++ b/NBTUtil/ConsoleRunner.cs @@ -45,17 +45,30 @@ public bool Run (string[] args) int successCount = 0; int failCount = 0; - foreach (var targetNode in new NbtPathEnumerator(_options.Path)) { - if (!op.CanProcess(targetNode)) { - Console.WriteLine(targetNode.NodePath + ": ERROR (invalid command)"); + var nodesToProcess = new List(); + + foreach (var node in new NbtPathEnumerator(_options.Path)) + { + if (op.CanProcess(node)) + { + nodesToProcess.Add(node); + } + else + { + Console.WriteLine(node.NodePath + ": ERROR (invalid command)"); failCount++; } + } + + foreach (var targetNode in nodesToProcess) { + var root = targetNode.Root; + if (!op.Process(targetNode, _options)) { Console.WriteLine(targetNode.NodePath + ": ERROR (apply)"); failCount++; } - targetNode.Root.Save(); + root.Save(); Console.WriteLine(targetNode.NodePath + ": OK"); successCount++; From 4dfee8cfd6b2a4862763845ed293ac41a0438425 Mon Sep 17 00:00:00 2001 From: Jon Kunkee Date: Sat, 27 Jun 2020 20:21:06 -0700 Subject: [PATCH 2/3] Add --delete operation --- NBTUtil/ConsoleOptions.cs | 2 ++ NBTUtil/ConsoleRunner.cs | 1 + NBTUtil/NBTUtil.csproj | 1 + NBTUtil/Ops/DeleteOperation.cs | 25 +++++++++++++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 NBTUtil/Ops/DeleteOperation.cs diff --git a/NBTUtil/ConsoleOptions.cs b/NBTUtil/ConsoleOptions.cs index 1fdee5c..863650d 100644 --- a/NBTUtil/ConsoleOptions.cs +++ b/NBTUtil/ConsoleOptions.cs @@ -11,6 +11,7 @@ public enum ConsoleCommand Print, PrintTree, SetValue, + DeleteValue, SetList, Json, Help, @@ -64,6 +65,7 @@ public ConsoleOptions () break; } }}, + { "delete", "Delete the NBT tag if found", v => Command = ConsoleCommand.DeleteValue }, }; } diff --git a/NBTUtil/ConsoleRunner.cs b/NBTUtil/ConsoleRunner.cs index c0f07fc..df1a465 100644 --- a/NBTUtil/ConsoleRunner.cs +++ b/NBTUtil/ConsoleRunner.cs @@ -13,6 +13,7 @@ class ConsoleRunner { private static readonly Dictionary _commandTable = new Dictionary() { { ConsoleCommand.SetValue, new EditOperation() }, + { ConsoleCommand.DeleteValue, new DeleteOperation() }, { ConsoleCommand.SetList, new SetListOperation() }, { ConsoleCommand.Print, new PrintOperation() }, { ConsoleCommand.PrintTree, new PrintTreeOperation() }, diff --git a/NBTUtil/NBTUtil.csproj b/NBTUtil/NBTUtil.csproj index 8571a2f..7b90512 100644 --- a/NBTUtil/NBTUtil.csproj +++ b/NBTUtil/NBTUtil.csproj @@ -45,6 +45,7 @@ + diff --git a/NBTUtil/Ops/DeleteOperation.cs b/NBTUtil/Ops/DeleteOperation.cs new file mode 100644 index 0000000..a3b165c --- /dev/null +++ b/NBTUtil/Ops/DeleteOperation.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using NBTExplorer.Model; + +namespace NBTUtil.Ops +{ + class DeleteOperation : ConsoleOperation + { + public override bool OptionsValid (ConsoleOptions options) + { + return true; + } + + public override bool CanProcess (DataNode dataNode) + { + return (dataNode != null) && dataNode.CanDeleteNode && (dataNode.Root != dataNode); + } + + public override bool Process (DataNode dataNode, ConsoleOptions options) + { + return dataNode.DeleteNode(); + } + } +} From 00e8edf453306398a777e9f790c098aefbce7e7e Mon Sep 17 00:00:00 2001 From: Jon Kunkee Date: Sun, 28 Jun 2020 16:40:21 -0700 Subject: [PATCH 3/3] Fix failure accounting, add comments --- NBTUtil/ConsoleOptions.cs | 2 +- NBTUtil/ConsoleRunner.cs | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/NBTUtil/ConsoleOptions.cs b/NBTUtil/ConsoleOptions.cs index 863650d..b43ac3c 100644 --- a/NBTUtil/ConsoleOptions.cs +++ b/NBTUtil/ConsoleOptions.cs @@ -56,6 +56,7 @@ public ConsoleOptions () if (!string.IsNullOrEmpty(v)) Values.Add(v); }}, + { "delete", "Delete the NBT tag if found", v => Command = ConsoleCommand.DeleteValue }, { "help", "Print this help message", v => Command = ConsoleCommand.Help }, { "<>", v => { switch (_currentKey) { @@ -65,7 +66,6 @@ public ConsoleOptions () break; } }}, - { "delete", "Delete the NBT tag if found", v => Command = ConsoleCommand.DeleteValue }, }; } diff --git a/NBTUtil/ConsoleRunner.cs b/NBTUtil/ConsoleRunner.cs index df1a465..4a387ef 100644 --- a/NBTUtil/ConsoleRunner.cs +++ b/NBTUtil/ConsoleRunner.cs @@ -29,6 +29,8 @@ public ConsoleRunner () public bool Run (string[] args) { + // Parse and validate command line arguments. + _options.Parse(args); if (_options.Command == ConsoleCommand.Help) @@ -48,6 +50,9 @@ public bool Run (string[] args) var nodesToProcess = new List(); + // Iterate over all nodes matching the provided Path and create a list of the ones that can be processed + // using the provided ConsoleCommand. + foreach (var node in new NbtPathEnumerator(_options.Path)) { if (op.CanProcess(node)) @@ -61,18 +66,29 @@ public bool Run (string[] args) } } + // Iterate over all the processable nodes and process them. + // Doing this separately from the CanProcess loop allows Process to make significant changes to the NBT + // tree like node deletion. + foreach (var targetNode in nodesToProcess) { + // Since Process may render targetNode inoperable, save targetNode.Root beforehand. var root = targetNode.Root; - if (!op.Process(targetNode, _options)) { + if (op.Process(targetNode, _options)) + { + // Now that processing has succeeded, save the changes. + root.Save(); + Console.WriteLine(targetNode.NodePath + ": OK"); + successCount++; + } + else + { + // Since processing failed, discard any changes that may have been made. This prevents other + // iterations of this loop from saving them. + targetNode.RefreshNode(); Console.WriteLine(targetNode.NodePath + ": ERROR (apply)"); failCount++; } - - root.Save(); - - Console.WriteLine(targetNode.NodePath + ": OK"); - successCount++; } Console.WriteLine("Operation complete. Nodes succeeded: {0} Nodes failed: {1}", successCount, failCount);