From d97021d3a0f04a14ac3c1881c18d33de5a1649fa Mon Sep 17 00:00:00 2001 From: Ygg01 Date: Sun, 23 May 2021 06:05:55 +0200 Subject: [PATCH] Fix layers displaying in cable stacks (#4028) * Fix layers displaying in cable stacks Fixed stackVisualizer to use another round method * Fix ShadowCommander review * Change to expected Result --- .../GameObjects/Components/StackVisualizer.cs | 13 ++--- Content.Shared/Utility/ContentHelpers.cs | 39 +++++++++++++- .../Shared/Utility/ContentHelpers_Test.cs | 53 ++++++++++++++++++- 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/Content.Client/GameObjects/Components/StackVisualizer.cs b/Content.Client/GameObjects/Components/StackVisualizer.cs index bc666fe1ef..b3d3b488cc 100644 --- a/Content.Client/GameObjects/Components/StackVisualizer.cs +++ b/Content.Client/GameObjects/Components/StackVisualizer.cs @@ -8,7 +8,6 @@ using Robust.Client.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; namespace Content.Client.GameObjects.Components { @@ -60,8 +59,7 @@ namespace Content.Client.GameObjects.Components /// Sprite layers used in stack visualizer. Sprites first in layer correspond to lower stack states /// e.g. _spriteLayers[0] is lower stack level than _spriteLayers[1]. /// - [DataField("stackLayers")] - private readonly List _spriteLayers = new(); + [DataField("stackLayers")] private readonly List _spriteLayers = new(); /// /// Determines if the visualizer uses composite or non-composite layers for icons. Defaults to false. @@ -76,10 +74,9 @@ namespace Content.Client.GameObjects.Components /// /// /// - [DataField("composite")] - private bool _isComposite; - [DataField("sprite")] - private ResourcePath? _spritePath; + [DataField("composite")] private bool _isComposite; + + [DataField("sprite")] private ResourcePath? _spritePath; public override void InitializeEntity(IEntity entity) { @@ -126,7 +123,7 @@ namespace Content.Client.GameObjects.Components maxCount = _spriteLayers.Count; } - var activeLayer = ContentHelpers.RoundToNearestLevels(actual, maxCount, _spriteLayers.Count - 1); + var activeLayer = ContentHelpers.RoundToEqualLevels(actual, maxCount, _spriteLayers.Count); spriteComponent.LayerSetState(IconLayer, _spriteLayers[activeLayer]); } diff --git a/Content.Shared/Utility/ContentHelpers.cs b/Content.Shared/Utility/ContentHelpers.cs index 31b7751c3a..dad2e39768 100644 --- a/Content.Shared/Utility/ContentHelpers.cs +++ b/Content.Shared/Utility/ContentHelpers.cs @@ -78,7 +78,7 @@ namespace Content.Shared.Utility /// The maximum value of the scale. /// Number of segments the scale is subdivided into. /// The segment lies on. - /// + /// If level is 1 or less public static int RoundToNearestLevels(double actual, double max, int levels) { if (levels <= 1) @@ -98,5 +98,42 @@ namespace Content.Shared.Utility return (int) Math.Round(actual / max * levels, MidpointRounding.AwayFromZero); } + + /// + /// Basically helper for when you need to choose 0..N-1 element based on what + /// percentage does actual/max takes. + /// Example: + /// We have a stack of 30 elements. + /// When is: + /// - 0..9 we return 0. + /// - 10..19 we return 1. + /// - 20..30 we return 2. + /// + /// Useful when selecting N sprites for display in stacks, etc. + /// + /// How many out of max elements are there + /// + /// + /// The + /// if level is one or less + public static int RoundToEqualLevels(double actual, double max, int levels) + { + if (levels <= 1) + { + throw new ArgumentException("Levels must be greater than 1.", nameof(levels)); + } + + if (actual >= max) + { + return levels - 1; + } + + if (actual <= 0) + { + return 0; + } + + return (int) Math.Round(actual / max * levels, MidpointRounding.ToZero); + } } } diff --git a/Content.Tests/Shared/Utility/ContentHelpers_Test.cs b/Content.Tests/Shared/Utility/ContentHelpers_Test.cs index 186fde1db4..206e18eca6 100644 --- a/Content.Tests/Shared/Utility/ContentHelpers_Test.cs +++ b/Content.Tests/Shared/Utility/ContentHelpers_Test.cs @@ -55,7 +55,7 @@ namespace Content.Tests.Shared.Utility (3, 5, 2, 1), (4, 5, 2, 2), (5, 5, 2, 2), - + // Testing even counts (0, 6, 5, 0), (1, 6, 5, 1), @@ -64,7 +64,7 @@ namespace Content.Tests.Shared.Utility (4, 6, 5, 3), (5, 6, 5, 4), (6, 6, 5, 5), - + // Testing transparency disable use case (0, 6, 6, 0), (1, 6, 6, 1), @@ -97,5 +97,54 @@ namespace Content.Tests.Shared.Utility (double val, double max, int size, int expected) = data; Assert.That(ContentHelpers.RoundToNearestLevels(val, max, size), Is.EqualTo(expected)); } + + [Parallelizable] + [Test] + // Testing odd max on even levels + [TestCase(0, 5, 2, ExpectedResult = 0)] + [TestCase(1, 5, 2, ExpectedResult = 0)] + [TestCase(2, 5, 2, ExpectedResult = 0)] + [TestCase(3, 5, 2, ExpectedResult = 1)] + [TestCase(4, 5, 2, ExpectedResult = 1)] + [TestCase(5, 5, 2, ExpectedResult = 1)] + // Testing even max on odd levels + [TestCase(0, 6, 3, ExpectedResult = 0)] + [TestCase(1, 6, 3, ExpectedResult = 0)] + [TestCase(2, 6, 3, ExpectedResult = 1)] + [TestCase(3, 6, 3, ExpectedResult = 1)] + [TestCase(4, 6, 3, ExpectedResult = 2)] + [TestCase(5, 6, 3, ExpectedResult = 2)] + [TestCase(6, 6, 3, ExpectedResult = 2)] + // Testing even max on even levels + [TestCase(0, 4, 2, ExpectedResult = 0)] + [TestCase(1, 4, 2, ExpectedResult = 0)] + [TestCase(2, 4, 2, ExpectedResult = 1)] + [TestCase(3, 4, 2, ExpectedResult = 1)] + [TestCase(4, 4, 2, ExpectedResult = 1)] + // Testing odd max on odd levels + [TestCase(0, 5, 3, ExpectedResult = 0)] + [TestCase(1, 5, 3, ExpectedResult = 0)] + [TestCase(2, 5, 3, ExpectedResult = 1)] + [TestCase(3, 5, 3, ExpectedResult = 1)] + [TestCase(4, 5, 3, ExpectedResult = 2)] + // Larger odd max on odd levels + [TestCase(0, 7, 3, ExpectedResult = 0)] + [TestCase(1, 7, 3, ExpectedResult = 0)] + [TestCase(2, 7, 3, ExpectedResult = 0)] + [TestCase(3, 7, 3, ExpectedResult = 1)] + [TestCase(4, 7, 3, ExpectedResult = 1)] + [TestCase(5, 7, 3, ExpectedResult = 2)] + [TestCase(6, 7, 3, ExpectedResult = 2)] + [TestCase(7, 7, 3, ExpectedResult = 2)] + // Testing edge cases + [TestCase(0.1, 6, 5, ExpectedResult = 0)] + [TestCase(-32, 6, 5, ExpectedResult = 0)] + [TestCase(2.4, 6, 5, ExpectedResult = 1)] + [TestCase(2.5, 6, 5, ExpectedResult = 2)] + [TestCase(320, 6, 5, ExpectedResult = 4)] + public int TestEqual(double val, double max, int size) + { + return ContentHelpers.RoundToEqualLevels(val, max, size); + } } }