using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; namespace Questionable.Model.Questing; public static class QuestRootSerializer { public const string SchemaUrl = "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/QuestPaths/quest-v1.json"; public static JsonSerializerOptions CreateOptions() { return new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, WriteIndented = true, IncludeFields = false, TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { (Action)NoEmptyCollectionModifier, (Action)DialogueChoiceSerializationModifier, (Action)NonDefaultBoolModifier } } }; } public static QuestRoot Clone(QuestRoot source, JsonSerializerOptions options) { return JsonSerializer.Deserialize(JsonSerializer.Serialize(source, options), options); } public static byte[] SerializeToUtf8(QuestRoot questRoot, JsonSerializerOptions options) { JsonObject obj = (JsonObject)JsonSerializer.SerializeToNode(questRoot, options); JsonObject jsonObject = new JsonObject { { "$schema", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/QuestPaths/quest-v1.json" } }; foreach (var (propertyName, jsonNode2) in obj) { jsonObject.Add(propertyName, jsonNode2?.DeepClone()); } using MemoryStream memoryStream = new MemoryStream(); using (Utf8JsonWriter writer = new Utf8JsonWriter(memoryStream, new JsonWriterOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, Indented = true, IndentSize = 2, IndentCharacter = ' ', NewLine = "\n" })) { jsonObject.WriteTo(writer, options); } memoryStream.WriteByte(10); return memoryStream.ToArray(); } private static void NoEmptyCollectionModifier(JsonTypeInfo typeInfo) { foreach (JsonPropertyInfo property in typeInfo.Properties) { if (typeof(ICollection).IsAssignableFrom(property.PropertyType)) { property.ShouldSerialize = (object _, object? val) => val is ICollection collection && collection.Count > 0; } } } private static void DialogueChoiceSerializationModifier(JsonTypeInfo typeInfo) { if (typeInfo.Type != typeof(DialogueChoice)) { return; } JsonPropertyInfo jsonPropertyInfo = typeInfo.Properties.FirstOrDefault((JsonPropertyInfo x) => x.Name == "Yes"); if (jsonPropertyInfo != null) { jsonPropertyInfo.ShouldSerialize = (object obj, object? _) => obj is DialogueChoice dialogueChoice && dialogueChoice.Type == EDialogChoiceType.YesNo; } } private static void NonDefaultBoolModifier(JsonTypeInfo typeInfo) { if (typeInfo.Type != typeof(QuestRoot)) { return; } JsonPropertyInfo jsonPropertyInfo = typeInfo.Properties.FirstOrDefault((JsonPropertyInfo x) => x.Name == "Interruptible"); if (jsonPropertyInfo != null) { jsonPropertyInfo.ShouldSerialize = (object obj, object? _) => obj is QuestRoot questRoot && !questRoot.Interruptible; } } }