using System.Collections.Generic; using System.Text; using System.Text.Json; using Cthangover.Core.Scenes; using Cthangover.Core.Utils; namespace Cthangover.Tools.Services { /// /// One mod's file of a logical scene (scenes/<name>.json). The game merges /// the files of all mods into one (backgrounds add up, /// a later non-empty ambient or default scenario wins); the scene editor works on /// the files themselves, because only one of them — the chosen mod's — is written. /// public sealed class SceneFileEntry { /// Mod that owns the file. public string ModId { get; set; } /// Mod-relative path of the file. public string RelativePath { get; set; } /// Scene name (the logical scene id). public string Name { get; set; } /// Backgrounds this file adds; the game shows one of the merged list at random. public List Backgrounds { get; set; } = new(); /// Ambient sound id (group sounds), empty for none. public string Ambient { get; set; } = string.Empty; /// Mod-relative path of the scenario played when nothing else starts, empty for none. public string DefaultScenario { get; set; } = string.Empty; /// Default path of a scene file: scenes/<name>.json. public static string PathFor(string name) => "scenes/" + name + ".json"; /// Reads a scene file with the game's own JSON options; null when it is not a scene. public static SceneFileEntry Parse(string modId, string relativePath, string json) { SceneDefinition definition; try { definition = JsonSerializer.Deserialize(json ?? string.Empty, JsonOptionsProvider.ReadOptions); } catch (JsonException) { return null; } if (string.IsNullOrEmpty(definition?.Name)) return null; return new SceneFileEntry { ModId = modId, RelativePath = relativePath, Name = definition.Name, Backgrounds = definition.DefaultBackground ?? new List(), Ambient = definition.DefaultAmbient ?? string.Empty, DefaultScenario = definition.DefaultScenario ?? string.Empty, }; } /// /// The file text in the style of the hand-written scene files (two-space indent, LF, /// camelCase keys). Empty fields are left out, so a file of a mod that only adds a /// background does not reset another mod's ambient or default scenario. /// public string ToJson() { var json = new StringBuilder("{\n \"name\": ").Append(Quote(Name)); if (Backgrounds.Count > 0) { json.Append(",\n \"defaultBackground\": ["); for (var i = 0; i < Backgrounds.Count; i++) json.Append(i == 0 ? string.Empty : ", ").Append(Quote(Backgrounds[i])); json.Append(']'); } if (!string.IsNullOrEmpty(Ambient)) json.Append(",\n \"defaultAmbient\": ").Append(Quote(Ambient)); if (!string.IsNullOrEmpty(DefaultScenario)) json.Append(",\n \"defaultScenario\": ").Append(Quote(DefaultScenario)); return json.Append("\n}\n").ToString(); } private static string Quote(string value) => JsonSerializer.Serialize(value ?? string.Empty); } }