diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 64adcecba4..a4270f22b4 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -12,6 +12,7 @@ using osu.Framework.Platform; using osu.Game; using OpenTK.Input; using Microsoft.Win32; +using osu.Desktop.Updater; using osu.Framework.Platform.Windows; namespace osu.Desktop @@ -38,6 +39,52 @@ namespace osu.Desktop } } + protected override void LoadComplete() + { + base.LoadComplete(); + + if (!noVersionOverlay) + { + LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v => + { + Add(v); + v.State = Visibility.Visible; + }); + +#if NET_FRAMEWORK + Add(new SquirrelUpdateManager()); +#else + Add(new SimpleUpdateManager()); +#endif + } + } + + public override void SetHost(GameHost host) + { + base.SetHost(host); + var desktopWindow = host.Window as DesktopGameWindow; + if (desktopWindow != null) + { + desktopWindow.CursorState |= CursorState.Hidden; + + desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico")); + desktopWindow.Title = Name; + + desktopWindow.FileDrop += fileDrop; + } + } + + private void fileDrop(object sender, FileDropEventArgs e) + { + var filePaths = new[] { e.FileName }; + + var firstExtension = Path.GetExtension(filePaths.First()); + + if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return; + + Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning); + } + /// /// A method of accessing an osu-stable install in a controlled fashion. /// @@ -77,45 +124,5 @@ namespace osu.Desktop { } } - - protected override void LoadComplete() - { - base.LoadComplete(); - - if (!noVersionOverlay) - { - LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v => - { - Add(v); - v.State = Visibility.Visible; - }); - } - } - - public override void SetHost(GameHost host) - { - base.SetHost(host); - var desktopWindow = host.Window as DesktopGameWindow; - if (desktopWindow != null) - { - desktopWindow.CursorState |= CursorState.Hidden; - - desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico")); - desktopWindow.Title = Name; - - desktopWindow.FileDrop += fileDrop; - } - } - - private void fileDrop(object sender, FileDropEventArgs e) - { - var filePaths = new[] { e.FileName }; - - var firstExtension = Path.GetExtension(filePaths.First()); - - if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return; - - Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning); - } } } diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index bc1faec822..1129969694 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -91,10 +91,6 @@ namespace osu.Desktop.Overlays } } }; - -#if NET_FRAMEWORK - Add(new SquirrelUpdateManager()); -#endif } protected override void LoadComplete() diff --git a/osu.Desktop/Updater/SimpleUpdateManager.cs b/osu.Desktop/Updater/SimpleUpdateManager.cs new file mode 100644 index 0000000000..cda8e6a7ca --- /dev/null +++ b/osu.Desktop/Updater/SimpleUpdateManager.cs @@ -0,0 +1,103 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json; +using osu.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.IO.Network; +using osu.Framework.Platform; +using osu.Game; +using osu.Game.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; + +namespace osu.Desktop.Updater +{ + /// + /// An update manager that shows notifications if a newer release is detected. + /// Installation is left up to the user. + /// + internal class SimpleUpdateManager : CompositeDrawable + { + private NotificationOverlay notificationOverlay; + private string version; + private GameHost host; + + [BackgroundDependencyLoader] + private void load(NotificationOverlay notification, OsuGameBase game, GameHost host) + { + notificationOverlay = notification; + + this.host = host; + version = game.Version; + + if (game.IsDeployedBuild) + Schedule(() => Task.Run(() => checkForUpdateAsync())); + } + + private async void checkForUpdateAsync() + { + var releases = new JsonWebRequest("https://api.github.com/repos/ppy/osu/releases/latest"); + await releases.PerformAsync(); + + var latest = releases.ResponseObject; + + if (latest.TagName != version) + { + notificationOverlay.Post(new SimpleNotification + { + Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n" + + "Click here to download the new version, which can be installed over the top of your existing installation", + Icon = FontAwesome.fa_upload, + Activated = () => + { + host.OpenUrlExternally(getBestUrl(latest)); + return true; + } + }); + } + } + + private string getBestUrl(GitHubRelease release) + { + GitHubAsset bestAsset = null; + + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe")); + break; + case RuntimeInfo.Platform.MacOsx: + bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".dmg")); + break; + } + + return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl; + } + + public class GitHubRelease + { + [JsonProperty("html_url")] + public string HtmlUrl { get; set; } + + [JsonProperty("tag_name")] + public string TagName { get; set; } + + [JsonProperty("assets")] + public List Assets { get; set; } + } + + public class GitHubAsset + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("browser_download_url")] + public string BrowserDownloadUrl { get; set; } + } + } +} diff --git a/osu.Desktop/Overlays/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs similarity index 97% rename from osu.Desktop/Overlays/SquirrelUpdateManager.cs rename to osu.Desktop/Updater/SquirrelUpdateManager.cs index ea86d2f028..81da26cff2 100644 --- a/osu.Desktop/Overlays/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -3,6 +3,7 @@ #if NET_FRAMEWORK using System; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -16,7 +17,7 @@ using OpenTK; using OpenTK.Graphics; using Squirrel; -namespace osu.Desktop.Overlays +namespace osu.Desktop.Updater { public class SquirrelUpdateManager : Component { @@ -35,7 +36,7 @@ namespace osu.Desktop.Overlays notificationOverlay = notification; if (game.IsDeployedBuild) - Schedule(() => checkForUpdateAsync()); + Schedule(() => Task.Run(() => checkForUpdateAsync())); } private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e488dacf80..fd24e4297b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -339,6 +339,8 @@ namespace osu.Game.Beatmaps { var beatmapInfos = new List(); + bool invalidateOnlineIDs = false; + foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu"))) { using (var raw = reader.GetStream(name)) @@ -355,9 +357,18 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. - if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) - beatmap.BeatmapInfo.OnlineBeatmapID = null; + if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue) + { + var ourId = beatmap.BeatmapInfo.OnlineBeatmapID; + + // check that no existing beatmap in database exists that is imported with the same online beatmap ID. if so, give it precedence. + if (QueryBeatmap(b => b.OnlineBeatmapID.Value == ourId) != null) + beatmap.BeatmapInfo.OnlineBeatmapID = null; + + // check that no other beatmap in this imported set has a conflicting online beatmap ID. If so, presume *all* are incorrect. + if (beatmapInfos.Any(b => b.OnlineBeatmapID == ourId)) + invalidateOnlineIDs = true; + } RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); @@ -375,6 +386,9 @@ namespace osu.Game.Beatmaps } } + if (invalidateOnlineIDs) + beatmapInfos.ForEach(b => b.OnlineBeatmapID = null); + return beatmapInfos; } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 246229a794..c1d5ae581e 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Textures; +using osu.Framework.Input; using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.Database; @@ -30,6 +31,7 @@ using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; +using OpenTK.Input; using DebugUtils = osu.Game.Utils.DebugUtils; namespace osu.Game @@ -98,6 +100,8 @@ namespace osu.Game private DatabaseContextFactory contextFactory; + protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); + [BackgroundDependencyLoader] private void load() { @@ -267,5 +271,31 @@ namespace osu.Game return copy; } } + + private class OsuUserInputManager : UserInputManager + { + protected override MouseButtonEventManager CreateButtonManagerFor(MouseButton button) + { + switch (button) + { + case MouseButton.Right: + return new RightMouseManager(button); + } + + return base.CreateButtonManagerFor(button); + } + + private class RightMouseManager : MouseButtonEventManager + { + public RightMouseManager(MouseButton button) + : base(button) + { + } + + public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers. + public override bool EnableClick => false; + public override bool ChangeFocusOnClick => false; + } + } } }