1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 22:02:56 +08:00

Merge branch 'master' into osb_loading

This commit is contained in:
Thomas Müller 2017-02-12 12:26:25 +01:00 committed by GitHub
commit e3f35cd66e
48 changed files with 1685 additions and 87 deletions

@ -1 +1 @@
Subproject commit 21fd81a84860cf6854026458ac82905b6248f41d
Subproject commit e776f6f2729bbe93206c4e8c089eeca57522fcf7

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Desktop.VisualTests;
using osu.Framework.Desktop.Platform;
using osu.Game.Modes;
using osu.Game.Modes.Catch;
using osu.Game.Modes.Mania;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Taiko;
namespace osu.Desktop.Tests
{
[TestFixture]
public class BenchmarkTest
{
[Test]
public void TestBenchmark()
{
using (var host = new HeadlessGameHost())
{
Ruleset.Register(new OsuRuleset());
Ruleset.Register(new TaikoRuleset());
Ruleset.Register(new ManiaRuleset());
Ruleset.Register(new CatchRuleset());
host.Add(new Benchmark());
host.Run();
}
}
}
}

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

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Desktop.Tests</RootNamespace>
<AssemblyName>osu.Desktop.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="Newtonsoft.Json">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SQLiteNetExtensions">
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
</Reference>
<Reference Include="SQLite.Net.Platform.Win32">
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll</HintPath>
</Reference>
<Reference Include="SQLite.Net.Platform.Generic">
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll</HintPath>
</Reference>
<Reference Include="OpenTK">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1339\lib\net45\OpenTK.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BenchmarkTest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework.Desktop\osu.Framework.Desktop.csproj">
<Project>{65DC628F-A640-4111-AB35-3A5652BC1E17}</Project>
<Name>osu.Framework.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Desktop.VisualTests\osu.Desktop.VisualTests.csproj">
<Project>{69051C69-12AE-4E7D-A3E6-460D2E282312}</Project>
<Name>osu.Desktop.VisualTests</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Catch\osu.Game.Modes.Catch.csproj">
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
<Name>osu.Game.Modes.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj">
<Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project>
<Name>osu.Game.Modes.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Modes.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Taiko\osu.Game.Modes.Taiko.csproj">
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Modes.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
<Name>osu.Game</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="NUnit" version="3.5.0" targetFramework="net45" />
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
</packages>

View File

@ -0,0 +1,56 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Desktop.Platform;
using osu.Framework.GameModes.Testing;
using osu.Game;
using osu.Game.Modes;
using osu.Game.Modes.Catch;
using osu.Game.Modes.Mania;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Taiko;
namespace osu.Desktop.VisualTests
{
public class Benchmark : OsuGameBase
{
private double timePerTest = 200;
[BackgroundDependencyLoader]
private void load(BaseGame game)
{
Host.MaximumDrawHz = int.MaxValue;
Host.MaximumUpdateHz = int.MaxValue;
Host.MaximumInactiveHz = int.MaxValue;
}
protected override void LoadComplete()
{
base.LoadComplete();
TestBrowser f = new TestBrowser();
Add(f);
Console.WriteLine($@"{Time}: Running {f.TestCount} tests for {timePerTest}ms each...");
for (int i = 1; i < f.TestCount; i++)
{
int loadableCase = i;
Scheduler.AddDelayed(delegate
{
f.LoadTest(loadableCase);
Console.WriteLine($@"{Time}: Switching to test #{loadableCase}");
}, loadableCase * timePerTest);
}
Scheduler.AddDelayed(Host.Exit, f.TestCount * timePerTest);
}
}
}

View File

@ -18,6 +18,8 @@ namespace osu.Desktop.VisualTests
[STAThread]
public static void Main(string[] args)
{
bool benchmark = args.Length > 0 && args[0] == @"-benchmark";
using (BasicGameHost host = Host.GetSuitableHost(@"osu"))
{
Ruleset.Register(new OsuRuleset());
@ -25,7 +27,10 @@ namespace osu.Desktop.VisualTests
Ruleset.Register(new ManiaRuleset());
Ruleset.Register(new CatchRuleset());
host.Add(new VisualTestGame());
if (benchmark)
host.Add(new Benchmark());
else
host.Add(new VisualTestGame());
host.Run();
}
}

View File

