]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add new "OptionsVisualizer" (#25128)
authorPieter-Jan Briers <pieterjan.briers+git@gmail.com>
Sat, 17 Feb 2024 20:52:11 +0000 (21:52 +0100)
committerGitHub <noreply@github.com>
Sat, 17 Feb 2024 20:52:11 +0000 (15:52 -0500)
This is a visualizer somewhat similar to the Generic. It allows configuring appearance info based on specific CVars the user has set. This allows YAML to easily configure alternatives for accessibility CVars like reduced motion.

Content.Client/Options/OptionsVisualizerComponent.cs [new file with mode: 0644]
Content.Client/Options/OptionsVisualizerSystem.cs [new file with mode: 0644]
Content.Server/Entry/IgnoredComponents.cs
Content.Shared/CCVar/CCVars.cs
Resources/Prototypes/Entities/Debugging/options_visualizer.yml [new file with mode: 0644]
Resources/Textures/Effects/optionsvisualizertest.rsi/both.png [new file with mode: 0644]
Resources/Textures/Effects/optionsvisualizertest.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Effects/optionsvisualizertest.rsi/motion.png [new file with mode: 0644]
Resources/Textures/Effects/optionsvisualizertest.rsi/none.png [new file with mode: 0644]
Resources/Textures/Effects/optionsvisualizertest.rsi/test.png [new file with mode: 0644]

diff --git a/Content.Client/Options/OptionsVisualizerComponent.cs b/Content.Client/Options/OptionsVisualizerComponent.cs
new file mode 100644 (file)
index 0000000..87999f3
--- /dev/null
@@ -0,0 +1,84 @@
+using Content.Shared.CCVar;
+
+namespace Content.Client.Options;
+
+/// <summary>
+/// Allows specifying sprite alternatives depending on the client's accessibility options.
+/// </summary>
+/// <remarks>
+/// A list of layer mappings is given that the component applies to,
+/// and it will pick one entry to apply based on the settings configuration. Example:
+///
+/// <code>
+/// - type: Sprite
+///   sprite: Effects/optionsvisualizertest.rsi
+///   layers:
+///   - state: none
+///     map: [ "layer" ]
+/// - type: OptionsVisualizer
+///   visuals:
+///     layer:
+///     - options: Default
+///       data: { state: none }
+///     - options: Test
+///       data: { state: test }
+///     - options: ReducedMotion
+///       data: { state: motion }
+///     - options: [Test, ReducedMotion]
+///       data: { state: both }
+/// </code>
+/// </remarks>
+/// <seealso cref="OptionsVisualizerSystem"/>
+/// <seealso cref="OptionVisualizerOptions"/>
+[RegisterComponent]
+public sealed partial class OptionsVisualizerComponent : Component
+{
+    /// <summary>
+    /// A mapping storing data about which sprite layer keys should be controlled.
+    /// </summary>
+    /// <remarks>
+    /// Each layer stores an array of possible options. The last entry with a
+    /// <see cref="LayerDatum.Options"/> matching the active user preferences will be picked.
+    /// This allows choosing a priority if multiple entries are matched.
+    /// </remarks>
+    [DataField(required: true)]
+    public Dictionary<string, LayerDatum[]> Visuals = default!;
+
+    /// <summary>
+    /// A single option for a layer to be selected.
+    /// </summary>
+    [DataDefinition]
+    public sealed partial class LayerDatum
+    {
+        /// <summary>
+        /// Which options must be set by the user to make this datum match.
+        /// </summary>
+        [DataField]
+        public OptionVisualizerOptions Options { get; set; }
+
+        /// <summary>
+        /// The sprite layer data to set on the sprite when this datum matches.
+        /// </summary>
+        [DataField]
+        public PrototypeLayerData Data { get; set; }
+    }
+}
+
+[Flags]
+public enum OptionVisualizerOptions
+{
+    /// <summary>
+    /// Corresponds to no special options being set, can be used as a "default" state.
+    /// </summary>
+    Default = 0,
+
+    /// <summary>
+    /// Corresponds to the <see cref="CCVars.DebugOptionVisualizerTest"/> CVar being set.
+    /// </summary>
+    Test = 1 << 0,
+
+    /// <summary>
+    /// Corresponds to the <see cref="CCVars.ReducedMotion"/> CVar being set.
+    /// </summary>
+    ReducedMotion = 1 << 1,
+}
diff --git a/Content.Client/Options/OptionsVisualizerSystem.cs b/Content.Client/Options/OptionsVisualizerSystem.cs
new file mode 100644 (file)
index 0000000..2a297e3
--- /dev/null
@@ -0,0 +1,97 @@
+using Content.Shared.CCVar;
+using Robust.Client.GameObjects;
+using Robust.Shared.Configuration;
+using Robust.Shared.Reflection;
+
+namespace Content.Client.Options;
+
+/// <summary>
+/// Implements <see cref="OptionsVisualizerComponent"/>.
+/// </summary>
+public sealed class OptionsVisualizerSystem : EntitySystem
+{
+    private static readonly (OptionVisualizerOptions, CVarDef<bool>)[] OptionVars =
+    {
+        (OptionVisualizerOptions.Test, CCVars.DebugOptionVisualizerTest),
+        (OptionVisualizerOptions.ReducedMotion, CCVars.ReducedMotion),
+    };
+
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+    [Dependency] private readonly IReflectionManager _reflection = default!;
+
+    private OptionVisualizerOptions _currentOptions;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        foreach (var (_, cvar) in OptionVars)
+        {
+            Subs.CVar(_cfg, cvar, _ => CVarChanged());
+        }
+
+        UpdateActiveOptions();
+
+        SubscribeLocalEvent<OptionsVisualizerComponent, ComponentStartup>(OnComponentStartup);
+    }
+
+    private void CVarChanged()
+    {
+        UpdateActiveOptions();
+        UpdateAllComponents();
+    }
+
+    private void UpdateActiveOptions()
+    {
+        _currentOptions = OptionVisualizerOptions.Default;
+
+        foreach (var (value, cVar) in OptionVars)
+        {
+            if (_cfg.GetCVar(cVar))
+                _currentOptions |= value;
+        }
+    }
+
+    private void UpdateAllComponents()
+    {
+        var query = EntityQueryEnumerator<OptionsVisualizerComponent, SpriteComponent>();
+        while (query.MoveNext(out _, out var component, out var sprite))
+        {
+            UpdateComponent(component, sprite);
+        }
+    }
+
+    private void OnComponentStartup(EntityUid uid, OptionsVisualizerComponent component, ComponentStartup args)
+    {
+        if (!TryComp(uid, out SpriteComponent? sprite))
+            return;
+
+        UpdateComponent(component, sprite);
+    }
+
+    private void UpdateComponent(OptionsVisualizerComponent component, SpriteComponent sprite)
+    {
+        foreach (var (layerKeyRaw, layerData) in component.Visuals)
+        {
+            object layerKey = _reflection.TryParseEnumReference(layerKeyRaw, out var @enum)
+                ? @enum
+                : layerKeyRaw;
+
+            OptionsVisualizerComponent.LayerDatum? matchedDatum = null;
+            foreach (var datum in layerData)
+            {
+                if ((datum.Options & _currentOptions) != datum.Options)
+                    continue;
+
+                matchedDatum = datum;
+            }
+
+            if (matchedDatum == null)
+                continue;
+
+            var layerIndex = sprite.LayerMapReserveBlank(layerKey);
+            sprite.LayerSetData(layerIndex, matchedDatum.Data);
+        }
+    }
+}
+
index c1b646ec4f968bbef7dea2cd05363e2c32a080be..fe073da7a49a677eeb7010b5c44919d175384e7d 100644 (file)
@@ -19,6 +19,7 @@ namespace Content.Server.Entry
             "InventorySlots",
             "LightFade",
             "HolidayRsiSwap",
