Skip to content

Commit

Permalink
Abstract out osu specific stuff from UpdateManager
Browse files Browse the repository at this point in the history
The first step in allowing rulesets to use the same GitHub update mechanism as an interim remedy to providing timely updates to players.
  • Loading branch information
LumpBloom7 committed Aug 8, 2023
1 parent e13eb75 commit 5e38187
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 171 deletions.
2 changes: 1 addition & 1 deletion osu.Android/OsuGameAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public override void SetHost(GameHost host)
host.Window.CursorState |= CursorState.Hidden;
}

protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager();
protected override UpdateManager CreateUpdateManager() => new SimpleGameUpdateManager();

protected override BatteryInfo CreateBatteryInfo() => new AndroidBatteryInfo();

Expand Down
4 changes: 2 additions & 2 deletions osu.Desktop/OsuGameDesktop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ protected override UpdateManager CreateUpdateManager()
string? packageManaged = Environment.GetEnvironmentVariable("OSU_EXTERNAL_UPDATE_PROVIDER");

if (!string.IsNullOrEmpty(packageManaged))
return new NoActionUpdateManager();
return new NoActionGameUpdateManager();

switch (RuntimeInfo.OS)
{
Expand All @@ -105,7 +105,7 @@ protected override UpdateManager CreateUpdateManager()
return new SquirrelUpdateManager();

default:
return new SimpleUpdateManager();
return new SimpleGameUpdateManager();
}
}

Expand Down
4 changes: 4 additions & 0 deletions osu.Desktop/Updater/SquirrelUpdateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Squirrel.SimpleSplat;
using LogLevel = Squirrel.SimpleSplat.LogLevel;
using UpdateManager = osu.Game.Updater.UpdateManager;
using GameVersionUpdater = osu.Game.Updater.GameVersionUpdater;

namespace osu.Desktop.Updater
{
Expand Down Expand Up @@ -45,6 +46,9 @@ private void load(INotificationOverlay notifications)
{
notificationOverlay = notifications;

// This will ensure that the version gets stored to the config as expected
AddInternal(new GameVersionUpdater());

SquirrelLocator.CurrentMutable.Register(() => squirrelLogger, typeof(ILogger));
}

Expand Down
2 changes: 1 addition & 1 deletion osu.Game/OsuGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ public override Task Import(ImportTask[] imports, ImportParameters parameters =

protected virtual Loader CreateLoader() => new Loader();

protected virtual UpdateManager CreateUpdateManager() => new UpdateManager();
protected virtual UpdateManager CreateUpdateManager() => new GameUpdateManager();

protected virtual HighPerformanceSession CreateHighPerformanceSession() => new HighPerformanceSession();

Expand Down
19 changes: 19 additions & 0 deletions osu.Game/Updater/GameUpdateManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Allocation;

namespace osu.Game.Updater
{
/// <summary>
/// An update manager which only shows notifications after a game update completes.
/// </summary>
public partial class GameUpdateManager : UpdateManager
{
[BackgroundDependencyLoader]
private void load()
{
AddInternal(new GameVersionUpdater());
}
}
}
74 changes: 74 additions & 0 deletions osu.Game/Updater/GameVersionUpdater.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;

namespace osu.Game.Updater
{
/// <summary>
/// This component is responsible for updating/comparing the osu! version string in the config.
/// This will show a notification suggesting users to read the changelogs if the game is on a newer version than last run.
/// </summary>
public partial class GameVersionUpdater : Component
{
[Resolved]
private OsuConfigManager config { get; set; } = null!;

[Resolved]
private OsuGameBase game { get; set; } = null!;

[Resolved]
protected INotificationOverlay Notifications { get; private set; } = null!;

protected override void LoadComplete()
{
base.LoadComplete();

string version = game.Version;

string lastVersion = config.Get<string>(OsuSetting.Version);

if (game.IsDeployedBuild && version != lastVersion)
{
// only show a notification if we've previously saved a version to the config file (ie. not the first run).
if (!string.IsNullOrEmpty(lastVersion))
Notifications.Post(new UpdateCompleteNotification(version));
}

// debug / local compilations will reset to a non-release string.
// can be useful to check when an install has transitioned between release and otherwise (see OsuConfigManager's migrations).
config.SetValue(OsuSetting.Version, version);
}

public partial class UpdateCompleteNotification : SimpleNotification
{
private readonly string version;

public UpdateCompleteNotification(string version)
{
this.version = version;
Text = $"You are now running osu! {version}.\nClick to see what's new!";
}

[BackgroundDependencyLoader]
private void load(OsuColour colours, ChangelogOverlay changelog, INotificationOverlay notificationOverlay)
{
Icon = FontAwesome.Solid.CheckSquare;
IconContent.Colour = colours.BlueDark;

Activated = delegate
{
notificationOverlay.Hide();
changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
return true;
};
}
}
}
}
19 changes: 19 additions & 0 deletions osu.Game/Updater/NoActionGameUpdateManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

namespace osu.Game.Updater
{
/// <summary>
/// An update manager that shows notifications if a newer release of osu! is detected.
/// This is a case where updates are handled externally by a package manager or other means, so no action is performed on clicking the notification.
/// </summary>
public partial class NoActionGameUpdateManager : SimpleGameUpdateManager
{
protected override string DownloadMessage => "Check with your package manager / provider to bring osu! up-to-date!";

// We intentionally ignore the user click.
protected override void UpdateActionOnClick(GitHubRelease release) {}
}
}
65 changes: 0 additions & 65 deletions osu.Game/Updater/NoActionUpdateManager.cs

This file was deleted.

61 changes: 61 additions & 0 deletions osu.Game/Updater/SimpleGameUpdateManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Framework.Allocation;
using osu.Framework;
using System.Runtime.InteropServices;

namespace osu.Game.Updater
{
/// <summary>
/// A simple update manager that is tailored for osu!'s update process.
/// </summary>
public partial class SimpleGameUpdateManager : SimpleUpdateManager
{
protected override string UpdatedComponentName => "osu!";
protected override string GitHubUrl => "https://api.github.com/repos/ppy/osu/releases/latest";

[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
Version = game.Version;

// This will ensure that the version gets stored to the config as expected
AddInternal(new GameVersionUpdater());
}

protected override string GetBestURL(GitHubRelease release)
{
GitHubAsset? bestAsset = null;

switch (RuntimeInfo.OS)
{
case RuntimeInfo.Platform.Windows:
bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".exe", StringComparison.Ordinal));
break;

case RuntimeInfo.Platform.macOS:
string arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "Apple.Silicon" : "Intel";
bestAsset = release.Assets?.Find(f => f.Name.EndsWith($".app.{arch}.zip", StringComparison.Ordinal));
break;

case RuntimeInfo.Platform.Linux:
bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".AppImage", StringComparison.Ordinal));
break;

case RuntimeInfo.Platform.iOS:
// iOS releases are available via testflight. this link seems to work well enough for now.
// see https://stackoverflow.com/a/32960501
return "itms-beta://beta.itunes.apple.com/v1/app/1447765923";

case RuntimeInfo.Platform.Android:
// on our testing device this causes the download to magically disappear.
//bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk"));
break;
}

return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
}
}
}
Loading

0 comments on commit 5e38187

Please sign in to comment.