@ -0,0 +1,121 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.GameModes.Testing;
using osu.Framework.MathUtils;
using osu.Framework.Timing;
using osu.Game.Overlays;
using System.Linq;
using osu.Game.Overlays.Notifications;
using osu.Game.Screens.Backgrounds;
namespace osu.Desktop.VisualTests.Tests
{
class TestCaseNotificationManager : TestCase
{
public override string Name => @"Notification Manager";
public override string Description => @"I handle notifications";
NotificationManager manager;
public override void Reset()
{
base.Reset();
progressingNotifications.Clear();
AddInternal(new BackgroundModeDefault() { Depth = 10 });
Content.Add(manager = new NotificationManager
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
});
AddToggle(@"show", manager.ToggleVisibility);
AddButton(@"simple #1", sendNotification1);
AddButton(@"simple #2", sendNotification2);
AddButton(@"progress #1", sendProgress1);
AddButton(@"progress #2", sendProgress2);
AddButton(@"barrage", () => sendBarrage());
}
private void sendBarrage(int remaining = 100)
{
switch (RNG.Next(0, 4))
{
case 0:
sendNotification1();
break;
case 1:
sendNotification2();
break;
case 2:
sendProgress1();
break;
case 3:
sendProgress2();
break;
}
if (remaining > 0)
{
Delay(80);
Schedule(() => sendBarrage(remaining - 1));
}
}
protected override void Update()
{
base.Update();
progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed);
while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
{
var p = progressingNotifications.FirstOrDefault(n => n.IsLoaded && n.State == ProgressNotificationState.Queued);
if (p == null)
break;
p.State = ProgressNotificationState.Active;
}
foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active))
{
if (n.Progress < 1)
n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle();
else
n.State = ProgressNotificationState.Completed;
}
}
private void sendProgress2()
{
var n = new ProgressNotification { Text = @"Downloading Haitai..." };
manager.Post(n);
progressingNotifications.Add(n);
}
List<ProgressNotification> progressingNotifications = new List<ProgressNotification>();
private void sendProgress1()
{
var n = new ProgressNotification { Text = @"Uploading to BSS..." };
manager.Post(n);
progressingNotifications.Add(n);
}
private void sendNotification2()
{
manager.Post(new SimpleNotification { Text = @"You are amazing" });
}
private void sendNotification1()
{
manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" });
}
}
}

View File

@ -10,7 +10,6 @@ using osu.Framework.Desktop.Platform;
using System.Reflection;
using System.IO;
using System.Collections.Generic;
using SQLiteNetExtensions.Extensions;
using osu.Framework.Allocation;
namespace osu.Desktop.VisualTests

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<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

@ -59,6 +59,7 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -73,6 +74,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<Win32Resource>
@ -100,13 +102,12 @@
<Reference Include="OpenTK">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1339\lib\net45\OpenTK.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
</None>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="OpenTK.dll.config" />
</ItemGroup>
@ -172,10 +173,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Benchmark.cs" />
<Compile Include="Program.cs" />
<Compile Include="Tests\TestCaseChatDisplay.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" />
<Compile Include="Tests\TestCaseNotificationManager.cs" />
<Compile Include="Tests\TestCasePlayer.cs" />
<Compile Include="Tests\TestCaseHitObjects.cs" />
<Compile Include="Tests\TestCaseKeyCounter.cs" />

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<packages>
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1339" targetFramework="net45" />
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<packages>
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1339" targetFramework="net45" />
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
</packages>

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

@ -59,6 +59,7 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<Commandlineparameters>
</Commandlineparameters>
</PropertyGroup>
@ -75,21 +76,76 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<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>
@ -155,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

@ -20,6 +20,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -28,6 +29,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">

View File

@ -20,6 +20,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -28,6 +29,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">

View File

@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -29,6 +30,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">

View File

@ -20,6 +20,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -28,6 +29,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">

View File

@ -18,6 +18,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
@ -25,6 +26,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">

View File

