diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index c33608832f..7290761d56 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -17,6 +17,7 @@ using osu.Framework.Logging; using osu.Game.Updater; using osu.Desktop.Windows; using osu.Framework.Allocation; +using osu.Game.Configuration; using osu.Game.IO; using osu.Game.IPC; using osu.Game.Online.Multiplayer; @@ -33,6 +34,8 @@ namespace osu.Desktop [Cached(typeof(IHighPerformanceSessionManager))] private readonly HighPerformanceSessionManager highPerformanceSessionManager = new HighPerformanceSessionManager(); + public bool IsFirstRun { get; init; } + public OsuGameDesktop(string[]? args = null) : base(args) { @@ -104,6 +107,14 @@ namespace osu.Desktop protected override UpdateManager CreateUpdateManager() { + // If this is the first time we've run the game, ie it is being installed, + // reset the user's release stream to "lazer". + // + // This ensures that if a user is trying to recover from a failed startup on an unstable release stream, + // the game doesn't immediately try and update them back to the release stream after starting up. + if (IsFirstRun) + LocalConfig.SetValue(OsuSetting.ReleaseStream, ReleaseStream.Lazer); + if (IsPackageManaged) return new NoActionUpdateManager(); diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index df872ae6c6..a311e42d6d 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -28,6 +28,8 @@ namespace osu.Desktop private static LegacyTcpIpcProvider? legacyIpc; + private static bool isFirstRun; + [STAThread] public static void Main(string[] args) { @@ -135,7 +137,12 @@ namespace osu.Desktop if (tournamentClient) host.Run(new TournamentGame()); else - host.Run(new OsuGameDesktop(args)); + { + host.Run(new OsuGameDesktop(args) + { + IsFirstRun = isFirstRun + }); + } } } @@ -177,6 +184,8 @@ namespace osu.Desktop var app = VelopackApp.Build(); + app.WithFirstRun(_ => isFirstRun = true); + if (OperatingSystem.IsWindows()) configureWindows(app); diff --git a/osu.Desktop/Updater/VelopackUpdateManager.cs b/osu.Desktop/Updater/VelopackUpdateManager.cs index 33ff6c2b37..6f22fd5940 100644 --- a/osu.Desktop/Updater/VelopackUpdateManager.cs +++ b/osu.Desktop/Updater/VelopackUpdateManager.cs @@ -4,8 +4,10 @@ using System; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game; +using osu.Game.Configuration; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Screens.Play; @@ -16,8 +18,8 @@ namespace osu.Desktop.Updater { public partial class VelopackUpdateManager : Game.Updater.UpdateManager { - private readonly UpdateManager updateManager; - private INotificationOverlay notificationOverlay = null!; + [Resolved] + private INotificationOverlay notificationOverlay { get; set; } = null!; [Resolved] private OsuGameBase game { get; set; } = null!; @@ -25,22 +27,32 @@ namespace osu.Desktop.Updater [Resolved] private ILocalUserPlayInfo? localUserInfo { get; set; } + [Resolved] + private OsuConfigManager osuConfigManager { get; set; } = null!; + private bool isInGameplay => localUserInfo?.PlayingState.Value != LocalUserPlayingState.NotPlaying; + private readonly Bindable releaseStream = new Bindable(); + private UpdateManager? updateManager; private UpdateInfo? pendingUpdate; - public VelopackUpdateManager() + protected override void LoadComplete() { - updateManager = new UpdateManager(new GithubSource(@"https://github.com/ppy/osu", null, false), new UpdateOptions + // Used by the base implementation. + osuConfigManager.BindWith(OsuSetting.ReleaseStream, releaseStream); + releaseStream.BindValueChanged(_ => onReleaseStreamChanged(), true); + + base.LoadComplete(); + } + + private void onReleaseStreamChanged() + { + updateManager = new UpdateManager(new GithubSource(@"https://github.com/ppy/osu", null, releaseStream.Value == ReleaseStream.Tachyon), new UpdateOptions { AllowVersionDowngrade = true, }); - } - [BackgroundDependencyLoader] - private void load(INotificationOverlay notifications) - { - notificationOverlay = notifications; + Schedule(() => Task.Run(CheckForUpdateAsync)); } protected override async Task PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false); @@ -76,6 +88,12 @@ namespace osu.Desktop.Updater return true; } + if (updateManager == null) + { + scheduleRecheck = true; + return false; + } + pendingUpdate = await updateManager.CheckForUpdatesAsync().ConfigureAwait(false); // No update is available. We'll check again later. @@ -141,6 +159,9 @@ namespace osu.Desktop.Updater private async Task restartToApplyUpdate() { + if (updateManager == null) + return; + await updateManager.WaitExitThenApplyUpdatesAsync(pendingUpdate?.TargetFullRelease).ConfigureAwait(false); Schedule(() => game.AttemptExit()); } diff --git a/osu.Game/Configuration/ReleaseStream.cs b/osu.Game/Configuration/ReleaseStream.cs index ed0bee1dd8..d4f382099c 100644 --- a/osu.Game/Configuration/ReleaseStream.cs +++ b/osu.Game/Configuration/ReleaseStream.cs @@ -1,13 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.ComponentModel; + namespace osu.Game.Configuration { public enum ReleaseStream { Lazer, - //Stable40, - //Beta40, - //Stable + + [Description("Tachyon (Unstable)")] + Tachyon } } diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 83a3af574c..0f4dd0805e 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -79,6 +79,18 @@ namespace osu.Game.Localisation /// public static LocalisableString LearnMoreAboutLazerTooltip => new TranslatableString(getKey(@"check_out_the_feature_comparison"), @"Check out the feature comparison and FAQ"); + /// + /// "Are you sure you want to run a potentially unstable version of the game?" + /// + public static LocalisableString ChangeReleaseStreamConfirmation => new TranslatableString(getKey(@"change_release stream_confirmation"), + @"Are you sure you want to run a potentially unstable version of the game?"); + + /// + /// "If you run into issues starting the game, you can usually run the installer from the official site to recover." + /// + public static LocalisableString ChangeReleaseStreamConfirmationInfo => new TranslatableString(getKey(@"change_release stream_confirmation_info"), + @"If you run into issues starting the game, you can usually run the installer from the official site to recover."); + /// /// "You are running the latest release ({0})" /// diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 261103173e..ac6215f3ad 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using osu.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; @@ -13,6 +14,7 @@ using osu.Framework.Statistics; using osu.Game.Configuration; using osu.Game.Localisation; using osu.Game.Online.Multiplayer; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Updater; @@ -27,6 +29,9 @@ namespace osu.Game.Overlays.Settings.Sections.General private SettingsButton checkForUpdatesButton = null!; + private readonly Bindable configReleaseStream = new Bindable(); + private SettingsEnumDropdown releaseStreamDropdown = null!; + [Resolved] private UpdateManager? updateManager { get; set; } @@ -40,21 +45,46 @@ namespace osu.Game.Overlays.Settings.Sections.General private OsuGame? game { get; set; } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load(OsuConfigManager config, IDialogOverlay? dialogOverlay) { - Add(new SettingsEnumDropdown - { - LabelText = GeneralSettingsStrings.ReleaseStream, - Current = config.GetBindable(OsuSetting.ReleaseStream), - }); + config.BindWith(OsuSetting.ReleaseStream, configReleaseStream); if (updateManager?.CanCheckForUpdate == true) { + Add(releaseStreamDropdown = new SettingsEnumDropdown + { + LabelText = GeneralSettingsStrings.ReleaseStream, + Current = { Value = configReleaseStream.Value }, + }); + Add(checkForUpdatesButton = new SettingsButton { Text = GeneralSettingsStrings.CheckUpdate, Action = () => checkForUpdates().FireAndForget() }); + + releaseStreamDropdown.Current.BindValueChanged(stream => + { + if (stream.NewValue == ReleaseStream.Tachyon) + { + dialogOverlay?.Push(new ConfirmDialog(GeneralSettingsStrings.ChangeReleaseStreamConfirmation, + () => + { + configReleaseStream.Value = ReleaseStream.Tachyon; + }, + () => + { + releaseStreamDropdown.Current.Value = ReleaseStream.Lazer; + }) + { + BodyText = GeneralSettingsStrings.ChangeReleaseStreamConfirmationInfo + }); + + return; + } + + configReleaseStream.Value = stream.NewValue; + }); } if (RuntimeInfo.IsDesktop)