1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 01:02:55 +08:00

Merge pull request #349 from peppy/installer-updater

Automatic updates.
This commit is contained in:
Thomas Müller 2017-02-12 12:16:03 +01:00 committed by GitHub
commit ff6838f88c
15 changed files with 395 additions and 126 deletions

@ -1 +1 @@
Subproject commit 16cc4a53a0447264b8f67f149da701c4f00a41ea
Subproject commit e776f6f2729bbe93206c4e8c089eeca57522fcf7

View File

@ -88,13 +88,13 @@ namespace osu.Desktop.VisualTests.Tests
if (n.Progress < 1)
n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle();
else
n.Complete();
n.State = ProgressNotificationState.Completed;
}
}
private void sendProgress2()
{
var n = new ProgressNotification(@"Downloading Haitai...");
var n = new ProgressNotification { Text = @"Downloading Haitai..." };
manager.Post(n);
progressingNotifications.Add(n);
}
@ -103,19 +103,19 @@ namespace osu.Desktop.VisualTests.Tests
private void sendProgress1()
{
var n = new ProgressNotification(@"Uploading to BSS...");
var n = new ProgressNotification { Text = @"Uploading to BSS..." };
manager.Post(n);
progressingNotifications.Add(n);
}
private void sendNotification2()
{
manager.Post(new SimpleNotification(@"You are amazing"));
manager.Post(new SimpleNotification { Text = @"You are amazing" });
}
private void sendNotification1()
{
manager.Post(new SimpleNotification(@"Welcome to osu!. Enjoy your stay!"));
manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" });
}
}
}

View File

@ -11,6 +11,9 @@ using System.Windows.Forms;
using osu.Framework.Platform;
using osu.Framework.Desktop.Platform;
using osu.Game.Database;
using osu.Desktop.Overlays;
using System.Reflection;
using System.Drawing;
namespace osu.Desktop
{
@ -22,12 +25,22 @@ namespace osu.Desktop
}
protected override void LoadComplete()
{
base.LoadComplete();
(new VersionManager()).Preload(this, Add);
}
public override void SetHost(BasicGameHost host)
{
base.SetHost(host);
var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null)
{
desktopWindow.Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
desktopWindow.Title = @"osu!lazer";
desktopWindow.DragEnter += dragEnter;
desktopWindow.DragDrop += dragDrop;
}

View File

@ -0,0 +1,93 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using Squirrel;
using System.Reflection;
namespace osu.Desktop.Overlays
{
public class VersionManager : OverlayContainer
{
private UpdateManager updateManager;
private NotificationManager notification;
[BackgroundDependencyLoader]
private void load(NotificationManager notification)
{
this.notification = notification;
AutoSizeAxes = Axes.Both;
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
var asm = Assembly.GetEntryAssembly().GetName();
Add(new OsuSpriteText
{
Text = $@"osu!lazer v{asm.Version}"
});
updateChecker();
}
protected override void LoadComplete()
{
base.LoadComplete();
State = Visibility.Visible;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
updateManager?.Dispose();
}
private async void updateChecker()
{
updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
var info = await updateManager.CheckForUpdate();
if (info.ReleasesToApply.Count > 0)
{
ProgressNotification n = new UpdateProgressNotification
{
Text = @"Downloading update..."
};
Schedule(() => notification.Post(n));
Schedule(() => n.State = ProgressNotificationState.Active);
await updateManager.DownloadReleases(info.ReleasesToApply, (int p) => Schedule(() => n.Progress = p / 100f));
Schedule(() => n.Text = @"Installing update...");
await updateManager.ApplyReleases(info, (int p) => Schedule(() => n.Progress = p / 100f));
Schedule(() => n.State = ProgressNotificationState.Completed);
}
else
{
//check again every 30 minutes.
Scheduler.AddDelayed(updateChecker, 60000 * 30);
}
}
protected override void PopIn()
{
}
protected override void PopOut()
{
}
class UpdateProgressNotification : ProgressNotification
{
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification(this)
{
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
UpdateManager.RestartApp();
return true;
}
};
}
}
}

