diff --git a/SharpNBT/TagBuilder.cs b/SharpNBT/TagBuilder.cs
index 71d5c90..f60c13a 100644
--- a/SharpNBT/TagBuilder.cs
+++ b/SharpNBT/TagBuilder.cs
@@ -42,7 +42,7 @@ public class TagBuilder
/// The name of the node to add.
/// The value of the tag.
/// Returns this instance for chaining.
- public TagBuilder AddBool(string? name, bool value) => AddTag(new BoolTag(name, value));
+ public TagBuilder AddBool(string? name, bool value) => AddTag(new ByteTag(name, value));
///
/// Adds a new unnamed with the specified to the tree at the current depth.
@@ -58,7 +58,10 @@ public class TagBuilder
/// The value of the tag.
/// Returns this instance for chaining.
public TagBuilder AddByte(string? name, byte value) => AddTag(new ByteTag(name, value));
-
+
+ ///
+ public TagBuilder AddByte(string? name, int value) => AddByte(name, unchecked((byte)(value & 0xFF)));
+
///
[CLSCompliant(false)]
public TagBuilder AddByte(string? name, sbyte value) => AddByte(name, unchecked((byte)value));
@@ -70,6 +73,9 @@ public class TagBuilder
/// Returns this instance for chaining.
public TagBuilder AddByte(byte value) => AddByte(null, value);
+ ///
+ public TagBuilder AddByte(int value) => AddByte(null, unchecked((byte)(value & 0xFF)));
+
///
[CLSCompliant(false)]
public TagBuilder AddByte(sbyte value) => AddByte(null, unchecked((byte)value));
@@ -82,6 +88,9 @@ public class TagBuilder
/// Returns this instance for chaining.
public TagBuilder AddShort(string? name, short value) => AddTag(new ShortTag(name, value));
+ ///
+ public TagBuilder AddShort(string? name, int value) => AddShort(name, unchecked((short)(value & 0xFFFF)));
+
///
[CLSCompliant(false)]
public TagBuilder AddShort(string? name, ushort value) => AddShort(name, unchecked((short)value));
@@ -93,6 +102,9 @@ public class TagBuilder
/// Returns this instance for chaining.
public TagBuilder AddShort(short value) => AddShort(null, value);
+ ///
+ public TagBuilder AddShort(int value) => AddShort(null, unchecked((short)(value & 0xFFFF)));
+
///
[CLSCompliant(false)]
public TagBuilder AddShort(ushort value) => AddShort(null, unchecked((short)value));
@@ -236,8 +248,7 @@ public class TagBuilder
///
[CLSCompliant(false)]
public TagBuilder AddByteArray(IEnumerable values) => AddByteArray(null, values.ToArray());
-
-
+
///
/// Adds a new with the specified to the tree at the current depth.
///
diff --git a/SharpNBT/TagWriter.cs b/SharpNBT/TagWriter.cs
index 9f05a99..67f6bef 100644
--- a/SharpNBT/TagWriter.cs
+++ b/SharpNBT/TagWriter.cs
@@ -118,7 +118,7 @@ public class TagWriter : TagIO
public virtual void WriteByteArray(ByteArrayTag tag)
{
WriteTypeAndName(tag);
- WriteCount(tag);
+ WriteCount(tag.Count);
BaseStream.Write(tag.ToArray(), 0, tag.Count);
}
@@ -129,7 +129,7 @@ public class TagWriter : TagIO
public virtual void WriteIntArray(IntArrayTag tag)
{
WriteTypeAndName(tag);
- WriteCount(tag);
+ WriteCount(tag.Count);
var values = new Span(tag.ToArray());
if (UseVarInt)
@@ -155,7 +155,7 @@ public class TagWriter : TagIO
{
WriteTypeAndName(tag);
- WriteCount(tag);
+ WriteCount(tag.Count);
var values = new Span(tag.ToArray());
if (UseVarInt)
@@ -182,7 +182,7 @@ public class TagWriter : TagIO
{
WriteTypeAndName(tag);
BaseStream.WriteByte((byte) tag.ChildType);
- WriteCount(tag);
+ WriteCount(tag.Count);
foreach (var child in tag)
WriteTag(child);
@@ -377,11 +377,11 @@ public class TagWriter : TagIO
return bytes;
}
- private void WriteCount(EnumerableTag tag)
+ private void WriteCount(int count)
{
if (UseVarInt)
- VarInt.Write(BaseStream, tag.Count, ZigZagEncoding);
+ VarInt.Write(BaseStream, count, ZigZagEncoding);
else
- BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int));
+ BaseStream.Write(GetBytes(count), 0, sizeof(int));
}
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/ArrayTag.cs b/SharpNBT/Tags/ArrayTag.cs
index c520689..71f3ec6 100644
--- a/SharpNBT/Tags/ArrayTag.cs
+++ b/SharpNBT/Tags/ArrayTag.cs
@@ -1,6 +1,142 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
+using System.Text;
+using JetBrains.Annotations;
+
namespace SharpNBT;
-public class ArrayTag
+///
+/// Base class for NBT tags that contain a fixed-size array of numeric types.
+///
+/// A value type that implements .
+[PublicAPI][Serializable]
+public abstract class ArrayTag : Tag, IReadOnlyList where T : unmanaged, INumber
{
+ ///
+ /// Gets a over the tag data.
+ ///
+ public Span Span => new(array);
+
+ ///
+ /// Gets a over the tag data.
+ ///
+ public Memory Memory => new(array);
+ ///
+ /// The value of the tag.
+ // ReSharper disable InvalidXmlDocComment
+ protected ArrayTag(TagType type, string? name, T[] value) : base(type, name)
+ // ReSharper restore InvalidXmlDocComment
+ {
+ array = value;
+ }
+
+ ///
+ protected ArrayTag(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ var _ = info.GetInt32("count");
+ var value = info.GetValue("values", typeof(T[])) as T[];
+ array = value ?? Array.Empty();
+ }
+
+ ///
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ info.AddValue("count", array.Length);
+ info.AddValue("values", array);
+ }
+
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ // ReSharper disable ForCanBeConvertedToForeach
+ for (var i = 0; i < array.Length; i++)
+ yield return array[i];
+ // ReSharper restore ForCanBeConvertedToForeach
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => array.GetEnumerator();
+
+ ///
+ // ReSharper disable once ParameterHidesMember
+ public void CopyTo(T[] array, int arrayIndex) => this.array.CopyTo(array, arrayIndex);
+
+ ///
+ public int Count => array.Length;
+
+ ///
+ public int IndexOf(T item)
+ {
+ for (var i = 0; i < array.Length; i++)
+ {
+ if (array[i] == item)
+ return i;
+ }
+
+ return -1;
+ }
+
+ ///
+ /// This method being defined provides Range indexers for the class.
+ public Span Slice(int start, int length) => new(array, start, length);
+
+ ///
+ public T this[int index]
+ {
+ get => array[index];
+ set => array[index] = value;
+ }
+
+ ///
+ /// Returns a reference to the underlying memory of this object that is be pinned using the
+ /// statement.
+ ///
+ /// A reference to the first value in the underlying array.
+ public ref T GetPinnableReference() => ref array[0] ;
+
+ private protected string Stringify(char prefix, char? suffix)
+ {
+ var sb = new StringBuilder(32 + array.Length * 4);
+ sb.Append($"{StringifyName}:[{prefix};");
+
+ for (var i = 0; i < array.Length; i++)
+ {
+ if (i > 0)
+ sb.Append(',');
+ sb.Append(array[i]);
+ if (suffix != null)
+ sb.Append(suffix.Value);
+ }
+ sb.Append(']');
+ return sb.ToString();
+ }
+
+ ///
+ /// Implicit conversion of a an to an array of .
+ ///
+ /// The to be converted.
+ /// The value of as an array of .
+ public static implicit operator T[](ArrayTag tag) => tag.array;
+
+ ///
+ /// Implicit conversion of a an to a .
+ ///
+ /// The to be converted.
+ /// The value of as a .
+ public static implicit operator Span(ArrayTag tag) => new(tag.array);
+
+ ///
+ /// Implicit conversion of a an to a .
+ ///
+ /// The to be converted.
+ /// The value of as a .
+ public static implicit operator Memory(ArrayTag tag) => new(tag.array);
+
+ private readonly T[] array;
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/BoolTag.cs b/SharpNBT/Tags/BoolTag.cs
index 2e98395..2bf0591 100644
--- a/SharpNBT/Tags/BoolTag.cs
+++ b/SharpNBT/Tags/BoolTag.cs
@@ -12,19 +12,19 @@ namespace SharpNBT;
/// actually serialized as.
///
[PublicAPI][Serializable]
-[Obsolete("Use the IsBool and Bool properties of ByteTag. This class will be removed in a future release.")]
-public class BoolTag : Tag
+[Obsolete("Use the IsBool and Bool properties of ByteTag. This class will be removed in a future version.")]
+public class BoolTag : Tag
{
- private const string TRUE = "true";
- private const string FALSE = "false";
-
+ public bool Value { get; set; }
+
///
/// Creates a new instance of the class with the specified .
///
/// The name of the tag, or if tag has no name.
/// The value to assign to this tag.
- public BoolTag(string? name, bool value) : base(TagType.Byte, name, value)
+ public BoolTag(string? name, bool value) : base(TagType.Byte, name)
{
+ Value = value;
}
///
@@ -37,7 +37,7 @@ public class BoolTag : Tag
}
///
- public override string ToString() => $"TAG_Bool({PrettyName}): {(Value ? TRUE : FALSE)}";
+ public override string ToString() => $"TAG_Byte({PrettyName}): {(Value ? "true" : "false")}";
///
/// Implicit conversion of this tag to a .
@@ -51,6 +51,6 @@ public class BoolTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{(Value ? TRUE : FALSE)}";
+ public override string Stringify() => $"{StringifyName}:{(Value ? "true" : "false")}";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/ByteArrayTag.cs b/SharpNBT/Tags/ByteArrayTag.cs
index e964df2..0d27a75 100644
--- a/SharpNBT/Tags/ByteArrayTag.cs
+++ b/SharpNBT/Tags/ByteArrayTag.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@@ -13,8 +14,17 @@ namespace SharpNBT;
/// the bits are equivalent for your values.
///
[PublicAPI][Serializable]
-public class ByteArrayTag : EnumerableTag
+public class ByteArrayTag : ArrayTag
{
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The name of the tag, or if tag has no name.
+ /// The capacity of the array.
+ public ByteArrayTag(string? name, int capacity) : base(TagType.IntArray, name, new byte[capacity])
+ {
+ }
+
///
/// Initializes a new instance of the .
///
@@ -29,7 +39,7 @@ public class ByteArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public ByteArrayTag(string? name, IEnumerable values) : base(TagType.ByteArray, name, values)
+ public ByteArrayTag(string? name, IEnumerable values) : base(TagType.ByteArray, name, values.ToArray())
{
}
@@ -38,7 +48,7 @@ public class ByteArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public ByteArrayTag(string? name, ReadOnlySpan values) : base(TagType.ByteArray, name, values)
+ public ByteArrayTag(string? name, ReadOnlySpan values) : base(TagType.ByteArray, name, values.ToArray())
{
}
@@ -63,11 +73,5 @@ public class ByteArrayTag : EnumerableTag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify()
- {
- var values = new string[Count];
- for (var i = 0; i < Count; i++)
- values[i] = $"{this[i]}b";
- return $"{StringifyName}[B;{string.Join(',', values)}]";
- }
+ public override string Stringify() => Stringify('B', 'b');
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/ByteTag.cs b/SharpNBT/Tags/ByteTag.cs
index c70124d..6c1360b 100644
--- a/SharpNBT/Tags/ByteTag.cs
+++ b/SharpNBT/Tags/ByteTag.cs
@@ -13,7 +13,7 @@ namespace SharpNBT;
/// equivalent.
///
[PublicAPI][Serializable]
-public class ByteTag : Tag
+public class ByteTag : NumericTag
{
///
/// Gets a flag indicating if this was assigned a value.
@@ -95,9 +95,13 @@ public class ByteTag : Tag
protected ByteTag(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
-
+
///
- public override string ToString() => $"TAG_Byte({PrettyName}): {Value}";
+ public override string ToString()
+ {
+ object obj = IsBool ? Bool : Value;
+ return $"TAG_Byte({PrettyName}): {obj}";
+ }
///
/// Implicit conversion of this tag to a .
@@ -126,5 +130,5 @@ public class ByteTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{Value}B";
+ public override string Stringify() => $"{StringifyName}:{Value}B";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/CompoundTag.cs b/SharpNBT/Tags/CompoundTag.cs
index b3f2941..ad6f90c 100644
--- a/SharpNBT/Tags/CompoundTag.cs
+++ b/SharpNBT/Tags/CompoundTag.cs
@@ -122,7 +122,9 @@ public class CompoundTag : TagContainer
for (var i = 0; i < strings.Length; i++)
strings[i] = this[i].Stringify();
- return $"{StringifyName}{{{string.Join(',', strings)}}}";
+ // TODO: Use StringBuilder
+
+ return $"{StringifyName}:{{{string.Join(',', strings)}}}";
}
///
diff --git a/SharpNBT/Tags/DoubleTag.cs b/SharpNBT/Tags/DoubleTag.cs
index 2dde1be..08559f9 100644
--- a/SharpNBT/Tags/DoubleTag.cs
+++ b/SharpNBT/Tags/DoubleTag.cs
@@ -8,7 +8,7 @@ namespace SharpNBT;
/// A tag that contains a single IEEE-754 double-precision floating point number.
///
[PublicAPI][Serializable]
-public class DoubleTag : Tag
+public class DoubleTag : NumericTag
{
///
/// Creates a new instance of the class with the specified .
@@ -43,5 +43,5 @@ public class DoubleTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{Value:0.0}D";
+ public override string Stringify() => $"{StringifyName}:{Value:0.0}D";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/EnumerableTag.cs b/SharpNBT/Tags/EnumerableTag.cs
index c54b89a..3ba7e64 100644
--- a/SharpNBT/Tags/EnumerableTag.cs
+++ b/SharpNBT/Tags/EnumerableTag.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Text;
using JetBrains.Annotations;
@@ -72,7 +71,9 @@ public abstract class EnumerableTag : Tag, IList
protected EnumerableTag(SerializationInfo info, StreamingContext context) : base(info, context)
{
var dummy = info.GetInt32("count");
- internalList.AddRange((T[]) info.GetValue("values", typeof(T[])));
+ var obj = info.GetValue("values", typeof(T[])) as T[];
+ if (obj is IEnumerable e)
+ internalList.AddRange(e);
}
/// Populates a with the data needed to serialize the target object.
@@ -101,7 +102,7 @@ public abstract class EnumerableTag : Tag, IList
/// The is read-only.
///
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
- public virtual void Add([DisallowNull] T item) => internalList.Add(item);
+ public virtual void Add(T item) => internalList.Add(item);
///
/// Adds the elements of the specified collection to the .
@@ -121,7 +122,7 @@ public abstract class EnumerableTag : Tag, IList
/// The is read-only.
///
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
- public virtual void Insert(int index, [DisallowNull] T item) => internalList.Insert(index, item);
+ public virtual void Insert(int index, T item) => internalList.Insert(index, item);
/// Gets or sets the element at the specified index.
/// The zero-based index of the element to get or set.
@@ -130,7 +131,6 @@ public abstract class EnumerableTag : Tag, IList
/// The property is set and the is read-only.
/// The element at the specified index.
///
- [DisallowNull]
public virtual T this[int index]
{
get => internalList[index];
diff --git a/SharpNBT/Tags/FloatTag.cs b/SharpNBT/Tags/FloatTag.cs
index b7319a7..813d8b5 100644
--- a/SharpNBT/Tags/FloatTag.cs
+++ b/SharpNBT/Tags/FloatTag.cs
@@ -8,7 +8,7 @@ namespace SharpNBT;
/// A tag that contains a single IEEE-754 single-precision floating point number.
///
[PublicAPI][Serializable]
-public class FloatTag : Tag
+public class FloatTag : NumericTag
{
///
/// Creates a new instance of the class with the specified .
@@ -42,5 +42,5 @@ public class FloatTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{Value:0.0}F";
+ public override string Stringify() => $"{StringifyName}:{Value:0.0}F";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/IntArrayTag.cs b/SharpNBT/Tags/IntArrayTag.cs
index 33a1382..fc9b965 100644
--- a/SharpNBT/Tags/IntArrayTag.cs
+++ b/SharpNBT/Tags/IntArrayTag.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@@ -9,15 +10,17 @@ namespace SharpNBT;
/// A tag that whose value is a contiguous sequence of 32-bit integers.
///
[PublicAPI][Serializable]
-public class IntArrayTag : EnumerableTag
+public class IntArrayTag : ArrayTag
{
///
/// Initializes a new instance of the .
///
/// The name of the tag, or if tag has no name.
- public IntArrayTag(string? name) : base(TagType.IntArray, name)
+ /// The capacity of the array.
+ public IntArrayTag(string? name, int capacity) : base(TagType.IntArray, name, new int[capacity])
{
}
+
///
/// Initializes a new instance of the with the specified .
///
@@ -33,7 +36,7 @@ public class IntArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public IntArrayTag(string? name, IEnumerable values) : base(TagType.IntArray, name, values)
+ public IntArrayTag(string? name, IEnumerable values) : base(TagType.IntArray, name, values.ToArray())
{
}
@@ -42,7 +45,7 @@ public class IntArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public IntArrayTag(string? name, ReadOnlySpan values) : base(TagType.IntArray, name, values)
+ public IntArrayTag(string? name, ReadOnlySpan values) : base(TagType.IntArray, name, values.ToArray())
{
}
@@ -67,5 +70,5 @@ public class IntArrayTag : EnumerableTag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}[I;{string.Join(',', this)}]";
+ public override string Stringify() => Stringify('I', null);
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/IntTag.cs b/SharpNBT/Tags/IntTag.cs
index aa49a3c..a62a117 100644
--- a/SharpNBT/Tags/IntTag.cs
+++ b/SharpNBT/Tags/IntTag.cs
@@ -8,7 +8,7 @@ namespace SharpNBT;
/// A tag that contains a single 32-bit integer value.
///
[PublicAPI][Serializable]
-public class IntTag : Tag
+public class IntTag : NumericTag
{
///
/// Gets or sets the value of this tag as an unsigned value.
@@ -70,5 +70,5 @@ public class IntTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{Value}";
+ public override string Stringify() => $"{StringifyName}:{Value}";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/ListTag.cs b/SharpNBT/Tags/ListTag.cs
index faa9205..a6a12c1 100644
--- a/SharpNBT/Tags/ListTag.cs
+++ b/SharpNBT/Tags/ListTag.cs
@@ -96,6 +96,8 @@ public class ListTag : TagContainer
for (var i = 0; i < strings.Length; i++)
strings[i] = this[i].Stringify();
- return $"{StringifyName}[{string.Join(',', strings)}]";
+ // TODO: Use StringBuilder
+
+ return $"{StringifyName}:[{string.Join(',', strings)}]";
}
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/LongArrayTag.cs b/SharpNBT/Tags/LongArrayTag.cs
index 4c249ec..609e4da 100644
--- a/SharpNBT/Tags/LongArrayTag.cs
+++ b/SharpNBT/Tags/LongArrayTag.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@@ -9,13 +10,14 @@ namespace SharpNBT;
/// A tag that whose value is a contiguous sequence of 64-bit integers.
///
[PublicAPI][Serializable]
-public class LongArrayTag : EnumerableTag
+public class LongArrayTag : ArrayTag
{
///
/// Initializes a new instance of the .
///
/// The name of the tag, or if tag has no name.
- public LongArrayTag(string? name) : base(TagType.LongArray, name)
+ /// The capacity of the array.
+ public LongArrayTag(string? name, int capacity) : base(TagType.LongArray, name, new long[capacity])
{
}
///
@@ -23,7 +25,7 @@ public class LongArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public LongArrayTag(string? name, long[] values) : base(TagType.LongArray, name, values)
+ public LongArrayTag(string? name, long[] values) : base(TagType.LongArray, name, values.ToArray())
{
}
@@ -41,7 +43,7 @@ public class LongArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public LongArrayTag(string? name, IEnumerable values) : base(TagType.LongArray, name, values)
+ public LongArrayTag(string? name, IEnumerable values) : base(TagType.LongArray, name, values.ToArray())
{
}
@@ -50,7 +52,7 @@ public class LongArrayTag : EnumerableTag
///
/// The name of the tag, or if tag has no name.
/// A collection of values to include in this tag.
- public LongArrayTag(string? name, ReadOnlySpan values) : base(TagType.LongArray, name, values)
+ public LongArrayTag(string? name, ReadOnlySpan values) : base(TagType.LongArray, name, values.ToArray())
{
}
@@ -66,11 +68,5 @@ public class LongArrayTag : EnumerableTag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify()
- {
- var values = new string[Count];
- for (var i = 0; i < Count; i++)
- values[i] = $"{this[i]}l";
- return $"{StringifyName}[L;{string.Join(',', values)}]";
- }
+ public override string Stringify() => Stringify('L', 'l');
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/LongTag.cs b/SharpNBT/Tags/LongTag.cs
index 978062e..c118130 100644
--- a/SharpNBT/Tags/LongTag.cs
+++ b/SharpNBT/Tags/LongTag.cs
@@ -8,7 +8,7 @@ namespace SharpNBT;
/// A tag that contains a single 64-bit integer value.
///
[PublicAPI][Serializable]
-public class LongTag : Tag
+public class LongTag : NumericTag
{
///
/// Gets or sets the value of this tag as an unsigned value.
@@ -70,5 +70,5 @@ public class LongTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{Value}L";
+ public override string Stringify() => $"{StringifyName}:{Value}L";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/NumericTag.cs b/SharpNBT/Tags/NumericTag.cs
index a97f1f0..22d023a 100644
--- a/SharpNBT/Tags/NumericTag.cs
+++ b/SharpNBT/Tags/NumericTag.cs
@@ -13,19 +13,32 @@ namespace SharpNBT;
[PublicAPI][Serializable]
public abstract class NumericTag : Tag, IEquatable>, IComparable>, IComparable where T : unmanaged, INumber
{
- public T Value { get; set; }
+ ///
+ /// Gets or sets the value of the tag.
+ ///
+ public T Value { get; [Obsolete("Numeric tag types will be made immutable in a future version.")] set; }
+ ///
protected NumericTag(TagType type, string? name, T value) : base(type, name)
{
Value = value;
}
+ ///
protected NumericTag(SerializationInfo info, StreamingContext context) : base(info, context)
{
var value = info.GetValue("value", typeof(T));
Value = value is null ? default : (T)value;
}
+
+ ///
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ info.AddValue("value", Value, typeof(T));
+ }
+ ///
public bool Equals(NumericTag? other)
{
if (ReferenceEquals(null, other)) return false;
@@ -33,6 +46,7 @@ public abstract class NumericTag : Tag, IEquatable>, IComparabl
return base.Equals(other) && Value.Equals(other.Value);
}
+ ///
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
@@ -41,8 +55,10 @@ public abstract class NumericTag : Tag, IEquatable>, IComparabl
return Equals((NumericTag)obj);
}
+ ///
public override int GetHashCode() => base.GetHashCode();
+ ///
public int CompareTo(NumericTag? other)
{
if (ReferenceEquals(this, other)) return 0;
@@ -50,6 +66,7 @@ public abstract class NumericTag : Tag, IEquatable>, IComparabl
return Value.CompareTo(other.Value);
}
+ ///
public int CompareTo(object? obj)
{
if (ReferenceEquals(null, obj)) return 1;
@@ -57,27 +74,80 @@ public abstract class NumericTag : Tag, IEquatable>, IComparabl
return obj is NumericTag other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(NumericTag)}");
}
+ ///
+ /// Compares two values to determine equality.
+ ///
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is equal to ; otherwise,
+ /// .
+ ///
public static bool operator ==(NumericTag? left, NumericTag? right) => Equals(left, right);
+ ///
+ /// Compares two values to determine inequality.
+ ///
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is not equal to ; otherwise,
+ /// .
+ ///
public static bool operator !=(NumericTag? left, NumericTag? right) => !Equals(left, right);
+ /// Compares two values to determine which is less.
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is less than ; otherwise,
+ /// .
+ ///
public static bool operator <(NumericTag? left, NumericTag? right)
{
return Comparer>.Default.Compare(left, right) < 0;
}
+ /// Compares two values to determine which is greater.
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is greater than ; otherwise,
+ /// .
+ ///
public static bool operator >(NumericTag? left, NumericTag? right)
{
return Comparer>.Default.Compare(left, right) > 0;
}
+ /// Compares two values to determine which is less or equal.
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is less than or equal to ;
+ /// otherwise, .
+ ///
public static bool operator <=(NumericTag? left, NumericTag? right)
{
return Comparer>.Default.Compare(left, right) <= 0;
}
+ /// Compares two values to determine which is greater or equal.
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is greater than or equal to ;
+ /// otherwise, .
+ ///
public static bool operator >=(NumericTag? left, NumericTag? right)
{
return Comparer>.Default.Compare(left, right) >= 0;
}
+
+ ///
+ /// Implicit conversion of a an to a .
+ ///
+ /// The to be converted.
+ /// The value of as a .
+ public static implicit operator T(NumericTag tag) => tag.Value;
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/ShortTag.cs b/SharpNBT/Tags/ShortTag.cs
index 6cb95d7..7a6a1ae 100644
--- a/SharpNBT/Tags/ShortTag.cs
+++ b/SharpNBT/Tags/ShortTag.cs
@@ -8,7 +8,7 @@ namespace SharpNBT;
/// A tag that contains a single 16-bit integer value.
///
[PublicAPI][Serializable]
-public class ShortTag : Tag
+public class ShortTag : NumericTag
{
///
/// Gets or sets the value of this tag as an unsigned value.
@@ -76,5 +76,5 @@ public class ShortTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}{Value}S";
+ public override string Stringify() => $"{StringifyName}:{Value}S";
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/StringTag.cs b/SharpNBT/Tags/StringTag.cs
index 8c93a07..7e5c05c 100644
--- a/SharpNBT/Tags/StringTag.cs
+++ b/SharpNBT/Tags/StringTag.cs
@@ -1,4 +1,5 @@
using System;
+using System.Numerics;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@@ -8,26 +9,36 @@ namespace SharpNBT;
/// A tag the contains a UTF-8 string.
///
[PublicAPI][Serializable]
-public class StringTag : Tag
+public class StringTag : Tag, IEquatable
{
+ ///
+ /// Gets or sets the value of the tag.
+ ///
+ public string Value { get; [Obsolete("String tag type will be made immutable in a future version.")] set; }
+
///
/// Creates a new instance of the class with the specified .
///
/// The name of the tag, or if tag has no name.
/// The value to assign to this tag.
- public StringTag(string? name, string? value) : base(TagType.String, name, value)
+ public StringTag(string? name, string? value) : base(TagType.String, name)
{
+ Value = value ?? string.Empty;
}
- ///
- /// Required constructor for ISerializable implementation.
- ///
- /// The to describing this instance.
- /// The destination (see ) for this serialization.
+ ///
protected StringTag(SerializationInfo info, StreamingContext context) : base(info, context)
{
+ Value = info.GetString("value") ?? string.Empty;
}
+ ///
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ info.AddValue("value", Value);
+ }
+
///
public override string ToString() => $"TAG_String({PrettyName}): \"{Value}\"";
@@ -43,5 +54,46 @@ public class StringTag : Tag
///
/// This NBT tag in SNBT format.
///
- public override string Stringify() => $"{StringifyName}\"{Value}\"";
+ public override string Stringify() => $"{StringifyName}:\"{Value}\""; // TODO: Does this get properly escaped?
+
+ ///
+ public bool Equals(StringTag? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return base.Equals(other) && string.CompareOrdinal(Value, other.Value) == 0;
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ return obj.GetType() == GetType() && Equals((StringTag)obj);
+ }
+
+ ///
+ public override int GetHashCode() => base.GetHashCode(); // TODO: Add Value once immutable
+
+ ///
+ /// Compares two values to determine equality.
+ ///
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is equal to ; otherwise,
+ /// .
+ ///
+ public static bool operator ==(StringTag? left, StringTag? right) => Equals(left, right);
+
+ ///
+ /// Compares two values to determine inequality.
+ ///
+ /// The value to compare with .
+ /// The value to compare with .
+ ///
+ /// if is not equal to ; otherwise,
+ /// .
+ ///
+ public static bool operator !=(StringTag? left, StringTag? right) => !Equals(left, right);
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/Tag.cs b/SharpNBT/Tags/Tag.cs
index 2773778..fb4984f 100644
--- a/SharpNBT/Tags/Tag.cs
+++ b/SharpNBT/Tags/Tag.cs
@@ -32,7 +32,8 @@ public abstract class Tag : IEquatable, ISerializable, ICloneable
return new[]
{
typeof(TagType),
- typeof(Tag<>),
+ typeof(NumericTag<>),
+ typeof(ArrayTag<>),
typeof(Tag[]),
typeof(EnumerableTag<>),
typeof(TagContainer),
@@ -81,15 +82,20 @@ public abstract class Tag : IEquatable, ISerializable, ICloneable
Type = type;
Name = name;
}
-
+
///
/// Writes this tag as a formatted string to the given .
///
/// A instance to write to.
/// The current indent depth to write at.
/// The string to use for indents.
- protected internal abstract void PrettyPrinted(StringBuilder buffer, int level, string indent);
-
+ protected internal virtual void PrettyPrinted(StringBuilder buffer, int level, string indent)
+ {
+ for (var i = 0; i < level; i++)
+ buffer.Append(indent);
+ buffer.AppendLine(ToString());
+ }
+
///
/// Gets the name of the object as a human-readable quoted string, or a default name to indicate it has no name when applicable.
///
@@ -234,113 +240,7 @@ public abstract class Tag : IEquatable, ISerializable, ICloneable
{
if (string.IsNullOrEmpty(Name))
return string.Empty;
- return simpleNameMatcher.IsMatch(Name) ? $"{Name}: " : $"\"{Name}\": ";
+ return simpleNameMatcher.IsMatch(Name) ? Name : $"\"{Name}\"";
}
}
-}
-
-///
-/// Abstract base class for types that contain a single primitive value.
-///
-/// The type of the value the tag represents.
-[PublicAPI][Serializable]
-public abstract class Tag : Tag, IEquatable>
-{
- ///
- /// Gets or sets the value of the tag.
- ///
- public T Value { get; set; }
-
- ///
- /// Required constructor for ISerializable implementation.
- ///
- /// The to describing this instance.
- /// The destination (see ) for this serialization.
- protected Tag(SerializationInfo info, StreamingContext context) : base(info, context)
- {
- Value = (T)info.GetValue("value", typeof(T));
- }
-
- /// Populates a with the data needed to serialize the target object.
- /// The to populate with data.
- /// The destination (see ) for this serialization.
- /// The caller does not have the required permission.
- public override void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- base.GetObjectData(info, context);
- info.AddValue("value", Value, typeof(T));
- }
-
- ///
- /// Creates a new instance of the class with the specified .
- ///
- /// A constant describing the NBT type for this tag.
- /// The name of the tag, or if tag has no name.
- /// The value to assign to this tag.
- protected Tag(TagType type, string? name, T value) : base(type, name)
- {
- Value = value;
- }
-
- ///
- protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent)
- {
- for (var i = 0; i < level; i++)
- buffer.Append(indent);
- buffer.AppendLine(ToString());
- }
-
- /// Indicates whether the current object is equal to another object of the same type.
- /// An object to compare with this object.
- ///
- /// if the current object is equal to the parameter; otherwise, .
- ///
- public bool Equals(Tag? other)
- {
- if (ReferenceEquals(null, other)) return false;
- if (ReferenceEquals(this, other)) return true;
- return base.Equals(other) && EqualityComparer.Default.Equals(Value, other.Value);
- }
-
- /// Determines whether the specified object is equal to the current object.
- /// The object to compare with the current object.
- ///
- /// if the specified object is equal to the current object; otherwise, .
- ///
- public override bool Equals(object? obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != GetType()) return false;
- return Equals((Tag)obj);
- }
-
- /// Serves as the default hash function.
- /// A hash code for the current object.
- ///
- public override int GetHashCode()
- {
- unchecked
- {
- // ReSharper disable NonReadonlyMemberInGetHashCode
- return (base.GetHashCode() * 421) ^ EqualityComparer.Default.GetHashCode(Value);
- // ReSharper restore NonReadonlyMemberInGetHashCode
- }
- }
-
- ///
- /// Tests for equality of this object with another instance.
- ///
- /// First value to compare.
- /// Second value to compare.
- /// Result of comparison.
- public static bool operator ==(Tag left, Tag right) => Equals(left, right);
-
- ///
- /// Tests for inequality of this object with another instance.
- ///
- /// First value to compare.
- /// Second value to compare.
- /// Result of comparison.
- public static bool operator !=(Tag left, Tag right) => !Equals(left, right);
}
\ No newline at end of file
diff --git a/SharpNBT/Tags/TagType.cs b/SharpNBT/Tags/TagType.cs
index 285322b..0fdbc9e 100644
--- a/SharpNBT/Tags/TagType.cs
+++ b/SharpNBT/Tags/TagType.cs
@@ -12,6 +12,7 @@ public enum TagType : byte
///
/// Signifies the end of a .
///
+ /// Some implementation may also use as the child type for an empty list.
End = 0x00,
///