diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index e99b68c8f..c2a81fa54 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -3555,6 +3555,10 @@ static void RequireRuntimeInputScreenUsesEveSurface(string root) "ActionGameManager.RequestRuntimeActionBarInput", "action.ApplyBindingOverride", "new InputAction(\"Aetheria Input Capture\")", + "AetheriaRuntimeInputSettingsSurfaceBuilder.DefaultActionBarCandidatePaths", + "AetheriaRuntimeInputSettingsSurfaceBuilder.IsSupportedCapturePath(", + "AetheriaRuntimeInputSettingsSurfaceBuilder.ProjectActionBarInputs(", + "new AetheriaRuntimeInputPathSurfaceLabel(", "HideLegacyChildren()" }; @@ -3589,7 +3593,10 @@ static void RequireRuntimeInputScreenUsesEveSurface(string root) "ToggleActionBarInput(request.Payload)", "private void BeginCapture(IReadOnlyDictionary payload)", "private void ToggleActionBarInput(IReadOnlyDictionary payload)", - "request.Payload" + "request.Payload", + "private static readonly string[] DefaultActionBarCandidatePaths", + "private static bool IsSupportedCapturePath(string path)", + "new SortedDictionary(StringComparer.Ordinal)" }; var survivingLegacySymbols = forbiddenInputScreenSymbols @@ -3619,6 +3626,11 @@ static void RequireRuntimeInputScreenUsesEveSurface(string root) "public sealed class AetheriaRuntimeInputSettingsSurfaceState", "public sealed class AetheriaRuntimeInputBindingSurfaceState", "public sealed class AetheriaRuntimeActionBarInputSurfaceState", + "public sealed class AetheriaRuntimeInputPathSurfaceLabel", + "public static readonly IReadOnlyList DefaultActionBarCandidatePaths", + "public static bool IsSupportedCapturePath(string path)", + "public static IReadOnlyList ProjectActionBarInputs(", + "new SortedDictionary(StringComparer.Ordinal)", "public enum AetheriaRuntimeInputSettingsCommandKind", "public readonly struct AetheriaRuntimeInputSettingsSurfaceCommand", "public static class AetheriaRuntimeInputSettingsSurfaceCommands", diff --git a/Assets/Scripts/UI/InputScreen/InputDisplayLayout.cs b/Assets/Scripts/UI/InputScreen/InputDisplayLayout.cs index 64c97a7a0..230be6d88 100644 --- a/Assets/Scripts/UI/InputScreen/InputDisplayLayout.cs +++ b/Assets/Scripts/UI/InputScreen/InputDisplayLayout.cs @@ -11,21 +11,6 @@ using UnityEngine.UIElements; public class InputDisplayLayout : MonoBehaviour { - private static readonly string[] DefaultActionBarCandidatePaths = - { - "/leftButton", - "/rightButton", - "/middleButton", - "/forwardButton", - "/backButton", - "/1", - "/2", - "/3", - "/4", - "/5", - "/leftShift" - }; - private UIDocument _surfaceDocument; private AetheriaInput _ownedInput; private InputAction _captureAction; @@ -202,7 +187,7 @@ public class InputDisplayLayout : MonoBehaviour .Where(entry => !entry.binding.isComposite && !string.IsNullOrWhiteSpace(entry.binding.effectivePath) && - IsSupportedCapturePath(entry.binding.effectivePath)) + AetheriaRuntimeInputSettingsSurfaceBuilder.IsSupportedCapturePath(entry.binding.effectivePath)) .Select(entry => new AetheriaRuntimeInputBindingSurfaceState( entry.action.name, entry.bindingIndex, @@ -215,18 +200,22 @@ public class InputDisplayLayout : MonoBehaviour private IReadOnlyList ProjectActionBarRows() { var runtimeSettings = ActionGameManager.RuntimePlayerSettings.InputSettings; - var candidates = new SortedDictionary(StringComparer.Ordinal); + var candidates = new List(); - foreach (var defaultPath in DefaultActionBarCandidatePaths) + foreach (var defaultPath in AetheriaRuntimeInputSettingsSurfaceBuilder.DefaultActionBarCandidatePaths) { - candidates[defaultPath] = DescribeInputPath(defaultPath); + candidates.Add(new AetheriaRuntimeInputPathSurfaceLabel( + defaultPath, + DescribeInputPath(defaultPath))); } foreach (var inputPath in runtimeSettings.ActionBarInputs) { if (!string.IsNullOrWhiteSpace(inputPath)) { - candidates[inputPath] = DescribeInputPath(inputPath); + candidates.Add(new AetheriaRuntimeInputPathSurfaceLabel( + inputPath, + DescribeInputPath(inputPath))); } } @@ -236,29 +225,23 @@ public class InputDisplayLayout : MonoBehaviour { foreach (var binding in action.bindings) { - if (binding.isComposite || string.IsNullOrWhiteSpace(binding.effectivePath) || !IsSupportedCapturePath(binding.effectivePath)) + if (binding.isComposite || + string.IsNullOrWhiteSpace(binding.effectivePath) || + !AetheriaRuntimeInputSettingsSurfaceBuilder.IsSupportedCapturePath(binding.effectivePath)) { continue; } - candidates[binding.effectivePath] = DescribeInputPath(binding.effectivePath); + candidates.Add(new AetheriaRuntimeInputPathSurfaceLabel( + binding.effectivePath, + DescribeInputPath(binding.effectivePath))); } } } - return candidates - .Select(entry => new AetheriaRuntimeActionBarInputSurfaceState( - entry.Key, - entry.Value, - runtimeSettings.ActionBarInputs.Contains(entry.Key))) - .ToArray(); - } - - private static bool IsSupportedCapturePath(string path) - { - return !string.IsNullOrWhiteSpace(path) && - (path.StartsWith("/", StringComparison.Ordinal) || - path.StartsWith("/", StringComparison.Ordinal)); + return AetheriaRuntimeInputSettingsSurfaceBuilder.ProjectActionBarInputs( + runtimeSettings.ActionBarInputs, + candidates); } private static string DescribeBinding(string actionName, InputBinding binding) @@ -362,7 +345,7 @@ public class InputDisplayLayout : MonoBehaviour var inputPath = context.control?.path ?? ""; if (string.IsNullOrWhiteSpace(inputPath) || inputPath.EndsWith("anyKey", StringComparison.Ordinal) || - !IsSupportedCapturePath(inputPath) || + !AetheriaRuntimeInputSettingsSurfaceBuilder.IsSupportedCapturePath(inputPath) || Input == null) { return; diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeInputSettingsSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeInputSettingsSurfaceBuilder.cs index 95eae1d23..eefde3239 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeInputSettingsSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeInputSettingsSurfaceBuilder.cs @@ -72,8 +72,80 @@ namespace GameCult.Aetheria.State.Verse public bool Enabled { get; } } + public sealed class AetheriaRuntimeInputPathSurfaceLabel + { + public AetheriaRuntimeInputPathSurfaceLabel(string inputPath, string label) + { + InputPath = inputPath ?? ""; + Label = label ?? ""; + } + + public string InputPath { get; } + + public string Label { get; } + } + public static class AetheriaRuntimeInputSettingsSurfaceBuilder { + public static readonly IReadOnlyList DefaultActionBarCandidatePaths = new[] + { + "/leftButton", + "/rightButton", + "/middleButton", + "/forwardButton", + "/backButton", + "/1", + "/2", + "/3", + "/4", + "/5", + "/leftShift" + }; + + public static bool IsSupportedCapturePath(string path) + { + return !string.IsNullOrWhiteSpace(path) && + (path.StartsWith("/", StringComparison.Ordinal) || + path.StartsWith("/", StringComparison.Ordinal)); + } + + public static IReadOnlyList ProjectActionBarInputs( + IEnumerable enabledInputPaths, + IEnumerable candidateInputPaths) + { + var enabledPaths = new HashSet( + (enabledInputPaths ?? Array.Empty()).Where(path => !string.IsNullOrWhiteSpace(path)), + StringComparer.Ordinal); + var candidates = new SortedDictionary(StringComparer.Ordinal); + + foreach (var candidate in candidateInputPaths ?? Array.Empty()) + { + if (candidate == null || string.IsNullOrWhiteSpace(candidate.InputPath)) + { + continue; + } + + candidates[candidate.InputPath] = string.IsNullOrWhiteSpace(candidate.Label) + ? candidate.InputPath + : candidate.Label; + } + + foreach (var enabledPath in enabledPaths) + { + if (!candidates.ContainsKey(enabledPath)) + { + candidates[enabledPath] = enabledPath; + } + } + + return candidates + .Select(entry => new AetheriaRuntimeActionBarInputSurfaceState( + entry.Key, + entry.Value, + enabledPaths.Contains(entry.Key))) + .ToArray(); + } + public static AetheriaRuntimeSurfaceDocument Build( AetheriaRuntimeInputSettingsSurfaceState settings, long version = 1)