namespace Nbt.Serialization; using System.Globalization; using Nbt.Tag; public static class SNbt { #region Serialize public enum SerializationStyle { Compact, Spaced, Indented } public class SerializerOptions { public static readonly SerializerOptions Default = new(); public SerializationStyle Style { get; init; } = SerializationStyle.Compact; public string Indent { get; init; } = " "; public bool AlwaysQuoteTagNames { get; init; } = false; // public bool AlwaysQuoteStringTags { get; init; } = false; } #region Sync public static string Serialize(INbtTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(NamedTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtList tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtCompound tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, NamedTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtList tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtCompound tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, NamedTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtList tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtCompound tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); private static void Serialize(TextWriter writer, SerializerOptions? options, Action serialize) { var serializer = new Serializer(writer, options); serialize(serializer); } private static void Serialize(Stream stream, SerializerOptions? options, Action serialize) { using var writer = new StreamWriter(stream, leaveOpen: true); Serialize(writer, options, serialize); } private static string Serialize(SerializerOptions? options, Action serialize) { using var writer = new StringWriter(); Serialize(writer, options, serialize); return writer.ToString(); } #endregion #region Async public static async ValueTask SerializeAsync(INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); private static async ValueTask SerializeAsync(TextWriter writer, SerializerOptions? options, CancellationToken ct, Func serialize) { var serializer = new Serializer(writer, options); await serialize(serializer, ct); } private static async ValueTask SerializeAsync(Stream stream, SerializerOptions? options, CancellationToken ct, Func serialize) { using var writer = new StreamWriter(stream, leaveOpen: true); await SerializeAsync(writer, options, ct, serialize); } private static async ValueTask SerializeAsync(SerializerOptions? options, CancellationToken ct, Func serialize) { using var writer = new StringWriter(); await SerializeAsync(writer, options, ct, serialize); return writer.ToString(); } #endregion private sealed class Serializer(TextWriter writer, SerializerOptions? options) { private readonly TextWriter writer = writer; private readonly SerializerOptions options = options ?? SerializerOptions.Default; private uint depth = 0u; private Context? context = null; #region Sync public void Serialize(INbtTag tag) { switch (tag) { case INbtArray arrayTag: Serialize(arrayTag); break; case INbtValue valueTag: Serialize(valueTag); break; case INbtList listTag: Serialize(listTag); break; case INbtCompound compoundTag: Serialize(compoundTag); break; } } public void Serialize(NamedTag namedTag) { if (!string.IsNullOrEmpty(namedTag.Name)) { writer.Write(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames)); writer.Write(':'); if (options.Style is not SerializationStyle.Compact) { writer.Write(' '); } } Serialize(namedTag.Tag); } public void Serialize(INbtList tag) { writer.Write('['); EnterContext(true); foreach (var entry in tag) { WriteSeparator(); Serialize(entry); context!.Length++; } ExitContext(); writer.Write(']'); } public void Serialize(INbtCompound tag) { writer.Write('{'); EnterContext(true); foreach (var entry in tag as IEnumerable) { WriteSeparator(); Serialize(entry); context!.Length++; } ExitContext(); writer.Write('}'); } public void Serialize(INbtArray tag) { switch (tag) { case INbtArray byteArrayTag: Serialize(byteArrayTag); break; case INbtArray intArrayTag: Serialize(intArrayTag); break; case INbtArray longArrayTag: Serialize(longArrayTag); break; } } public void Serialize(INbtValue valueTag) { switch (valueTag) { case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; } } public void Serialize(INbtArray tag) => Serialize(tag, 'B', Serialize); public void Serialize(INbtArray tag) => Serialize(tag, 'I', Serialize); public void Serialize(INbtArray tag) => Serialize(tag, 'L', Serialize); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); private void Serialize(INbtArray tag, char decorator, Action writeValue) where T : notnull { writer.Write('['); writer.Write(decorator); writer.Write(';'); EnterContext(false); if (tag.Value.Length > 0) { if (options.Style is not SerializationStyle.Compact) { writer.Write(' '); } foreach (var e in tag) { WriteSeparator(); writeValue(e); context!.Length++; } } ExitContext(); writer.Write(']'); } private void Serialize(sbyte value) { writer.Write(value.ToString(CultureInfo.InvariantCulture)); writer.Write('b'); } private void Serialize(short value) { writer.Write(value.ToString(CultureInfo.InvariantCulture)); writer.Write('s'); } private void Serialize(int value) { writer.Write(value.ToString(CultureInfo.InvariantCulture)); } private void Serialize(long value) { writer.Write(value.ToString(CultureInfo.InvariantCulture)); writer.Write('L'); } private void Serialize(float value) { writer.Write(value.ToString(CultureInfo.InvariantCulture)); if (float.IsFinite(value)) { writer.Write('F'); } } private void Serialize(double value) { writer.Write(value.ToString(CultureInfo.InvariantCulture)); if (double.IsFinite(value)) { writer.Write('D'); } } private void Serialize(string value) { // Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR); writer.Write(NbtUtils.QuoteString(value, onlyIfNeeded: false)); } private void EnterContext(bool newLine) { depth++; context = new(context, newLine); } private void ExitContext() { depth--; if (context!.NewLine && context!.Length > 0 && options.Style is SerializationStyle.Indented) { WriteNewLine(); } context = context!.Parent; } private void WriteSeparator() { if (context!.Length > 0) { writer.Write(','); if (options.Style is SerializationStyle.Spaced || !context.NewLine && options.Style is not SerializationStyle.Compact) { writer.Write(' '); } } if (context.NewLine && options.Style is SerializationStyle.Indented) { WriteNewLine(); } } private void WriteNewLine() { writer.WriteLine(); for (var i = 0; i < depth; i++) { writer.Write(options.Indent); } } #endregion #region Async public async ValueTask SerializeAsync(INbtTag tag, CancellationToken ct) { switch (tag) { case INbtArray arrayTag: await SerializeAsync(arrayTag, ct); break; case INbtValue valueTag: await SerializeAsync(valueTag, ct); break; case INbtList listTag: await SerializeAsync(listTag, ct); break; case INbtCompound compoundTag: await SerializeAsync(compoundTag, ct); break; } } public async ValueTask SerializeAsync(NamedTag namedTag, CancellationToken ct) { if (!string.IsNullOrEmpty(namedTag.Name)) { await WriteStringAsync(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames), ct); await WriteStringAsync(":", ct); if (options.Style is not SerializationStyle.Compact) { await WriteStringAsync(" ", ct); } } await SerializeAsync(namedTag.Tag, ct); } public async ValueTask SerializeAsync(INbtList tag, CancellationToken ct) { await WriteStringAsync("[", ct); await EnterContextAsync(true, ct); foreach (var entry in tag) { await WriteSeparatorAsync(ct); await SerializeAsync(entry, ct); context!.Length++; } await ExitContextAsync(ct); await WriteStringAsync("]", ct); } public async ValueTask SerializeAsync(INbtCompound tag, CancellationToken ct) { await WriteStringAsync("{", ct); await EnterContextAsync(true, ct); foreach (var entry in tag as IEnumerable) { await WriteSeparatorAsync(ct); await SerializeAsync(entry, ct); context!.Length++; } await ExitContextAsync(ct); await WriteStringAsync("}", ct); } public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) { switch (tag) { case INbtArray byteArrayTag: await SerializeAsync(byteArrayTag, ct); break; case INbtArray intArrayTag: await SerializeAsync(intArrayTag, ct); break; case INbtArray longArrayTag: await SerializeAsync(longArrayTag, ct); break; } } public async ValueTask SerializeAsync(INbtValue valueTag, CancellationToken ct) { switch (valueTag) { case INbtValue tag: await SerializeAsync(tag, ct); break; case INbtValue tag: await SerializeAsync(tag, ct); break; case INbtValue tag: await SerializeAsync(tag, ct); break; case INbtValue tag: await SerializeAsync(tag, ct); break; case INbtValue tag: await SerializeAsync(tag, ct); break; case INbtValue tag: await SerializeAsync(tag, ct); break; case INbtValue tag: await SerializeAsync(tag, ct); break; } } public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) => await SerializeAsync(tag, "B", ct, SerializeAsync); public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) => await SerializeAsync(tag, "I", ct, SerializeAsync); public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) => await SerializeAsync(tag, "L", ct, SerializeAsync); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); private async ValueTask SerializeAsync(INbtArray tag, string decorator, CancellationToken ct, Func writeValue) where T : notnull { await WriteStringAsync("[", ct); await WriteStringAsync(decorator, ct); await WriteStringAsync(";", ct); await EnterContextAsync(false, ct); if (tag.Value.Length > 0) { if (options.Style is not SerializationStyle.Compact) { await WriteStringAsync(" ", ct); } foreach (var e in tag) { await WriteSeparatorAsync(ct); await writeValue(e, ct); context!.Length++; } } await ExitContextAsync(ct); await WriteStringAsync("]", ct); } private async ValueTask SerializeAsync(sbyte value, CancellationToken ct) { await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); await WriteStringAsync("b", ct); } private async ValueTask SerializeAsync(short value, CancellationToken ct) { await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); await WriteStringAsync("s", ct); } private async ValueTask SerializeAsync(int value, CancellationToken ct) { await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); } private async ValueTask SerializeAsync(long value, CancellationToken ct) { await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); await WriteStringAsync("L", ct); } private async ValueTask SerializeAsync(float value, CancellationToken ct) { await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); if (float.IsFinite(value)) { await WriteStringAsync("F", ct); } } private async ValueTask SerializeAsync(double value, CancellationToken ct) { await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); if (double.IsFinite(value)) { await WriteStringAsync("D", ct); } } private async ValueTask SerializeAsync(string value, CancellationToken ct) { // Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR); await WriteStringAsync(NbtUtils.QuoteString(value, onlyIfNeeded: false), ct); } private async ValueTask WriteStringAsync(string s, CancellationToken ct) { await writer.WriteAsync(s.AsMemory(), ct); } private ValueTask EnterContextAsync(bool newLine, CancellationToken ct) { depth++; context = new(context, newLine); return ValueTask.CompletedTask; } private async ValueTask ExitContextAsync(CancellationToken ct) { depth--; if (context!.NewLine && context!.Length > 0 && options.Style is SerializationStyle.Indented) { await WriteNewLineAsync(ct); } context = context!.Parent; } private async ValueTask WriteSeparatorAsync(CancellationToken ct) { if (context!.Length > 0) { await WriteStringAsync(",", ct); if (options.Style is SerializationStyle.Spaced || !context.NewLine && options.Style is not SerializationStyle.Compact) { await WriteStringAsync(" ", ct); } } if (context.NewLine && options.Style is SerializationStyle.Indented) { await WriteNewLineAsync(ct); } } private async ValueTask WriteNewLineAsync(CancellationToken ct) { await WriteStringAsync(writer.NewLine, ct); for (var i = 0; i < depth; i++) { await WriteStringAsync(options.Indent, ct); } } #endregion private class Context(Context? parent, bool newLine) { public Context? Parent => parent; public bool NewLine => newLine; public int Length { get; set; } = 0; } } #endregion }