View File

@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu!lazer")]
[assembly: AssemblyDescription("click the circles. to the beat.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ppy Pty Ltd")]
[assembly: AssemblyProduct("osu!lazer")]
[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")]
[assembly: AssemblyVersion("0.0.3")]
[assembly: AssemblyFileVersion("0.0.3")]

11
osu.Desktop/app.config Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -79,19 +79,73 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<Win32Resource>osu!.res</Win32Resource>
<Win32Resource>
</Win32Resource>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>lazer.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.0.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.PatchApi.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\squirrel.windows.1.5.2\lib\Net45\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4" />
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Squirrel, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
</None>
<None Include="app.config" />
<None Include="osu!.res" />
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
</ItemGroup>
<ItemGroup>
@ -157,10 +211,14 @@
</ItemGroup>
<ItemGroup>
<Compile Include="OsuGameDesktop.cs" />
<Compile Include="Overlays\VersionManager.cs" />
<Compile Include="Program.cs" />
<Compile Include="Beatmaps\IO\LegacyFilesystemReader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="lazer.ico" />
</ItemGroup>
<ItemGroup />
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.1" targetFramework="net45" />
<package id="Splat" version="1.6.2" targetFramework="net45" />
<package id="squirrel.windows" version="1.5.2" targetFramework="net45" />
</packages>

View File

@ -83,64 +83,66 @@ namespace osu.Game.Database
connection.DeleteAll<BeatmapInfo>();
}
public void Import(params string[] paths)
public void Import(IEnumerable<string> paths)
{
foreach (string p in paths)
Import(p);
}
public void Import(string path)
{
string hash = null;
BeatmapMetadata metadata;
using (var reader = ArchiveReader.GetReader(storage, path))
metadata = reader.ReadMetadata();
if (metadata.OnlineBeatmapSetID.HasValue &&
connection.Table<BeatmapSetInfo>().Count(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) != 0)
return; // TODO: Update this beatmap instead
if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader
{
var path = p;
string hash = null;
BeatmapMetadata metadata;
using (var reader = ArchiveReader.GetReader(storage, path))
metadata = reader.ReadMetadata();
if (metadata.OnlineBeatmapSetID.HasValue &&
connection.Table<BeatmapSetInfo>().Count(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) != 0)
return; // TODO: Update this beatmap instead
if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader
using (var md5 = MD5.Create())
using (var input = storage.GetStream(path))
{
using (var md5 = MD5.Create())
using (var input = storage.GetStream(path))
{
hash = BitConverter.ToString(md5.ComputeHash(input)).Replace("-", "").ToLowerInvariant();
input.Seek(0, SeekOrigin.Begin);
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
using (var output = storage.GetStream(path, FileAccess.Write))
input.CopyTo(output);
}
hash = BitConverter.ToString(md5.ComputeHash(input)).Replace("-", "").ToLowerInvariant();
input.Seek(0, SeekOrigin.Begin);
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
using (var output = storage.GetStream(path, FileAccess.Write))
input.CopyTo(output);
}
var beatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
Beatmaps = new List<BeatmapInfo>(),
Path = path,
Hash = hash,
Metadata = metadata
};
using (var reader = ArchiveReader.GetReader(storage, path))
{
string[] mapNames = reader.ReadBeatmaps();
foreach (var name in mapNames)
{
using (var stream = new StreamReader(reader.GetStream(name)))
{
var decoder = BeatmapDecoder.GetDecoder(stream);
Beatmap beatmap = decoder.Decode(stream);
beatmap.BeatmapInfo.Path = name;
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
beatmap.BeatmapInfo.Metadata = null;
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
}
}
}
Import(new[] { beatmapSet });
}
var beatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
Beatmaps = new List<BeatmapInfo>(),
Path = path,
Hash = hash,
Metadata = metadata
};
using (var reader = ArchiveReader.GetReader(storage, path))
{
string[] mapNames = reader.ReadBeatmaps();
foreach (var name in mapNames)
{
using (var stream = new StreamReader(reader.GetStream(name)))
{
var decoder = BeatmapDecoder.GetDecoder(stream);
Beatmap beatmap = decoder.Decode(stream);
beatmap.BeatmapInfo.Path = name;
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
beatmap.BeatmapInfo.Metadata = null;
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
}
}
}
Import(new[] { beatmapSet });
}
public void Import(IEnumerable<BeatmapSetInfo> beatmapSets)

