diff --git a/README.md b/README.md
index b83eee6..9e502a5 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,8 @@ A CLS-compliant implementation of the Named Binary Tag (NBT) specifications (Jav
## Features
-* **Java/Bedrock Support:** Supports all NBT protocols used by different versions of Minecraft, including: Java, Bedrock (file protocol), and Bedrock (network protocol), including full support for either GZip or ZLib compression.
-* **Ease-of-use:** An intuitive API design, following the style and conventions of the .NET runtime, with full Intellisense for every public member: Spend more time being productive and less time digging through documentation.
+* **Java/Bedrock Support:** Supports all NBT protocols used by different versions of Minecraft, including: Java, Bedrock (file protocol), and Bedrock (network protocol), including full support for either GZip/ZLib compression, big/little endian, and variable length integers with optional ZigZag encoding.
+* **Ease-of-use:** An intuitive API design, following the style and conventions of the .NET runtime, with full Intellisense for every member: Spend more time being productive and less time digging through documentation.
* **Performance:** Leverages the power of modern C# language features, including `Span` with `stackalloc`, `MemoryMarshal`, etc. This allows for a type-safe way to reinterpret raw buffers without pointers or making unnecessary copies of buffers, a common pitfall with serialization in type-safe languages.
* **Concurrency:** Includes standard async/await concurrency patterns for reading and writing.
* **Cross-platform and cross-language support:** Fully CLR compliant and build against .NET Standard 2.1, allowing support for any CLR language (i.e. C#, Visual Basic, F#, etc.) for the following runtime versions or greater:
@@ -114,7 +114,10 @@ Pull requests are always welcome.
The project is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
-
## Code of Conduct
-Everyone interacting in the SharpNBT project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ForeverZer0/SharpNBT/blob/master/CODE_OF_CONDUCT.md).
\ No newline at end of file
+Everyone interacting in the SharpNBT project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ForeverZer0/SharpNBT/blob/master/CODE_OF_CONDUCT.md).
+
+## Special Thanks
+
+This project would not be possible without all the contributors to the https://wiki.vg/ and its maintainers, who have created an invaluable source of information for developers for everything related to the game of Minecraft.
diff --git a/SharpNBT/BufferedTagWriter.cs b/SharpNBT/BufferedTagWriter.cs
new file mode 100644
index 0000000..5f24104
--- /dev/null
+++ b/SharpNBT/BufferedTagWriter.cs
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+using System.IO.Compression;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using SharpNBT.ZLib;
+
+namespace SharpNBT
+{
+ ///
+ /// Provides a object that writes to an internal buffer instead of a object, which then can be retrieved as
+ /// an array of bytes or written directly to a stream. This is especially convenient when creating packets to be sent over a network, where the size of
+ /// the packet must be pre-determined before sending.
+ ///
+ [PublicAPI]
+ public class BufferedTagWriter : TagWriter
+ {
+ private readonly MemoryStream buffer;
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ /// Indicates the compression algorithm used to compress the file.
+ /// Bitwise flags to configure how data should be handled for compatibility between different specifications.
+ /// A newly created instance.
+ /// Thrown when an invalid compression type is specified.
+ public static BufferedTagWriter Create(CompressionType compression, FormatOptions options)
+ {
+ // ReSharper disable once IntroduceOptionalParameters.Global
+ return Create(compression, options, 4096);
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ /// Indicates the compression algorithm used to compress the file.
+ /// Bitwise flags to configure how data should be handled for compatibility between different specifications.
+ /// The initial capacity of the buffer.
+ /// A newly created instance.
+ /// Thrown when an invalid compression type is specified.
+ public static BufferedTagWriter Create(CompressionType compression, FormatOptions options, int capacity)
+ {
+ var buffer = new MemoryStream(capacity);
+ Stream stream = compression switch
+ {
+ CompressionType.None => buffer,
+ CompressionType.GZip => new GZipStream(buffer, CompressionMode.Compress, false),
+ CompressionType.ZLib => new ZLibStream(buffer, CompressionMode.Compress),
+ _ => throw new ArgumentOutOfRangeException(nameof(compression), compression, null)
+ };
+
+ return new BufferedTagWriter(stream, buffer, options);
+ }
+
+ private BufferedTagWriter([NotNull] Stream stream, MemoryStream buffer, FormatOptions options) : base(stream, options, false)
+ {
+ this.buffer = buffer;
+ }
+
+ ///
+ /// Gets the number of bytes in the internal buffer.
+ ///
+ public long Length
+ {
+ get
+ {
+ BaseStream.Flush();
+ return buffer.Length;
+ }
+ }
+
+ ///
+ /// Gets the capacity of the internal buffer.
+ ///
+ /// The capacity will expand automatically as-needed.
+ public long Capacity => buffer.Capacity;
+
+ ///
+ /// Gets the internal buffer as an array of bytes containing the NBT data written so far.
+ ///
+ /// An array of bytes containing the NBT data.
+ [Pure]
+ public byte[] ToArray()
+ {
+ BaseStream.Flush();
+ return buffer.ToArray();
+ }
+
+ ///
+ /// Copies the internal buffer to the specified ;
+ ///
+ /// A instance to write to.
+ public void CopyTo([NotNull] Stream stream)
+ {
+ BaseStream.Flush();
+ buffer.CopyTo(stream);
+ }
+
+ ///
+ /// Asynchronously copies the internal buffer to the specified ;
+ ///
+ /// A instance to write to.
+ public async Task CopyToAsync([NotNull] Stream stream)
+ {
+ await BaseStream.FlushAsync();
+ await buffer.CopyToAsync(stream);
+ }
+
+ public static implicit operator ReadOnlySpan(BufferedTagWriter writer)
+ {
+ writer.BaseStream.Flush();
+ return writer.buffer.ToArray();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SharpNBT/TagReader.cs b/SharpNBT/TagReader.cs
index 3c54912..016d44e 100644
--- a/SharpNBT/TagReader.cs
+++ b/SharpNBT/TagReader.cs
@@ -7,7 +7,6 @@ using JetBrains.Annotations;
namespace SharpNBT
{
-
///
/// Provides methods for reading NBT data from a stream.
///
diff --git a/SharpNBT/TagWriter.cs b/SharpNBT/TagWriter.cs
index 9568af6..36c2b63 100644
--- a/SharpNBT/TagWriter.cs
+++ b/SharpNBT/TagWriter.cs
@@ -215,6 +215,12 @@ namespace SharpNBT
BaseStream.WriteByte((byte) TagType.End);
}
+ ///
+ /// Convenience method to build and write a instance to the underlying stream.
+ ///
+ /// A instance to write.
+ public virtual void WriteBuilder([NotNull] TagBuilder builder) => WriteCompound(builder.Create());
+
///
///
///