diff --git a/NBTUtil/ConsoleOptions.cs b/NBTUtil/ConsoleOptions.cs index 1fdee5c..b43ac3c 100644 --- a/NBTUtil/ConsoleOptions.cs +++ b/NBTUtil/ConsoleOptions.cs @@ -11,6 +11,7 @@ public enum ConsoleCommand Print, PrintTree, SetValue, + DeleteValue, SetList, Json, Help, @@ -55,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) { diff --git a/NBTUtil/ConsoleRunner.cs b/NBTUtil/ConsoleRunner.cs index 0f94ba1..4a387ef 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() }, @@ -28,6 +29,8 @@ public ConsoleRunner () public bool Run (string[] args) { + // Parse and validate command line arguments. + _options.Parse(args); if (_options.Command == ConsoleCommand.Help) @@ -45,20 +48,47 @@ 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)"); - failCount++; + 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)) + { + nodesToProcess.Add(node); } - if (!op.Process(targetNode, _options)) { - Console.WriteLine(targetNode.NodePath + ": ERROR (apply)"); + else + { + Console.WriteLine(node.NodePath + ": ERROR (invalid command)"); failCount++; } + } - targetNode.Root.Save(); + // 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. - Console.WriteLine(targetNode.NodePath + ": OK"); - successCount++; + foreach (var targetNode in nodesToProcess) { + // Since Process may render targetNode inoperable, save targetNode.Root beforehand. + var root = targetNode.Root; + + 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++; + } } Console.WriteLine("Operation complete. Nodes succeeded: {0} Nodes failed: {1}", successCount, failCount); 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(); + } + } +}