@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps
{
if (background != null) return background;
if (BeatmapInfo.Metadata?.BackgroundFile == null) return null;
if (BeatmapInfo?.Metadata?.BackgroundFile == null) return null;
try
{

View File

@ -83,65 +83,67 @@ 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
};
}
var beatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
Beatmaps = new List<BeatmapInfo>(),
Path = path,
Hash = hash,
Metadata = metadata
};
using (var reader = ArchiveReader.GetReader(storage, path))
using (var reader = ArchiveReader.GetReader(storage, path))
{
string[] mapNames = reader.ReadBeatmaps();
foreach (var name in mapNames)
{
string[] mapNames = reader.ReadBeatmaps();
foreach (var name in mapNames)
using (var stream = new StreamReader(reader.GetStream(name)))
{
using (var stream = new StreamReader(reader.GetStream(name)))
{
var decoder = BeatmapDecoder.GetDecoder(stream);
Beatmap beatmap = decoder.Decode(stream);
beatmap.BeatmapInfo.Path = 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;
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
beatmap.BeatmapInfo.Metadata = null;
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
}
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
}
beatmapSet.StoryboardFile = reader.ReadStoryboard();
}
Import(new[] { beatmapSet });
}
Import(new[] { beatmapSet });
}
public void Import(IEnumerable<BeatmapSetInfo> beatmapSets)

View File

@ -45,7 +45,8 @@ namespace osu.Game.Graphics.Containers
{
base.Update();
content.MoveTo((ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
Vector2 offset = input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2;
content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
content.Scale = new Vector2(1 + ParallaxAmount);
firstUpdate = false;

View File

@ -67,6 +67,11 @@ namespace osu.Game.Graphics.Cursor
Masking = true,
BorderThickness = Size.X / 6,
BorderColour = Color4.White,
EdgeEffect = new EdgeEffect {
Type = EdgeEffectType.Shadow,
Colour = Color4.Pink.Opacity(0.5f),
Radius = 5,
},
Children = new Drawable[]
{
new Box

View File

@ -9,7 +9,7 @@ using OpenTK.Graphics;
namespace osu.Game.Graphics.Sprites
{
class OsuSpriteText : SpriteText
public class OsuSpriteText : SpriteText
{
public const float FONT_SIZE = 16;

View File

@ -13,7 +13,7 @@ using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
class Nub : CircularContainer, IStateful<CheckBoxState>
public class Nub : CircularContainer, IStateful<CheckBoxState>
{
public const float COLLAPSED_SIZE = 20;
public const float EXPANDED_SIZE = 40;

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
{
@ -35,6 +36,8 @@ namespace osu.Game
private MusicController musicController;
private NotificationManager notificationManager;
private MainMenu mainMenu => modeStack?.ChildGameMode as MainMenu;
private Intro intro => modeStack as Intro;
@ -65,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); });
}
@ -117,8 +123,16 @@ namespace osu.Game
Origin = Anchor.TopRight,
}).Preload(this, overlayContent.Add);
(notificationManager = new NotificationManager
{
Depth = -2,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}).Preload(this, overlayContent.Add);
Dependencies.Cache(options);
Dependencies.Cache(musicController);
Dependencies.Cache(notificationManager);
(Toolbar = new Toolbar
{

View File

@ -240,7 +240,6 @@ namespace osu.Game.Overlays
if (current?.TrackLoaded ?? false)
{
progress.UpdatePosition((float)(current.Track.CurrentTime / current.Track.Length));
playButton.Icon = current.Track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o;

View File

@ -0,0 +1,113 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Game.Graphics;
using osu.Game.Overlays.Notifications;
using OpenTK.Graphics;
namespace osu.Game.Overlays
{
public class NotificationManager : FocusedOverlayContainer
{
private const float width = 320;
public const float TRANSITION_LENGTH = 600;
private ScrollContainer scrollContainer;
private FlowContainer<NotificationSection> sections;
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours)
{
Width = width;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.6f,
},
scrollContainer = new ScrollContainer()
{
Margin = new MarginPadding { Top = Toolbar.Toolbar.HEIGHT },
Children = new[]
{
sections = new FlowContainer<NotificationSection>
{
Direction = FlowDirection.VerticalOnly,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Children = new []
{
new NotificationSection
{
Title = @"Notifications",
ClearText = @"Clear All",
AcceptTypes = new [] { typeof(SimpleNotification) },
},
new NotificationSection
{
Title = @"Running Tasks",
ClearText = @"Cancel All",
AcceptTypes = new [] { typeof(ProgressNotification) },
},
}
}
}
}
};
}
int runningDepth = 0;
public void Post(Notification notification)
{
State = Visibility.Visible;
++runningDepth;
notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth;
var hasCompletionTarget = notification as IHasCompletionTarget;
if (hasCompletionTarget != null)
hasCompletionTarget.CompletionTarget = Post;
var ourType = notification.GetType();
sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => ourType == accept || ourType.IsSubclassOf(accept)))?.Add(notification);
}
protected override void PopIn()
{
base.PopIn();
scrollContainer.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint);
MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint);
FadeTo(1, TRANSITION_LENGTH / 2);
}
private void markAllRead()
{
sections.Children.ForEach(s => s.MarkAllRead());
}
protected override void PopOut()
{
base.PopOut();
markAllRead();
MoveToX(width, TRANSITION_LENGTH, EasingTypes.OutQuint);
FadeTo(0, TRANSITION_LENGTH / 2);
}
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Overlays.Notifications
{
public interface IHasCompletionTarget
{
Action<Notification> CompletionTarget { get; set; }
}
}

