diff --git a/SharpNBT/TagWriter.cs b/SharpNBT/TagWriter.cs index 67f6bef..5af5265 100644 --- a/SharpNBT/TagWriter.cs +++ b/SharpNBT/TagWriter.cs @@ -306,7 +306,7 @@ public class TagWriter : TagIO [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteTypeAndName(Tag tag) { - if (tag.Parent is ListTag) + if (tag.Parent is ListTag || string.IsNullOrEmpty(tag.Name)) return; BaseStream.WriteByte((byte) tag.Type); diff --git a/SharpNBT/Tags/CompoundTag.cs b/SharpNBT/Tags/CompoundTag.cs index fbc87d5..256b688 100644 --- a/SharpNBT/Tags/CompoundTag.cs +++ b/SharpNBT/Tags/CompoundTag.cs @@ -39,12 +39,12 @@ public class CompoundTag : Tag, IDictionary, ICollection { foreach (var value in values) { - dict.Add(value.Name!, AssertName(value)); + dict.Add(value.Name!, ValidateChild(value)); } } - + /// - void ICollection>.Add(KeyValuePair item) => dict.Add(item.Key, item.Value); + void ICollection>.Add(KeyValuePair item) => Add(item.Value); /// bool ICollection>.Contains(KeyValuePair item) => dict.Contains(item); @@ -61,12 +61,25 @@ public class CompoundTag : Tag, IDictionary, ICollection /// bool ICollection.IsReadOnly => false; - + /// - bool ICollection>.Remove(KeyValuePair item) => dict.Remove(item.Key); + bool ICollection>.Remove(KeyValuePair item) + { + if (dict.Remove(item.Key)) + { + item.Value.Parent = null; + return true; + } + return false; + } /// - public void Clear() => dict.Clear(); + public void Clear() + { + foreach (var child in dict.Values) + child.Parent = null; + dict.Clear(); + } /// public int Count => dict.Count; @@ -88,10 +101,10 @@ public class CompoundTag : Tag, IDictionary, ICollection } /// - public void Add(string key, Tag value) => dict.Add(key, AssertName(value)); + public void Add(string key, Tag value) => dict.Add(key, ValidateChild(value)); /// - public void Add(Tag value) => dict.Add(value.Name!, AssertName(value)); + public void Add(Tag value) => dict.Add(value.Name!, ValidateChild(value)); /// public bool ContainsKey(string key) => dict.ContainsKey(key); @@ -100,10 +113,24 @@ public class CompoundTag : Tag, IDictionary, ICollection public bool Contains(Tag tag) => !string.IsNullOrEmpty(tag.Name) && dict.ContainsKey(tag.Name); /// - public bool Remove(string key) => dict.Remove(key); + public bool Remove(string key) + { + if (dict.TryGetValue(key, out var tag)) + tag.Parent = null; + return dict.Remove(key); + } /// - public bool Remove(Tag item) => !string.IsNullOrWhiteSpace(item.Name) && dict.Remove(item.Name); + public bool Remove(Tag item) + { + if (!string.IsNullOrWhiteSpace(item.Name) && dict.Remove(item.Name)) + { + item.Parent = null; + return true; + } + + return false; + } /// public bool TryGetValue(string key, out Tag value) => dict.TryGetValue(key, out value!); @@ -131,7 +158,7 @@ public class CompoundTag : Tag, IDictionary, ICollection public Tag this[string name] { get => dict[name]; - set => dict[name] = value; + set => dict[name] = ValidateChild(value); } public TTag Get(string name) where TTag : Tag @@ -249,10 +276,11 @@ public class CompoundTag : Tag, IDictionary, ICollection } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Tag AssertName(Tag tag) + private Tag ValidateChild(Tag tag) { if (string.IsNullOrWhiteSpace(tag.Name)) throw new FormatException(Strings.ChildrenMustBeNamed); + tag.Parent = this; return tag; } } \ No newline at end of file diff --git a/SharpNBT/Tags/ListTag.cs b/SharpNBT/Tags/ListTag.cs index c976ae8..fc189e5 100644 --- a/SharpNBT/Tags/ListTag.cs +++ b/SharpNBT/Tags/ListTag.cs @@ -20,7 +20,7 @@ public class ListTag : Tag, IList /// /// Gets the NBT type of this tag's children. /// - public TagType ChildType { get; private set; } + public TagType ChildType { get; } /// /// Creates a new instance of the class. @@ -54,7 +54,7 @@ public class ListTag : Tag, IList public ListTag(string? name, TagType childType, IEnumerable children) : this(name, childType) { foreach (var item in children) - list.Add(AssertType(item)); + list.Add(ValidateChild(item)); } /// @@ -64,12 +64,12 @@ public class ListTag : Tag, IList IEnumerator IEnumerable.GetEnumerator() => list.GetEnumerator(); /// - public void Add(Tag item) => list.Add(AssertType(item)); + public void Add(Tag item) => list.Add(ValidateChild(item)); public void AddRange(IEnumerable items) { foreach (var item in items) - list.Add(AssertType(item)); + list.Add(ValidateChild(item)); } /// @@ -82,7 +82,16 @@ public class ListTag : Tag, IList public void CopyTo(Tag[] array, int arrayIndex) => list.CopyTo(array, arrayIndex); /// - public bool Remove(Tag item) => list.Remove(item); + public bool Remove(Tag item) + { + if (list.Remove(item)) + { + item.Parent = null; + return true; + } + + return false; + } /// public int Count => list.Count; @@ -94,16 +103,21 @@ public class ListTag : Tag, IList public int IndexOf(Tag item) => list.IndexOf(item); /// - public void Insert(int index, Tag item) => list.Insert(index, AssertType(item)); + public void Insert(int index, Tag item) => list.Insert(index, ValidateChild(item)); /// - public void RemoveAt(int index) => list.RemoveAt(index); + public void RemoveAt(int index) + { + var item = list[index]; + item.Parent = null; + list.RemoveAt(index); + } /// public Tag this[int index] { get => list[index]; - set => list[index] = AssertType(value); + set => list[index] = ValidateChild(value); } /// @@ -173,14 +187,13 @@ public class ListTag : Tag, IList } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Tag AssertType(Tag tag) + private Tag ValidateChild(Tag tag) { if (tag.Type != ChildType) throw new ArrayTypeMismatchException(Strings.ChildWrongType); + tag.Parent = this; return tag; } private readonly List list; - - } \ No newline at end of file diff --git a/SharpNBT/Tags/Tag.cs b/SharpNBT/Tags/Tag.cs index 4f69f01..ae32fb2 100644 --- a/SharpNBT/Tags/Tag.cs +++ b/SharpNBT/Tags/Tag.cs @@ -31,7 +31,7 @@ public abstract class Tag : IEquatable, ICloneable /// /// Gets the parent this object is a child of. /// - [Obsolete("Parent property will be removed in a future version.")] + [Obsolete("Parent property may be removed in a future version.")] public Tag? Parent { get; internal set; } /// @@ -181,7 +181,7 @@ public abstract class Tag : IEquatable, ICloneable // Serialize then deserialize to make a deep-copy using var stream = new MemoryStream(); - // Might as well not worry about swapping bits, just use native endian + // Use native endian var opts = BitConverter.IsLittleEndian ? FormatOptions.LittleEndian : FormatOptions.BigEndian; using var writer = new TagWriter(stream, opts, true); using var reader = new TagReader(stream, opts, true); @@ -192,6 +192,7 @@ public abstract class Tag : IEquatable, ICloneable return reader.ReadTag(!string.IsNullOrWhiteSpace(Name)); } + /// /// Tests for equality of this object with another instance. ///