diff --git a/src/Games/NexusMods.Games.FOMOD/CoreDelegates/UiDelegate.cs b/src/Games/NexusMods.Games.FOMOD/CoreDelegates/UiDelegate.cs index c8514b8236..4183cb7b7a 100644 --- a/src/Games/NexusMods.Games.FOMOD/CoreDelegates/UiDelegate.cs +++ b/src/Games/NexusMods.Games.FOMOD/CoreDelegates/UiDelegate.cs @@ -45,7 +45,7 @@ private static void DummyCancelInstaller() { } private readonly SemaphoreSlim _semaphoreSlim = new (1, 1); private readonly EventWaitHandle _waitHandle = new ManualResetEvent(initialState: false); - private long _taskFuckeryState; + private long _taskWaitingState; private const long Ready = 0; private const long WaitingForCallback = 1; @@ -92,7 +92,7 @@ public void UpdateState(FomodInstaller.Interface.ui.InstallerStep[] installSteps if (currentStepId < 0 || currentStepId >= installSteps.Length) return; // NOTE(erri120): This fuckery is explained further below when we call _selectOptions() - if (Interlocked.Read(ref _taskFuckeryState) == WaitingForCallback) + if (Interlocked.Read(ref _taskWaitingState) == WaitingForCallback) { if (!_waitHandle.Set()) { @@ -158,7 +158,7 @@ public void UpdateState(FomodInstaller.Interface.ui.InstallerStep[] installSteps // NOTE(erri120): Once again, the FOMOD library we're using is complete ass and expects // to be used in a JavaScript environment. However, this isn't JavaScript this is C#. // When calling _selectOptions, the library spawns a new Task that runs in the background. - // This means that after calling _selectOptions, we state hasn't been updated YET. + // This means that after calling _selectOptions, the state hasn't been updated YET. // Inside _selectOptions, the library wants to get the next step, however, if we // call _continueToNextStep, then the next step variable has already been updated. // The library doesn't do any checks to prevent this and can throw an exception @@ -170,14 +170,14 @@ public void UpdateState(FomodInstaller.Interface.ui.InstallerStep[] installSteps // updated its internal state. This behavior allows us to use an EventWaitHandle to "wait" for // the library to call us back. // We're also using CAS to set our state into "waiting" mode. - if (Interlocked.CompareExchange(ref _taskFuckeryState, WaitingForCallback, Ready) != Ready) + if (Interlocked.CompareExchange(ref _taskWaitingState, WaitingForCallback, Ready) != Ready) _logger.LogWarning("Unable to CAS!"); _selectOptions(currentStepId, selectedGroupId, selectedOptionIds); _waitHandle.WaitOne(TimeSpan.FromMilliseconds(200), exitContext: false); _waitHandle.Reset(); - if (Interlocked.CompareExchange(ref _taskFuckeryState, Ready, WaitingForCallback) != WaitingForCallback) + if (Interlocked.CompareExchange(ref _taskWaitingState, Ready, WaitingForCallback) != WaitingForCallback) _logger.LogWarning("Unable to CAS!"); } diff --git a/src/NexusMods.CLI/CliGuidedInstaller.cs b/src/NexusMods.CLI/CliGuidedInstaller.cs index 910f599673..e5c2a29a23 100644 --- a/src/NexusMods.CLI/CliGuidedInstaller.cs +++ b/src/NexusMods.CLI/CliGuidedInstaller.cs @@ -15,13 +15,14 @@ namespace NexusMods.CLI; public class CliGuidedInstaller : IGuidedInstaller { private const string CancelInput = "x"; + private const string PreviousInput = "p"; private const string BackInput = "b"; private const string NextInput = "n"; private static readonly string[] TableOfGroupsHeaders = { "Key", "Group" }; - private static readonly object[] TableOfGroupsFooterNextGroup = { NextInput, "Next Step" }; + private static readonly object[] TableOfGroupsFooterNextStep = { NextInput, "Next Step" }; private static readonly object[] TableOfGroupsFooterFinish = { NextInput, "Finish Installation" }; - private static readonly object[] TableOfGroupsFooterGoBack = { BackInput, "Previous Step" }; + private static readonly object[] TableOfGroupsFooterPreviousStep = { PreviousInput, "Previous Step" }; private static readonly object[] TableOfGroupsFooterCancel = { CancelInput, "Cancel Installation" }; private static readonly string[] TableOfOptionsHeaders = { "Key", "State", "Name", "Description" }; @@ -69,9 +70,7 @@ public Task RequestUserChoice(GuidedInstallationStep installationSte { if (currentGroup is null) { - // if the installation step has multiple groups - // the user has to select which group they want to use - + // the user hasn't selected a group yet RenderTableOfGroups(installationStep); var input = SkipAll ? NextInput : GetUserInput(); @@ -80,7 +79,7 @@ public Task RequestUserChoice(GuidedInstallationStep installationSte { case CancelInput: return Task.FromResult(new UserChoice(new UserChoice.CancelInstallation())); - case BackInput: + case PreviousInput: return Task.FromResult(new UserChoice(new UserChoice.GoToPreviousStep())); case NextInput: { @@ -95,12 +94,16 @@ public Task RequestUserChoice(GuidedInstallationStep installationSte // proceed to the next step return Task.FromResult(new UserChoice(new UserChoice.GoToNextStep(selectedOptions.ToArray()))); } - } + default: + { + var groupIndex = ParseNumericalUserInput(input, installationStep.Groups.Length); + if (groupIndex < 0) continue; - var groupIndex = ParseNumericalUserInput(input, installationStep.Groups.Length); - if (groupIndex < 0) continue; + currentGroup = installationStep.Groups[groupIndex]; + break; + } + } - currentGroup = installationStep.Groups[groupIndex]; } else { @@ -133,11 +136,11 @@ private void RenderTableOfGroups(GuidedInstallationStep installationStep) var row = installationStep.Groups .Select(group => new object[] { key++, group.Description }) .Append(installationStep.HasNextStep - ? TableOfGroupsFooterNextGroup + ? TableOfGroupsFooterNextStep : TableOfGroupsFooterFinish ); - if (installationStep.HasPreviousStep) row = row.Append(TableOfGroupsFooterGoBack); + if (installationStep.HasPreviousStep) row = row.Append(TableOfGroupsFooterPreviousStep); row = row.Append(TableOfGroupsFooterCancel); var table = new Table(TableOfGroupsHeaders, row.ToArray(), "Select a Group"); @@ -227,6 +230,8 @@ private static int ParseNumericalUserInput(string input, int upperLimit) { try { + // method returns a zero-based index for use as the option index + // the user inputs a one-based index, as it's easier to understand var idx = int.Parse(input) - 1; if (idx >= 0 && idx < upperLimit) return idx;