From 6ac28f5bd3f87ce7f7370f3afc6e6759df974298 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Sun, 15 Dec 2024 13:11:27 -0500 Subject: [PATCH 1/3] Add fairy pond trade to PlandoConfig --- .../Options/PlandoConfig.cs | 21 +++++++++++++-- .../FileData/Patches/FairyPondTradePatch.cs | 26 ++++++++++++------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs b/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs index 07f830fc9..54a8988dc 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using TrackerCouncil.Smz3.Shared; using TrackerCouncil.Smz3.Data.Logic; @@ -43,13 +44,19 @@ public PlandoConfig(World world) .ToDictionary(x => x.ToString(), x => ((IHasPrerequisite)x).RequiredItem); Logic = world.Config.LogicConfig.Clone(); StartingInventory = world.Config.ItemOptions; - var prizes = DropPrizes.GetPool(world.Config.CasPatches.ZeldaDrops); + var prizes = DropPrizes.GetPool(world.Config.CasPatches.ZeldaDrops).ToList(); ZeldaPrizes.EnemyDrops = prizes.Take(56).ToList(); ZeldaPrizes.TreePulls = prizes.Skip(56).Take(3).ToList(); ZeldaPrizes.CrabBaseDrop = prizes.Skip(59).First(); ZeldaPrizes.CrabEightDrop = prizes.Skip(60).First(); ZeldaPrizes.StunPrize = prizes.Skip(61).First(); ZeldaPrizes.FishPrize = prizes.Skip(62).First(); + + var bottleItems = Enum.GetValues().Where(x => x.IsInCategory(ItemCategory.Bottle)) + .Shuffle(new Random().Sanitize()).Take(2) + .ToList(); + WaterfallFairyTrade = bottleItems.First(); + PyramidFairyTrade = bottleItems.Last(); } /// @@ -119,6 +126,16 @@ public PlandoConfig(World world) /// public PlandoZeldaPrizeConfig ZeldaPrizes { get; set; } = new(); + /// + /// Bottle trade offer with the waterfall fairy + /// + public ItemType? WaterfallFairyTrade { get; set; } + + /// + /// Bottle trade offer with the pyramid fairy + /// + public ItemType? PyramidFairyTrade { get; set; } + /// /// Item Options for the starting inventory /// diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/FileData/Patches/FairyPondTradePatch.cs b/src/TrackerCouncil.Smz3.SeedGenerator/FileData/Patches/FairyPondTradePatch.cs index 380c7a54b..28a4ad7ca 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/FileData/Patches/FairyPondTradePatch.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/FileData/Patches/FairyPondTradePatch.cs @@ -1,23 +1,29 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using TrackerCouncil.Smz3.Shared; +using TrackerCouncil.Smz3.Shared.Enums; namespace TrackerCouncil.Smz3.SeedGenerator.FileData.Patches; [Order(-6)] public class FairyPondTradePatch : RomPatch { - - private static readonly List s_fairyPondTrades = new() - { - 0x16, 0x2B, 0x2C, 0x2D, 0x3C, 0x3D, 0x48 - }; - public override IEnumerable GetChanges(GetPatchesRequest data) { if (!data.World.Config.CasPatches.RandomizedBottles) yield break; - yield return new GeneratedPatch(Snes(0x6C8FF), new[] { s_fairyPondTrades.Random(data.Random) }); - yield return new GeneratedPatch(Snes(0x6C93B), new[] { s_fairyPondTrades.Random(data.Random) }); - } + var tradeOptions = Enum.GetValues().Where(x => x.IsInCategory(ItemCategory.Bottle)).ToList(); + var waterfallTrade = data.PlandoConfig.WaterfallFairyTrade?.IsInCategory(ItemCategory.Bottle) == true + ? data.PlandoConfig.WaterfallFairyTrade + : tradeOptions.Random(data.Random); + + var pyramidTrade = data.PlandoConfig.PyramidFairyTrade?.IsInCategory(ItemCategory.Bottle) == true + ? data.PlandoConfig.PyramidFairyTrade + : tradeOptions.Random(data.Random); + + yield return new GeneratedPatch(Snes(0x6C8FF), [(byte)(waterfallTrade ?? ItemType.Bottle)]); // Waterfall Fairy + yield return new GeneratedPatch(Snes(0x6C93B), [(byte)(pyramidTrade ?? ItemType.Bottle)]); // Pyramid Fairy + } } From 8711b0d1c2e52242b556efd18619d14eb4a1a7cc Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Sun, 15 Dec 2024 13:12:17 -0500 Subject: [PATCH 2/3] Standardize directories into unified file --- .../Configuration/ConfigProvider.cs | 28 +------- .../Options/Sprite.cs | 37 +--------- .../RandomizerDirectories.cs | 69 +++++++++++++++++++ .../PatchBuilderService.cs | 19 +---- .../FileData/IpsPatches/IpsPatch.cs | 18 +---- 5 files changed, 75 insertions(+), 96 deletions(-) create mode 100644 src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs diff --git a/src/TrackerCouncil.Smz3.Data/Configuration/ConfigProvider.cs b/src/TrackerCouncil.Smz3.Data/Configuration/ConfigProvider.cs index 582c53f7d..51b571879 100644 --- a/src/TrackerCouncil.Smz3.Data/Configuration/ConfigProvider.cs +++ b/src/TrackerCouncil.Smz3.Data/Configuration/ConfigProvider.cs @@ -38,18 +38,7 @@ public partial class ConfigProvider /// public ConfigProvider(ILogger? logger) { -#if DEBUG - var parentDir = new DirectoryInfo(SolutionPath).Parent; - var configRepo = parentDir?.GetDirectories().FirstOrDefault(x => x.Name == "SMZ3CasConfigs"); - _basePath = Path.Combine(configRepo?.FullName ?? "", "Profiles"); - - if (!Directory.Exists(_basePath)) - { - _basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "Configs"); - } -#else - _basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "Configs"); -#endif + _basePath = RandomizerDirectories.ConfigPath; _logger = logger; } @@ -432,21 +421,6 @@ private static T GetBuiltInConfig(string fileName) ?? throw new InvalidOperationException("The embedded tracker configuration could not be loaded."); } - private static string SolutionPath - { - get - { - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - - while (directory != null && !directory.GetFiles("*.sln").Any()) - { - directory = directory.Parent; - } - - return Path.Combine(directory!.FullName); - } - } - [GeneratedRegex("[^\\.]+\\.(?.+)\\.yml")] private static partial Regex ProfileFileNameWithMoodRegex(); } diff --git a/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs b/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs index 29a8388e5..0ad7b4d38 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs @@ -117,40 +117,5 @@ public override string ToString() return string.IsNullOrEmpty(Author) ? Name : $"{Name} by {Author}"; } - public static string SpritePath - { - get - { -#if DEBUG - var parentDir = new DirectoryInfo(SolutionPath).Parent; - var spriteRepo = parentDir?.GetDirectories().FirstOrDefault(x => x.Name == "SMZ3CasSprites"); - var path = Path.Combine(spriteRepo?.FullName ?? "", "Sprites"); - - if (!Directory.Exists(path) || path == "Sprites") - { - return Path.Combine(AppContext.BaseDirectory, "Sprites"); - } - - return path; -#else - return Path.Combine(AppContext.BaseDirectory, "Sprites"); -#endif - } - - } - - private static string SolutionPath - { - get - { - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - - while (directory != null && !directory.GetFiles("*.sln").Any()) - { - directory = directory.Parent; - } - - return Path.Combine(directory!.FullName); - } - } + public static string SpritePath => RandomizerDirectories.SpritePath; } diff --git a/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs b/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs new file mode 100644 index 000000000..625ccd3dc --- /dev/null +++ b/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs @@ -0,0 +1,69 @@ +using System; +using System.IO; +using System.Linq; + +namespace TrackerCouncil.Smz3.Data; + +public class RandomizerDirectories +{ + public static string SolutionPath + { + get + { +#if DEBUG + var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); + + while (directory != null && !directory.GetFiles("*.sln").Any()) + { + directory = directory.Parent; + } + + return Path.Combine(directory!.FullName); +#else + throw new InvalidOperationException("This method should only be called in debug mode."); +#endif + } + } + + public static string ConfigPath + { + get + { +#if DEBUG + var parentDir = new DirectoryInfo(SolutionPath).Parent; + var configRepo = parentDir?.GetDirectories().FirstOrDefault(x => x.Name == "SMZ3CasConfigs"); + var basePath = Path.Combine(configRepo?.FullName ?? "", "Profiles"); + + if (!Directory.Exists(basePath)) + { + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "Configs"); + } + + return basePath; +#else + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "Configs"); +#endif + } + } + + public static string SpritePath + { + get + { +#if DEBUG + var parentDir = new DirectoryInfo(SolutionPath).Parent; + var spriteRepo = parentDir?.GetDirectories().FirstOrDefault(x => x.Name == "SMZ3CasSprites"); + var path = Path.Combine(spriteRepo?.FullName ?? "", "Sprites"); + + if (!Directory.Exists(path) || path == "Sprites") + { + return Path.Combine(AppContext.BaseDirectory, "Sprites"); + } + + return path; +#else + return Path.Combine(AppContext.BaseDirectory, "Sprites"); +#endif + } + } +} diff --git a/src/TrackerCouncil.Smz3.PatchBuilder/PatchBuilderService.cs b/src/TrackerCouncil.Smz3.PatchBuilder/PatchBuilderService.cs index addc5a552..23f7c353c 100644 --- a/src/TrackerCouncil.Smz3.PatchBuilder/PatchBuilderService.cs +++ b/src/TrackerCouncil.Smz3.PatchBuilder/PatchBuilderService.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using MSURandomizerLibrary.Models; using MSURandomizerLibrary.Services; +using TrackerCouncil.Smz3.Data; using TrackerCouncil.Smz3.Data.Interfaces; using TrackerCouncil.Smz3.Data.Options; using TrackerCouncil.Smz3.SeedGenerator.Infrastructure; @@ -24,7 +25,7 @@ public PatchBuilderService(ILogger logger, IRomGenerationSe { _logger = logger; _romGenerationService = romGenerationService; - _solutionPath = SolutionPath; + _solutionPath = RandomizerDirectories.SolutionPath; _randomizerRomPath = Path.Combine(_solutionPath, "alttp_sm_combo_randomizer_rom"); _optionsFactory = optionsFactory; _msuLookupService = msuLookupService; @@ -226,20 +227,4 @@ private void Launch(PatchBuilderConfig config) _romLauncherService.LaunchRom(romPath, config.EnvironmentSettings.LaunchApplication, config.EnvironmentSettings.LaunchArguments); } - - private static string SolutionPath - { - get - { - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - - while (directory != null && !directory.GetFiles("*.sln").Any()) - { - directory = directory.Parent; - } - - return Path.Combine(directory!.FullName); - } - } - } diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/FileData/IpsPatches/IpsPatch.cs b/src/TrackerCouncil.Smz3.SeedGenerator/FileData/IpsPatches/IpsPatch.cs index e88e1a6d3..04ff928b2 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/FileData/IpsPatches/IpsPatch.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/FileData/IpsPatches/IpsPatch.cs @@ -1,5 +1,6 @@ using System.IO; using System.Linq; +using TrackerCouncil.Smz3.Data; namespace TrackerCouncil.Smz3.SeedGenerator.FileData.IpsPatches; @@ -8,7 +9,7 @@ public static class IpsPatch public static Stream GetStream(string name) { #if DEBUG - var path = Path.Combine(SolutionPath, "src", "TrackerCouncil.Smz3.SeedGenerator", "FileData", "IpsPatches", name); + var path = Path.Combine(RandomizerDirectories.SolutionPath, "src", "TrackerCouncil.Smz3.SeedGenerator", "FileData", "IpsPatches", name); return File.OpenRead(path); #else var type = typeof(IpsPatch); @@ -16,21 +17,6 @@ public static Stream GetStream(string name) #endif } - private static string SolutionPath - { - get - { - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - - while (directory != null && !directory.GetFiles("*.sln").Any()) - { - directory = directory.Parent; - } - - return Path.Combine(directory!.FullName); - } - } - /// /// Gets a stream for the IPS patch that enables custom ship sprite support. /// From 33074e260db246512e4a8623351b6863e6188eab Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Sun, 15 Dec 2024 16:11:43 -0500 Subject: [PATCH 3/3] Add plando schema file generation --- .../Program.cs | 51 +++++++++++++------ ...erCouncil.Smz3.Data.SchemaGenerator.csproj | 1 + .../Logic/LogicConfig.cs | 4 +- .../Options/PlandoConfig.cs | 12 ++++- .../Options/PlandoTextConfig.cs | 2 +- .../Generation/RomTextService.cs | 30 ++++++++++- 6 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Data.SchemaGenerator/Program.cs b/src/TrackerCouncil.Smz3.Data.SchemaGenerator/Program.cs index 4df42bd71..af61394f1 100644 --- a/src/TrackerCouncil.Smz3.Data.SchemaGenerator/Program.cs +++ b/src/TrackerCouncil.Smz3.Data.SchemaGenerator/Program.cs @@ -1,7 +1,10 @@ using System.ComponentModel; using System.Reflection; +using System.Text; using System.Text.RegularExpressions; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Schema; +using Newtonsoft.Json.Schema.Generation; using NJsonSchema.Generation; using NJsonSchema.NewtonsoftJson.Generation; using Serilog; @@ -9,7 +12,9 @@ using TrackerCouncil.Smz3.Data.Configuration; using TrackerCouncil.Smz3.Data.Configuration.ConfigFiles; using TrackerCouncil.Smz3.Data.Configuration.ConfigTypes; +using TrackerCouncil.Smz3.Data.Options; using YamlDotNet.Serialization; +using JsonSchemaGenerator = NJsonSchema.Generation.JsonSchemaGenerator; namespace TrackerCouncil.Smz3.Data.SchemaGenerator; @@ -60,6 +65,34 @@ public static void Main(string[] args) CreateSchemas(outputPath); CreateTemplates(outputPath); + CreatePlandoSchema(outputPath); + } + + private static void CreatePlandoSchema(string outputPath) + { + var plandoConfig = new PlandoConfig(); + var serializer = new SerializerBuilder() + .DisableAliases() + .Build(); + var newHashCode = serializer.Serialize(plandoConfig).GetHashCode(); + if (newHashCode == PlandoConfig.SHashCode) + { + Log.Information("PlandoConfig default object matches SHashCode value of {Code}", newHashCode); + return; + } + + Log.Information( + "New PlandoConfig HashCode {NewHashCode} does not match prior PlandoConfig.SHashCode value of {OldHashCode}", + newHashCode, PlandoConfig.SHashCode); + + var schemaPath = Path.Combine(outputPath, "Schemas"); + var generator = new JSchemaGenerator(); + generator.GenerationProviders.Add(new StringEnumGenerationProvider()); + var schema = generator.Generate(typeof(PlandoConfig), false); + var path = Path.Combine(schemaPath, "plando.json"); + File.WriteAllText(path, schema.ToString()); + + Log.Information("Wrote {Type} schema to {Path}. Update PlandoConfig SHashCode value to {Hash}", typeof(PlandoConfig).FullName, path, newHashCode); } private static void CreateSchemas(string outputPath) @@ -81,6 +114,7 @@ private static void CreateSchemas(string outputPath) { var path = Path.Combine(schemaPath, type.Item2); var schema = generator.Generate(type.Item1); + var text = schrodingersStringReplacement.Replace(schema.ToJson(), "").Replace("\\n", " "); for (var i = 0; i < 5; i++) @@ -255,7 +289,7 @@ private static SchrodingersString GetPopulatedSchrodingersString(string name, bo private static string GetOutputPath() { - var slnDirectory = new DirectoryInfo(SolutionPath); + var slnDirectory = new DirectoryInfo(RandomizerDirectories.SolutionPath); if (slnDirectory.Parent?.GetDirectories().Any(x => x.Name == "SMZ3CasConfigs") == true) { return slnDirectory.Parent.GetDirectories().First(x => x.Name == "SMZ3CasConfigs").FullName; @@ -265,19 +299,4 @@ private static string GetOutputPath() return Path.Combine(slnDirectory.FullName, "src", "SchemaGenerator", "Output"); } } - - private static string SolutionPath - { - get - { - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - - while (directory != null && !directory.GetFiles("*.sln").Any()) - { - directory = directory.Parent; - } - - return Path.Combine(directory!.FullName); - } - } } diff --git a/src/TrackerCouncil.Smz3.Data.SchemaGenerator/TrackerCouncil.Smz3.Data.SchemaGenerator.csproj b/src/TrackerCouncil.Smz3.Data.SchemaGenerator/TrackerCouncil.Smz3.Data.SchemaGenerator.csproj index dbb8dd251..b2e22688d 100644 --- a/src/TrackerCouncil.Smz3.Data.SchemaGenerator/TrackerCouncil.Smz3.Data.SchemaGenerator.csproj +++ b/src/TrackerCouncil.Smz3.Data.SchemaGenerator/TrackerCouncil.Smz3.Data.SchemaGenerator.csproj @@ -8,6 +8,7 @@ + diff --git a/src/TrackerCouncil.Smz3.Data/Logic/LogicConfig.cs b/src/TrackerCouncil.Smz3.Data/Logic/LogicConfig.cs index 48abafe53..ae068d69e 100644 --- a/src/TrackerCouncil.Smz3.Data/Logic/LogicConfig.cs +++ b/src/TrackerCouncil.Smz3.Data/Logic/LogicConfig.cs @@ -42,7 +42,7 @@ public LogicConfig(bool enableAllCasOptions, bool enableAllTricks, WallJumpDiffi WallJumpDifficulty = wallJumpDifficulty; } - [YamlIgnore] + [YamlIgnore, Newtonsoft.Json.JsonIgnore] [DynamicFormFieldText(groupName: "CasTop")] public string CasLogicDescription => "Logic settings that will make the experience more relaxed and easier to play."; @@ -76,7 +76,7 @@ public LogicConfig(bool enableAllCasOptions, bool enableAllTricks, WallJumpDiffi [DynamicFormFieldCheckBox(checkBoxText: "Include Quarter Magic", toolTipText: "Adds an additional progressive half magic to the item pool.", groupName: "CasMiddle")] public bool QuarterMagic { get; set; } - [YamlIgnore] + [YamlIgnore, Newtonsoft.Json.JsonIgnore] [DynamicFormFieldText(groupName: "TricksTop")] public string TricksDescription => "Logic settings that will make the game more difficult by requiring you to do techniques or maneuvers not typically required in the vanilla games."; diff --git a/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs b/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs index 54a8988dc..7ee4a0f29 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs @@ -6,6 +6,7 @@ using TrackerCouncil.Smz3.Data.WorldData; using TrackerCouncil.Smz3.Data.WorldData.Regions; using TrackerCouncil.Smz3.Shared.Enums; +using YamlDotNet.Core; using YamlDotNet.Serialization; namespace TrackerCouncil.Smz3.Data.Options; @@ -15,6 +16,12 @@ namespace TrackerCouncil.Smz3.Data.Options; /// public class PlandoConfig // TODO: Consider using this instead of SeedData? { + /// + /// Number that represents the hash code the serialized string this class. Used to prevent unnecessary generation + /// of the schema file to prevent going over usage limits. + /// + public static int SHashCode = 0; + /// /// Initializes a new empty instance of the /// class. @@ -38,7 +45,7 @@ public PlandoConfig(World world) TourianBossCount = world.Config.TourianBossCount; Items = world.Locations .ToDictionary(x => x.ToString(), x => x.Item.Type); - Rewards = world.Regions.Where(x => x is IHasReward) + Rewards = world.Regions.Where(x => x is IHasReward r && !r.RewardType.IsInCategory(RewardCategory.NonRandomized) && r.RewardType.IsInCategory(RewardCategory.Zelda)) .ToDictionary(x => x.ToString(), x => ((IHasReward)x).RewardType); Medallions = world.Regions.Where(x => x is IHasPrerequisite) .ToDictionary(x => x.ToString(), x => ((IHasPrerequisite)x).RequiredItem); @@ -63,9 +70,10 @@ public PlandoConfig(World world) /// Gets or sets the name of the file from which the plando config was /// deserialized. /// - [YamlIgnore] + [YamlIgnore, Newtonsoft.Json.JsonIgnore] public string FileName { get; set; } = ""; + [YamlMember(ScalarStyle = ScalarStyle.DoubleQuoted)] public string Seed { get; set; } = ""; /// diff --git a/src/TrackerCouncil.Smz3.Data/Options/PlandoTextConfig.cs b/src/TrackerCouncil.Smz3.Data/Options/PlandoTextConfig.cs index df4a592d8..128850a4f 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/PlandoTextConfig.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/PlandoTextConfig.cs @@ -85,7 +85,7 @@ public class PlandoTextConfig public string? HintTileSouthEastDarkworldCave { get; init; } - [YamlIgnore] + [YamlIgnore, Newtonsoft.Json.JsonIgnore] public bool HasHintTileText => !string.IsNullOrEmpty(HintTileEasternPalace) || !string.IsNullOrEmpty(HintTileTowerOfHeraFloor4) || !string.IsNullOrEmpty(HintTileSpectacleRock) || diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/RomTextService.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/RomTextService.cs index b57622e1a..ba7bfc834 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/RomTextService.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/RomTextService.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using SnesConnectorLibrary; +using TrackerCouncil.Smz3.Data; using TrackerCouncil.Smz3.Data.GeneratedData; using TrackerCouncil.Smz3.Data.Options; using TrackerCouncil.Smz3.Data.WorldData.Regions; @@ -16,6 +17,8 @@ namespace TrackerCouncil.Smz3.SeedGenerator.Generation; public class RomTextService(ILogger logger, IGameHintService gameHintService, ISnesConnectorService snesConnectorService) { + private static readonly string s_plandoSchemaPath = @"https://raw.githubusercontent.com/TheTrackerCouncil/SMZ3CasConfigs/refs/heads/main/Schemas/plando.json"; + public async Task WriteSpoilerLog(RandomizerOptions options, SeedData seed, Config config, string folderPath, string fileSuffix, bool isParsedRom = false) { var spoilerLog = GetSpoilerLog(options, seed, config.Race || config.DisableSpoilerLog, isParsedRom); @@ -78,7 +81,14 @@ public void PrepareAutoTrackerFiles(RandomizerOptions options) var plandoConfig = new PlandoConfig(world); var serializer = new YamlDotNet.Serialization.Serializer(); - return serializer.Serialize(plandoConfig); + + StringBuilder output = new(); + output.AppendLine($"# yaml-language-server: $schema={GetPlandoSchemaPath()}"); + output.AppendLine(); + output.AppendLine("# Visual Studio Code with the redhat YAML extension is recommended for schema validation."); + output.AppendLine(); + output.AppendLine(serializer.Serialize(plandoConfig)); + return output.ToString(); } catch (Exception ex) { @@ -87,6 +97,24 @@ public void PrepareAutoTrackerFiles(RandomizerOptions options) } } + private static string GetPlandoSchemaPath() + { +#if DEBUG + var parentDir = new DirectoryInfo(RandomizerDirectories.SolutionPath).Parent; + var localPlandoSchemaPath = Path.Combine(parentDir?.FullName ?? RandomizerDirectories.SolutionPath, "SMZ3CasConfigs", "Schemas", "plando.json"); + if (File.Exists(localPlandoSchemaPath)) + { + return localPlandoSchemaPath; + } + else + { + return s_plandoSchemaPath; + } +#else + return s_plandoSchemaPath; +#endif + } + /// /// Underlines text in the spoiler log ///