View File

@ -0,0 +1,284 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Framework.Input;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Overlays.Notifications
{
public abstract class Notification : Container
{
/// <summary>
/// Use requested close.
/// </summary>
public Action Closed;
/// <summary>
/// Run on user activating the notification. Return true to close.
/// </summary>
public Func<bool> Activated;
/// <summary>
/// Should we show at the top of our section on display?
/// </summary>
public virtual bool DisplayOnTop => true;
protected NotificationLight Light;
private CloseButton closeButton;
protected Container IconContent;
private Container content;
protected override Container<Drawable> Content => content;
protected Container NotificationContent;
private bool read;
public virtual bool Read
{
get { return read; }
set
{
read = value;
}
}
public Notification()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
AddInternal(new Drawable[]
{
Light = new NotificationLight
{
Margin = new MarginPadding { Right = 5 },
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreRight,
},
NotificationContent = new Container
{
CornerRadius = 8,
Masking = true,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
},
new Container
{
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding(5),
Height = 60,
Children = new Drawable[]
{
IconContent = new Container
{
Size = new Vector2(40),
Colour = Color4.DarkGray,
Masking = true,
CornerRadius = 5,
},
content = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Top = 5,
Left = 45,
Right = 30
},
}
}
},
closeButton = new CloseButton
{
Alpha = 0,
Action = Close,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding
{
Right = 5
},
}
}
}
});
}
protected override bool OnHover(InputState state)
{
closeButton.FadeIn(75);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
closeButton.FadeOut(75);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
if (Activated?.Invoke() ?? true)
Close();
return true;
}
protected override void LoadComplete()
{
base.LoadComplete();
FadeInFromZero(200);
NotificationContent.MoveToX(DrawSize.X);
NotificationContent.MoveToX(0, 500, EasingTypes.OutQuint);
}
private bool wasClosed;
public virtual void Close()
{
if (wasClosed) return;
wasClosed = true;
Closed?.Invoke();
FadeOut(100);
Expire();
}
class CloseButton : ClickableContainer
{
private Color4 hoverColour;
public CloseButton()
{
Colour = OsuColour.Gray(0.2f);
AutoSizeAxes = Axes.Both;
Children = new[]
{
new TextAwesome
{
Anchor = Anchor.Centre,
Icon = FontAwesome.fa_times_circle,
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
hoverColour = colours.Yellow;
}
protected override bool OnHover(InputState state)
{
FadeColour(hoverColour, 200);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
FadeColour(OsuColour.Gray(0.2f), 200);
base.OnHoverLost(state);
}
}
public class NotificationLight : Container
{
private bool pulsate;
private Container pulsateLayer;
public bool Pulsate
{
get { return pulsate; }
set
{
pulsate = value;
pulsateLayer.ClearTransformations();
pulsateLayer.Alpha = 1;
if (pulsate)
{
const float length = 1000;
pulsateLayer.Transforms.Add(new TransformAlpha
{
StartTime = Time.Current,
EndTime = Time.Current + length,
StartValue = 1,
EndValue = 0.4f,
Easing = EasingTypes.In
});
pulsateLayer.Transforms.Add(new TransformAlpha
{
StartTime = Time.Current + length,
EndTime = Time.Current + length * 2,
StartValue = 0.4f,
EndValue = 1,
Easing = EasingTypes.Out
});
//todo: figure why we can't add arbitrary delays at the end of loop.
pulsateLayer.Loop(length * 2);
}
}
}
public new SRGBColour Colour
{
set
{
base.Colour = value;
pulsateLayer.EdgeEffect = new EdgeEffect
{
Colour = ((Color4)value).Opacity(0.5f), //todo: avoid cast
Type = EdgeEffectType.Glow,
Radius = 12,
Roundness = 12,
};
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Size = new Vector2(6, 15);
Children = new[]
{
pulsateLayer = new CircularContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Masking = true,
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
},
}
}
};
}
}
}
}