View File

@ -24,6 +24,7 @@ using osu.Game.Screens.Menu;
using OpenTK;
using System.Linq;
using osu.Framework.Graphics.Primitives;
using System.Collections.Generic;
namespace osu.Game
{
@ -67,14 +68,17 @@ namespace osu.Game
}
if (args?.Length > 0)
ImportBeatmaps(args);
{
var paths = args.Where(a => !a.StartsWith(@"-"));
ImportBeatmaps(paths);
}
Dependencies.Cache(this);
PlayMode = LocalConfig.GetBindable<PlayMode>(OsuConfig.PlayMode);
}
public void ImportBeatmaps(params string[] paths)
public void ImportBeatmaps(IEnumerable<string> paths)
{
Schedule(delegate { Dependencies.Get<BeatmapDatabase>().Import(paths); });
}

View File

@ -73,6 +73,8 @@ namespace osu.Game.Overlays
public void Post(Notification notification)
{
State = Visibility.Visible;
++runningDepth;
notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth;

View File

@ -53,8 +53,7 @@ namespace osu.Game.Overlays.Notifications
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
public Notification()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;

View File

@ -1,6 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Graphics;
namespace osu.Game.Overlays.Notifications
{
public class ProgressCompletionNotification : SimpleNotification
@ -8,9 +10,9 @@ namespace osu.Game.Overlays.Notifications
private ProgressNotification progressNotification;
public ProgressCompletionNotification(ProgressNotification progressNotification)
: base(@"Task has completed!")
{
this.progressNotification = progressNotification;
Icon = FontAwesome.fa_check;
}
}
}

View File

