From c63514d9ad162240901445cf7ba508051f9ad95b Mon Sep 17 00:00:00 2001 From: Anna Date: Fri, 21 Jun 2024 11:27:36 -0400 Subject: [PATCH] feat: allow lists of replacement text --- Model/IWhen.cs | 2 +- Model/{WhenStatus.cs => QuestStatus.cs} | 0 Model/Replacement.cs | 4 +- Model/ReplacementText.cs | 66 +++++++++++++++++++++++++ Model/WhenLevel.cs | 13 ++--- Model/WhenQuest.cs | 2 +- Plugin.cs | 7 ++- 7 files changed, 83 insertions(+), 11 deletions(-) rename Model/{WhenStatus.cs => QuestStatus.cs} (100%) create mode 100644 Model/ReplacementText.cs diff --git a/Model/IWhen.cs b/Model/IWhen.cs index 9f851a8..71d3eb2 100644 --- a/Model/IWhen.cs +++ b/Model/IWhen.cs @@ -5,7 +5,7 @@ using YamlDotNet.Serialization; namespace TimePasses.Model; public interface IWhen { - string Text { get; } + ReplacementText Text { get; } bool Slowly { get; } bool IsValid(Plugin plugin); diff --git a/Model/WhenStatus.cs b/Model/QuestStatus.cs similarity index 100% rename from Model/WhenStatus.cs rename to Model/QuestStatus.cs diff --git a/Model/Replacement.cs b/Model/Replacement.cs index 3e8c615..16736f4 100644 --- a/Model/Replacement.cs +++ b/Model/Replacement.cs @@ -1,9 +1,11 @@ +using YamlDotNet.Serialization; + namespace TimePasses.Model; [Serializable] internal class Replacement { public uint Id { get; init; } - public string? Text { get; init; } + public ReplacementText? Text { get; init; } public bool Slowly { get; init; } public IWhen[] When { get; init; } = []; } diff --git a/Model/ReplacementText.cs b/Model/ReplacementText.cs new file mode 100644 index 0000000..fb9988e --- /dev/null +++ b/Model/ReplacementText.cs @@ -0,0 +1,66 @@ +using System.Collections; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace TimePasses.Model; + +[Serializable] +public class ReplacementText : IReadOnlyList { + private IReadOnlyList List { get; } + + internal ReplacementText(IReadOnlyList list) { + this.List = list; + } + + public string this[int index] => this.List[index]; + + public int Count => this.List.Count; + + public IEnumerator GetEnumerator() { + return this.List.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return this.List.GetEnumerator(); + } +} + +internal class ReplacementTextConverter : IYamlTypeConverter { + internal static readonly ReplacementTextConverter Instance = new(); + + public bool Accepts(Type type) { + return type == typeof(ReplacementText); + } + + public object? ReadYaml(IParser parser, Type type) { + var list = new List(); + if (parser.Current is Scalar) { + AddItem(); + } else if (parser.Current is SequenceStart) { + parser.Consume(); + while (parser.Current is not SequenceEnd) { + AddItem(); + } + + parser.Consume(); + } else { + throw new YamlException("expected string or list of strings"); + } + + return new ReplacementText(list); + + void AddItem() { + var scalar = parser.Consume(); + if (scalar.IsKey) { + throw new YamlException("invalid key found: expected string or list of strings"); + } + + list.Add(scalar.Value); + } + } + + public void WriteYaml(IEmitter emitter, object? value, Type type) { + throw new NotImplementedException(); + } +} diff --git a/Model/WhenLevel.cs b/Model/WhenLevel.cs index 8a656e7..1a04ffe 100644 --- a/Model/WhenLevel.cs +++ b/Model/WhenLevel.cs @@ -8,7 +8,7 @@ namespace TimePasses.Model; public class WhenLevel : IWhen { public uint Level { get; init; } public int CompareResult { get; init; } - public string Text { get; init; } + public ReplacementText Text { get; init; } public bool Slowly { get; init; } public bool IsValid(Plugin plugin) { @@ -34,7 +34,7 @@ public class WhenLevelConverter : IYamlTypeConverter { public object ReadYaml(IParser parser, Type type) { parser.Consume(); - string? text = null; + ReplacementText? text = null; int? comparerResult = null; uint? level = null; var slowly = false; @@ -44,6 +44,11 @@ public class WhenLevelConverter : IYamlTypeConverter { throw new YamlException("expected key"); } + if (key.Value == "text") { + text = (ReplacementText?) ReplacementTextConverter.Instance.ReadYaml(parser, type); + continue; + } + var value = parser.Consume(); switch (key.Value) { @@ -59,10 +64,6 @@ public class WhenLevelConverter : IYamlTypeConverter { ParseOperation(-1); break; } - case "text": { - text = value.Value; - break; - } case "slowly": { if (!bool.TryParse(value.Value, out slowly)) { throw new YamlException("invalid whenlevel: slowly was not a boolean"); diff --git a/Model/WhenQuest.cs b/Model/WhenQuest.cs index ad26b66..c8b7750 100644 --- a/Model/WhenQuest.cs +++ b/Model/WhenQuest.cs @@ -6,7 +6,7 @@ namespace TimePasses.Model; public class WhenQuest : IWhen { public uint Id { get; init; } public QuestStatus Status { get; init; } - public string Text { get; init; } + public ReplacementText Text { get; init; } public bool Slowly { get; init; } public unsafe bool IsValid(Plugin plugin) { diff --git a/Plugin.cs b/Plugin.cs index ee61917..4b5402d 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -33,6 +33,7 @@ public sealed class Plugin : IDalamudPlugin { private static IDeserializer Deserializer { get; } = new DeserializerBuilder() .WithNamingConvention(UnderscoredNamingConvention.Instance) .WithTypeConverter(new WhenLevelConverter()) + .WithTypeConverter(ReplacementTextConverter.Instance) .WithNodeDeserializer(new WhenNodeDeserialiser()) .IgnoreUnmatchedProperties() .Build(); @@ -111,11 +112,13 @@ public sealed class Plugin : IDalamudPlugin { var when = rep.When.FirstOrDefault(when => when.IsValid(this)); if (when != null) { - return this.GetOrCreateReplacementPointer(when.Text, when.Slowly); + var idx = Random.Shared.Next(when.Text.Count); + return this.GetOrCreateReplacementPointer(when.Text[idx], when.Slowly); } if (rep.Text != null) { - return this.GetOrCreateReplacementPointer(rep.Text, rep.Slowly); + var idx = Random.Shared.Next(rep.Text.Count); + return this.GetOrCreateReplacementPointer(rep.Text[idx], rep.Slowly); } return null;