+            "OptionsVisualizer",
         };
     }
 }
index fb6b25b57f5aaf41e48a617e167b4c8cb76b7b75..e8f5e44a616bfebc7072046a767131c3ecaf182d 100644 (file)
@@ -2011,5 +2011,15 @@ namespace Content.Shared.CCVar
 
         public static readonly CVarDef<bool> GatewayGeneratorEnabled =
             CVarDef.Create("gateway.generator_enabled", true);
+
+        /*
+         * DEBUG
+         */
+
+        /// <summary>
+        /// A simple toggle to test <c>OptionsVisualizerComponent</c>.
+        /// </summary>
+        public static readonly CVarDef<bool> DebugOptionVisualizerTest =
+            CVarDef.Create("debug.option_visualizer_test", false, CVar.CLIENTONLY);
     }
 }
diff --git a/Resources/Prototypes/Entities/Debugging/options_visualizer.yml b/Resources/Prototypes/Entities/Debugging/options_visualizer.yml
new file mode 100644 (file)
index 0000000..229ffa0
--- /dev/null
@@ -0,0 +1,24 @@
+- type: entity
+  id: OptionsVisualizerTest
+  suffix: DEBUG
+  components:
+  - type: Tag
+    tags:
+    - Debug
+  - type: Sprite
+    sprite: Effects/optionsvisualizertest.rsi
+    layers:
+    - state: none
+      map: [ "layer" ]
+  - type: OptionsVisualizer
+    visuals:
+      layer:
+      - options: Default
+        data: { state: none }
+      - options: Test
+        data: { state: test }
+      - options: ReducedMotion
+        data: { state: motion }
+      - options: [Test, ReducedMotion]
+        data: { state: both }
+
diff --git a/Resources/Textures/Effects/optionsvisualizertest.rsi/both.png b/Resources/Textures/Effects/optionsvisualizertest.rsi/both.png
new file mode 100644 (file)
index 0000000..76237f5
Binary files /dev/null and b/Resources/Textures/Effects/optionsvisualizertest.rsi/both.png differ
diff --git a/Resources/Textures/Effects/optionsvisualizertest.rsi/meta.json b/Resources/Textures/Effects/optionsvisualizertest.rsi/meta.json
new file mode 100644 (file)
index 0000000..e7f7495
--- /dev/null
@@ -0,0 +1 @@
+{"version":1,"size":{"x":32,"y":32},"license":"CC-BY-SA-4.0","copyright":"Discord pjb","states":[{"name":"none"},{"name":"both"},{"name":"motion"},{"name":"test"}]}
diff --git a/Resources/Textures/Effects/optionsvisualizertest.rsi/motion.png b/Resources/Textures/Effects/optionsvisualizertest.rsi/motion.png
new file mode 100644 (file)
index 0000000..edbbd52
Binary files /dev/null and b/Resources/Textures/Effects/optionsvisualizertest.rsi/motion.png differ
diff --git a/Resources/Textures/Effects/optionsvisualizertest.rsi/none.png b/Resources/Textures/Effects/optionsvisualizertest.rsi/none.png
new file mode 100644 (file)
index 0000000..2f2dc7b
Binary files /dev/null and b/Resources/Textures/Effects/optionsvisualizertest.rsi/none.png differ
diff --git a/Resources/Textures/Effects/optionsvisualizertest.rsi/test.png b/Resources/Textures/Effects/optionsvisualizertest.rsi/test.png
new file mode 100644 (file)
index 0000000..0078fd4
Binary files /dev/null and b/Resources/Textures/Effects/optionsvisualizertest.rsi/test.png differ