Implemented BufferedTagWriter class
This commit is contained in:
parent
2e15b58792
commit
7e30b7f898
11
README.md
11
README.md
|
@ -6,8 +6,8 @@ A CLS-compliant implementation of the Named Binary Tag (NBT) specifications (Jav
|
||||||
|
|
||||||
## Features
|
## 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.
|
* **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 public member: Spend more time being productive and less time digging through documentation.
|
* **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.
|
* **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.
|
* **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:
|
* **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).
|
The project is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
||||||
|
|
||||||
|
|
||||||
## Code of Conduct
|
## 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).
|
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.
|
||||||
|
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a <see cref="TagWriter"/> object that writes to an internal buffer instead of a <see cref="Stream"/> 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.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public class BufferedTagWriter : TagWriter
|
||||||
|
{
|
||||||
|
private readonly MemoryStream buffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="BufferedTagWriter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="compression">Indicates the compression algorithm used to compress the file.</param>
|
||||||
|
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
||||||
|
/// <returns>A newly created <see cref="BufferedTagWriter"/> instance.</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when an invalid compression type is specified.</exception>
|
||||||
|
public static BufferedTagWriter Create(CompressionType compression, FormatOptions options)
|
||||||
|
{
|
||||||
|
// ReSharper disable once IntroduceOptionalParameters.Global
|
||||||
|
return Create(compression, options, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="BufferedTagWriter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="compression">Indicates the compression algorithm used to compress the file.</param>
|
||||||
|
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
||||||
|
/// <param name="capacity">The initial capacity of the buffer.</param>
|
||||||
|
/// <returns>A newly created <see cref="BufferedTagWriter"/> instance.</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when an invalid compression type is specified.</exception>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of bytes in the internal buffer.
|
||||||
|
/// </summary>
|
||||||
|
public long Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
BaseStream.Flush();
|
||||||
|
return buffer.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the capacity of the internal buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The capacity will expand automatically as-needed.</remarks>
|
||||||
|
public long Capacity => buffer.Capacity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the internal buffer as an array of bytes containing the NBT data written so far.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of bytes containing the NBT data.</returns>
|
||||||
|
[Pure]
|
||||||
|
public byte[] ToArray()
|
||||||
|
{
|
||||||
|
BaseStream.Flush();
|
||||||
|
return buffer.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the internal buffer to the specified <paramref name="stream"/>;
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">A <see cref="Stream"/> instance to write to.</param>
|
||||||
|
public void CopyTo([NotNull] Stream stream)
|
||||||
|
{
|
||||||
|
BaseStream.Flush();
|
||||||
|
buffer.CopyTo(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously copies the internal buffer to the specified <paramref name="stream"/>;
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">A <see cref="Stream"/> instance to write to.</param>
|
||||||
|
public async Task CopyToAsync([NotNull] Stream stream)
|
||||||
|
{
|
||||||
|
await BaseStream.FlushAsync();
|
||||||
|
await buffer.CopyToAsync(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator ReadOnlySpan<byte>(BufferedTagWriter writer)
|
||||||
|
{
|
||||||
|
writer.BaseStream.Flush();
|
||||||
|
return writer.buffer.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace SharpNBT
|
namespace SharpNBT
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides methods for reading NBT data from a stream.
|
/// Provides methods for reading NBT data from a stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -215,6 +215,12 @@ namespace SharpNBT
|
||||||
BaseStream.WriteByte((byte) TagType.End);
|
BaseStream.WriteByte((byte) TagType.End);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to build and write a <see cref="TagBuilder"/> instance to the underlying stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">A <see cref="TagBuilder"/> instance to write.</param>
|
||||||
|
public virtual void WriteBuilder([NotNull] TagBuilder builder) => WriteCompound(builder.Create());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in New Issue