View File

@ -0,0 +1,162 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Transformations;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Overlays.Notifications
{
public class NotificationSection : FlowContainer
{
private OsuSpriteText titleText;
private OsuSpriteText countText;
private ClearAllButton clearButton;
private FlowContainer<Notification> notifications;
public void Add(Notification notification)
{
notifications.Add(notification);
}
public IEnumerable<Type> AcceptTypes;
private string clearText;
public string ClearText
{
get { return clearText; }
set
{
clearText = value;
if (clearButton != null) clearButton.Text = clearText;
}
}
private string title;
public string Title
{
get { return title; }
set
{
title = value;
if (titleText != null) titleText.Text = title.ToUpper();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FlowDirection.VerticalOnly;
Padding = new MarginPadding
{
Top = 10,
Bottom = 5,
Right = 20,
Left = 20,
};
AddInternal(new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
clearButton = new ClearAllButton
{
Text = clearText,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Action = clearAll
},
new FlowContainer
{
Margin = new MarginPadding
{
Bottom = 5
},
Spacing = new Vector2(5, 0),
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
titleText = new OsuSpriteText
{
Text = title.ToUpper(),
Font = @"Exo2.0-Black",
},
countText = new OsuSpriteText
{
Text = "3",
Colour = colours.Yellow,
Font = @"Exo2.0-Black",
},
}
},
},
},
notifications = new FlowContainer<Notification>
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
LayoutDuration = 150,
LayoutEasing = EasingTypes.OutQuart,
Spacing = new Vector2(3),
}
});
}
private void clearAll()
{
notifications.Children.ForEach(c => c.Close());
}
protected override void Update()
{
base.Update();
countText.Text = notifications.Children.Count(c => c.Alpha > 0.99f).ToString();
}
class ClearAllButton : ClickableContainer
{
private OsuSpriteText text;
public ClearAllButton()
{
AutoSizeAxes = Axes.Both;
Children = new[]
{
text = new OsuSpriteText()
};
}
public string Text
{
get { return text.Text; }
set { text.Text = value.ToUpper(); }
}
}
public void MarkAllRead()
{
notifications.Children.ForEach(n => n.Read = true);
}
}
}

View File

@ -0,0 +1,18 @@
// 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
{
private ProgressNotification progressNotification;
public ProgressCompletionNotification(ProgressNotification progressNotification)
{
this.progressNotification = progressNotification;
Icon = FontAwesome.fa_check;
}
}
}

View File

@ -0,0 +1,231 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Overlays.Notifications
{
public class ProgressNotification : Notification, IHasCompletionTarget
{
public string Text
{
get { return textDrawable.Text; }
set
{
textDrawable.Text = value;
}
}
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;
if (IsLoaded)
{
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;
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;
private ProgressBar progressBar;
private Color4 colourQueued;
private Color4 colourActive;
private Color4 colourCancelled;
private SpriteText textDrawable;
public ProgressNotification()
{
IconContent.Add(new Box
{
RelativeSizeAxes = Axes.Both,
});
Content.Add(textDrawable = new SpriteText
{
TextSize = 16,
Colour = OsuColour.Gray(128),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
});
NotificationContent.Add(progressBar = new ProgressBar
{
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
});
State = ProgressNotificationState.Queued;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
colourQueued = colours.YellowDark;
colourActive = colours.Blue;
colourCancelled = colours.Red;
}
public override void Close()
{
switch (State)
{
case ProgressNotificationState.Cancelled:
base.Close();
break;
case ProgressNotificationState.Active:
case ProgressNotificationState.Queued:
State = ProgressNotificationState.Cancelled;
break;
}
}
/// <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;
private Color4 colourActive;
private Color4 colourInactive;
private float progress;
public float Progress
{
get { return progress; }
set
{
if (progress == value) return;
progress = value;
box.ResizeTo(new Vector2(progress, 1), 100, EasingTypes.OutQuad);
}
}
private bool active;
public bool Active
{
get { return active; }
set
{
active = value;
FadeColour(active ? colourActive : colourInactive, 100);
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
colourActive = colours.Blue;
Colour = colourInactive = OsuColour.Gray(0.5f);
Height = 5;
Children = new[]
{
box = new Box
{
RelativeSizeAxes = Axes.Both,
Width = 0,
}
};
}
}
}
public enum ProgressNotificationState
{
Queued,
Active,
Completed,
Cancelled
}
}

View File

@ -0,0 +1,87 @@
// 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.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
namespace osu.Game.Overlays.Notifications
{
public class SimpleNotification : Notification
{
private string text;
public string Text
{
get { return text; }
set
{
text = value;
textDrawable.Text = text;
}
}
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[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.5f))
},
iconDrawable = new TextAwesome
{
Anchor = Anchor.Centre,
Icon = icon ,
}
});
Content.Add(textDrawable = new SpriteText
{
TextSize = 16,
Colour = OsuColour.Gray(128),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Text = text
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Light.Colour = colours.Green;
}
public override bool Read
{
get
{
return base.Read;
}
set
{
if (base.Read = value)
Light.FadeOut(100);
else
Light.FadeIn(100);
}
}
}
}