@ -16,50 +16,91 @@ namespace osu.Game.Overlays.Notifications
{
public class ProgressNotification : Notification, IHasCompletionTarget
{
private string text;
private float progress;
public float Progress
public string Text
{
get { return progress; }
get { return textDrawable.Text; }
set
{
Debug.Assert(state == ProgressNotificationState.Active);
progress = value;
progressBar.Progress = progress;
textDrawable.Text = value;
}
}
public ProgressNotificationState State
public float Progress
{
get { return progressBar.Progress; }
set
{
progressBar.Progress = value;
}
}
protected override void LoadComplete()
{
base.LoadComplete();
//we may have received changes before we were displayed.
State = state;
}
public virtual ProgressNotificationState State
{
get { return state; }
set
{
bool stateChanged = state != value;
state = value;
switch (state)
if (IsLoaded)
{
case ProgressNotificationState.Queued:
Light.Colour = colourQueued;
Light.Pulsate = false;
progressBar.Active = false;
break;
case ProgressNotificationState.Active:
Light.Colour = colourActive;
Light.Pulsate = true;
progressBar.Active = true;
break;
case ProgressNotificationState.Cancelled:
Light.Colour = colourCancelled;
Light.Pulsate = false;
progressBar.Active = false;
break;
switch (state)
{
case ProgressNotificationState.Queued:
Light.Colour = colourQueued;
Light.Pulsate = false;
progressBar.Active = false;
break;
case ProgressNotificationState.Active:
Light.Colour = colourActive;
Light.Pulsate = true;
progressBar.Active = true;
break;
case ProgressNotificationState.Cancelled:
Light.Colour = colourCancelled;
Light.Pulsate = false;
progressBar.Active = false;
break;
}
}
if (stateChanged)
{
switch (state)
{
case ProgressNotificationState.Completed:
NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint);
FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run.
Delay(100);
Schedule(Completed);
break;
}
}
}
}
private ProgressNotificationState state;
public Action Completed;
protected virtual Notification CreateCompletionNotification() => new ProgressCompletionNotification(this)
{
Activated = CompletionClickAction,
Text = $"Task \"{Text}\" has completed!"
};
protected virtual void Completed()
{
Expire();
CompletionTarget?.Invoke(CreateCompletionNotification());
}
public override bool DisplayOnTop => false;
@ -68,30 +109,21 @@ namespace osu.Game.Overlays.Notifications
private Color4 colourActive;
private Color4 colourCancelled;
public ProgressNotification(string text)
{
this.text = text;
}
private SpriteText textDrawable;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
public ProgressNotification()
{
colourQueued = colours.YellowDark;
colourActive = colours.Blue;
colourCancelled = colours.Red;
IconContent.Add(new Box
{
RelativeSizeAxes = Axes.Both,
});
Content.Add(new SpriteText
Content.Add(textDrawable = new SpriteText
{
TextSize = 16,
Colour = OsuColour.Gray(128),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Text = text
});
NotificationContent.Add(progressBar = new ProgressBar
@ -104,21 +136,12 @@ namespace osu.Game.Overlays.Notifications
State = ProgressNotificationState.Queued;
}
public void Complete()
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Debug.Assert(state != ProgressNotificationState.Completed);
state = ProgressNotificationState.Completed;
NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint);
FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run.
Delay(100);
Schedule(() =>
{
CompletionTarget?.Invoke(new ProgressCompletionNotification(this));
base.Close();
});
colourQueued = colours.YellowDark;
colourActive = colours.Blue;
colourCancelled = colours.Red;
}
public override void Close()
@ -135,8 +158,16 @@ namespace osu.Game.Overlays.Notifications
}
}
/// <summary>
/// The function to post completion notifications back to.
/// </summary>
public Action<Notification> CompletionTarget { get; set; }
/// <summary>
/// An action to complete when the completion notification is clicked.
/// </summary>
public Func<bool> CompletionClickAction;
class ProgressBar : Container
{
private Box box;
@ -175,7 +206,7 @@ namespace osu.Game.Overlays.Notifications
{
colourActive = colours.Blue;
Colour = colourInactive = OsuColour.Gray(0.5f);
Height = 5;
Children = new[]

View File

@ -12,14 +12,31 @@ namespace osu.Game.Overlays.Notifications
public class SimpleNotification : Notification
{
private string text;
public SimpleNotification(string text)
public string Text
{
this.text = text;
get { return text; }
set
{
text = value;
textDrawable.Text = text;
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private FontAwesome icon = FontAwesome.fa_info_circle;
public FontAwesome Icon
{
get { return icon; }
set
{
icon = value;
iconDrawable.Icon = icon;
}
}
private SpriteText textDrawable;
private TextAwesome iconDrawable;
public SimpleNotification()
{
IconContent.Add(new Drawable[]
{
@ -28,14 +45,14 @@ namespace osu.Game.Overlays.Notifications
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.5f))
},
new TextAwesome
iconDrawable = new TextAwesome
{
Anchor = Anchor.Centre,
Icon = FontAwesome.fa_info_circle,
Icon = icon ,
}
});
Content.Add(new SpriteText
Content.Add(textDrawable = new SpriteText
{
TextSize = 16,
Colour = OsuColour.Gray(128),
@ -43,7 +60,11 @@ namespace osu.Game.Overlays.Notifications
RelativeSizeAxes = Axes.X,
Text = text
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Light.Colour = colours.Green;
}