diff --git a/Content.Shared/Dataset/LocalizedDatasetPrototype.cs b/Content.Shared/Dataset/LocalizedDatasetPrototype.cs new file mode 100644 index 000000000000..8be9967e309d --- /dev/null +++ b/Content.Shared/Dataset/LocalizedDatasetPrototype.cs @@ -0,0 +1,94 @@ +using System.Collections; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Dataset; + +/// +/// A variant of intended to specify a sequence of LocId strings +/// without having to copy-paste a ton of LocId strings into the YAML. +/// +[Prototype] +public sealed partial class LocalizedDatasetPrototype : IPrototype +{ + /// + /// Identifier for this prototype. + /// + [ViewVariables] + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// Collection of LocId strings. + /// + [DataField] + public LocalizedDatasetValues Values { get; private set; } = []; +} + +[Serializable, NetSerializable] +[DataDefinition] +public sealed partial class LocalizedDatasetValues : IReadOnlyList +{ + /// + /// String prepended to the index number to generate each LocId string. + /// For example, a prefix of tips-dataset- will generate tips-dataset-1, + /// tips-dataset-2, etc. + /// + [DataField(required: true)] + public string Prefix { get; private set; } = default!; + + /// + /// How many values are in the dataset. + /// + [DataField(required: true)] + public int Count { get; private set; } + + public string this[int index] + { + get + { + if (index > Count || index < 0) + throw new IndexOutOfRangeException(); + return Prefix + index; + } + } + + public IEnumerator GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public sealed class Enumerator : IEnumerator + { + private int _index = 0; // Whee, 1-indexing + + private readonly LocalizedDatasetValues _values; + + public Enumerator(LocalizedDatasetValues values) + { + _values = values; + } + + public string Current => _values.Prefix + _index; + + object IEnumerator.Current => Current; + + public void Dispose() { } + + public bool MoveNext() + { + _index++; + return _index <= _values.Count; + } + + public void Reset() + { + _index = 0; + } + } +} diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs index 20e57e942128..f5fbc1bd24e8 100644 --- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs +++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs @@ -12,6 +12,11 @@ public static string Pick(this IRobustRandom random, DatasetPrototype prototype) return random.Pick(prototype.Values); } + public static string Pick(this IRobustRandom random, LocalizedDatasetPrototype prototype) + { + return random.Pick(prototype.Values); + } + public static string Pick(this IWeightedRandomPrototype prototype, System.Random random) { var picks = prototype.Weights; diff --git a/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs b/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs new file mode 100644 index 000000000000..0ec4c076f5b4 --- /dev/null +++ b/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs @@ -0,0 +1,59 @@ +using System; +using Content.Shared.Dataset; +using NUnit.Framework; +using Robust.Shared.Collections; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; + +namespace Content.Tests.Shared; + +[TestFixture] +[TestOf(typeof(LocalizedDatasetPrototype))] +public sealed class LocalizedDatasetPrototypeTest : ContentUnitTest +{ + private IPrototypeManager _prototypeManager; + + [OneTimeSetUp] + public void OneTimeSetup() + { + IoCManager.Resolve().Initialize(); + _prototypeManager = IoCManager.Resolve(); + _prototypeManager.Initialize(); + _prototypeManager.LoadString(TestPrototypes); + _prototypeManager.ResolveResults(); + } + + private const string TestPrototypes = @" +- type: localizedDataset + id: Test + values: + prefix: test-dataset- + count: 4 +"; + + [Test] + public void LocalizedDatasetTest() + { + var testPrototype = _prototypeManager.Index("Test"); + var values = new ValueList(); + foreach (var value in testPrototype.Values) + { + values.Add(value); + } + + // Make sure we get the right number of values + Assert.That(values, Has.Count.EqualTo(4)); + + // Make sure indexing works as expected + Assert.That(values[0], Is.EqualTo("test-dataset-1")); + Assert.That(values[1], Is.EqualTo("test-dataset-2")); + Assert.That(values[2], Is.EqualTo("test-dataset-3")); + Assert.That(values[3], Is.EqualTo("test-dataset-4")); + Assert.Throws(() => { var x = values[4]; }); + Assert.Throws(() => { var x = values[-1]; }); + + // Make sure that the enumerator gets all of the values + Assert.That(testPrototype.Values[testPrototype.Values.Count], Is.EqualTo("test-dataset-4")); + } +}