View File

@ -71,7 +71,14 @@ namespace osu.Game.Overlays.Options
{
items = value;
if(dropdown != null)
{
dropdown.Items = value;
// We need to refresh the dropdown because our items changed,
// thus its selected value may be outdated.
if (bindable != null)
dropdown.SelectedValue = bindable.Value;
}
}
}

View File

@ -14,6 +14,7 @@ namespace osu.Game.Overlays.Options.Sections.Audio
protected override string Header => "Devices";
private AudioManager audio;
private OptionDropDown<string> dropdown;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
@ -21,21 +22,45 @@ namespace osu.Game.Overlays.Options.Sections.Audio
this.audio = audio;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
audio.OnNewDevice -= onDeviceChanged;
audio.OnLostDevice -= onDeviceChanged;
}
private void updateItems()
{
var deviceItems = new List<KeyValuePair<string, string>>();
deviceItems.Add(new KeyValuePair<string, string>("Default", string.Empty));
deviceItems.AddRange(audio.AudioDeviceNames.Select(d => new KeyValuePair<string, string>(d, d)));
var preferredDeviceName = audio.AudioDevice.Value;
if (!deviceItems.Any(kv => kv.Value == preferredDeviceName))
deviceItems.Add(new KeyValuePair<string, string>(preferredDeviceName, preferredDeviceName));
dropdown.Items = deviceItems;
}
private void onDeviceChanged(string name) => updateItems();
protected override void LoadComplete()
{
base.LoadComplete();
var deviceItems = new List<KeyValuePair<string, string>>();
deviceItems.Add(new KeyValuePair<string, string>("Default", string.Empty));
deviceItems.AddRange(audio.GetDeviceNames().Select(d => new KeyValuePair<string, string>(d, d)));
Children = new Drawable[]
{
new OptionDropDown<string>()
dropdown = new OptionDropDown<string>()
{
Items = deviceItems,
Bindable = audio.AudioDevice
},
};
updateItems();
audio.OnNewDevice += onDeviceChanged;
audio.OnLostDevice += onDeviceChanged;
}
}
}

View File

@ -90,7 +90,7 @@ namespace osu.Game.Overlays
{
Text = "settings",
TextSize = 40,
Margin = new MarginPadding { Left = CONTENT_MARGINS, Top = 30 },
Margin = new MarginPadding { Left = CONTENT_MARGINS, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT },
},
new OsuSpriteText
{

View File

@ -17,6 +17,7 @@ namespace osu.Game.Overlays.Toolbar
public class Toolbar : OverlayContainer
{
public const float HEIGHT = 40;
public const float TOOLTIP_HEIGHT = 30;
public Action OnHome;
public Action<PlayMode> OnPlayModeChange;
@ -73,10 +74,7 @@ namespace osu.Game.Overlays.Toolbar
Icon = FontAwesome.fa_search
},
userArea = new ToolbarUserArea(),
new ToolbarButton
{
Icon = FontAwesome.fa_bars
},
new ToolbarNotificationButton(),
}
}
};

View File

@ -56,6 +56,8 @@ namespace osu.Game.Overlays.Toolbar
}
}
protected virtual Anchor TooltipAnchor => Anchor.TopLeft;
public Action Action;
protected TextAwesome DrawableIcon;
protected SpriteText DrawableText;
@ -107,19 +109,24 @@ namespace osu.Game.Overlays.Toolbar
{
Direction = FlowDirection.VerticalOnly,
RelativeSizeAxes = Axes.Both, //stops us being considered in parent's autosize
Anchor = Anchor.BottomLeft,
Position = new Vector2(5, 5),
Anchor = (TooltipAnchor & Anchor.x0) > 0 ? Anchor.BottomLeft : Anchor.BottomRight,
Origin = TooltipAnchor,
Position = new Vector2((TooltipAnchor & Anchor.x0) > 0 ? 5 : -5, 5),
Alpha = 0,
Children = new[]
{
tooltip1 = new OsuSpriteText
{
Anchor = TooltipAnchor,
Origin = TooltipAnchor,
Shadow = true,
TextSize = 22,
Font = @"Exo2.0-Bold",
},
tooltip2 = new OsuSpriteText
{
Anchor = TooltipAnchor,
Origin = TooltipAnchor,
Shadow = true,
TextSize = 16
}

View File

@ -0,0 +1,28 @@
// 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.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
namespace osu.Game.Overlays.Toolbar
{
class ToolbarNotificationButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
public ToolbarNotificationButton()
{
Icon = FontAwesome.fa_bars;
TooltipMain = "Notifications";
TooltipSub = "Waiting for 'ya";
}
[BackgroundDependencyLoader]
private void load(NotificationManager notificationManager)
{
StateContainer = notificationManager;
Action = notificationManager.ToggleVisibility;
}
}
}

View File

@ -84,7 +84,7 @@ namespace osu.Game.Screens.Backgrounds
[BackgroundDependencyLoader]
private void load()
{
Sprite.Texture = beatmap.Background;
Sprite.Texture = beatmap?.Background;
}
}
}

View File

@ -119,11 +119,11 @@ namespace osu.Game.Screens.Menu
buttonFlow.Add(buttonsTopLevel);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuGame game)
[BackgroundDependencyLoader(true)]
private void load(AudioManager audio, OsuGame game = null)
{
sampleOsuClick = audio.Sample.Get(@"Menu/menuhit");
toolbar = game.Toolbar;
toolbar = game?.Toolbar;
}
protected override void LoadComplete()

View File

@ -23,6 +23,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -31,6 +32,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@ -100,6 +102,13 @@
<Compile Include="Beatmaps\Timing\SampleChange.cs" />
<Compile Include="Beatmaps\Timing\TimingChange.cs" />
<Compile Include="Configuration\OsuConfigManager.cs" />
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
<Compile Include="Overlays\Notifications\Notification.cs" />
<Compile Include="Overlays\NotificationManager.cs" />
<Compile Include="Overlays\Notifications\NotificationSection.cs" />
<Compile Include="Overlays\Notifications\ProgressCompletionNotification.cs" />
<Compile Include="Overlays\Notifications\ProgressNotification.cs" />
<Compile Include="Overlays\Notifications\SimpleNotification.cs" />
<Compile Include="Overlays\Options\OptionDropDown.cs" />
<Compile Include="Overlays\Options\OptionLabel.cs" />
<Compile Include="Graphics\UserInterface\OsuDropDownHeader.cs" />
@ -107,6 +116,7 @@
<Compile Include="Graphics\UserInterface\OsuDropDownMenuItem.cs" />
<Compile Include="Overlays\Toolbar\ToolbarHomeButton.cs" />
<Compile Include="Overlays\Toolbar\ToolbarMusicButton.cs" />
<Compile Include="Overlays\Toolbar\ToolbarNotificationButton.cs" />
<Compile Include="Overlays\Toolbar\ToolbarSettingsButton.cs" />
<Compile Include="Overlays\Toolbar\ToolbarOverlayToggleButton.cs" />
<Compile Include="Overlays\Toolbar\ToolbarUserArea.cs" />

View File

@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Modes.Taiko", "osu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Modes.Mania", "osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop.Tests", "osu.Desktop.Tests\osu.Desktop.Tests.csproj", "{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -79,6 +81,10 @@ Global
{48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU
{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -95,6 +101,7 @@ Global
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
{F167E17A-7DE6-4AF5-B920-A5112296C695} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
{48F4582B-7687-4621-9CBE-5C24197CB536} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0