1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-30 11:57:24 +08:00

Merge remote-tracking branch 'refs/remotes/ppy/master'

This commit is contained in:
Shawdooow 2017-09-18 23:09:41 -04:00
commit 70a295764c
361 changed files with 8844 additions and 4155 deletions

6
NuGet.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="opentk-develop" value="https://www.myget.org/F/opentk-develop" />
</packageSources>
</configuration>

View File

@ -1,3 +1,4 @@
# 2017-09-14
clone_depth: 1 clone_depth: 1
version: '{branch}-{build}' version: '{branch}-{build}'
configuration: Debug configuration: Debug

@ -1 +1 @@
Subproject commit 5c22092e590d589927962b8d0173dae5f9b1405c Subproject commit 3f4545aae82650dc87cac7dd5df64e6e47918da1

@ -1 +1 @@
Subproject commit f6042e1cb37cfad6c879d0e1245f7880c7fcd5f5 Subproject commit a4418111f8ed2350a6fd46fe69258884f0757745

View File

@ -33,7 +33,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" /> <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.17.1.0" newVersion="0.17.1.0" /> <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>

View File

@ -17,8 +17,8 @@ namespace osu.Desktop.Deploy
{ {
internal static class Program internal static class Program
{ {
private const string nuget_path = @"packages\NuGet.CommandLine.3.5.0\tools\NuGet.exe"; private const string nuget_path = @"packages\NuGet.CommandLine.4.3.0\tools\NuGet.exe";
private const string squirrel_path = @"packages\squirrel.windows.1.5.2\tools\Squirrel.exe"; private const string squirrel_path = @"packages\squirrel.windows.1.7.8\tools\Squirrel.exe";
private const string msbuild_path = @"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe"; private const string msbuild_path = @"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe";
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"]; public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
@ -100,7 +100,7 @@ namespace osu.Desktop.Deploy
updateAssemblyInfo(version); updateAssemblyInfo(version);
write("Running build process..."); write("Running build process...");
runCommand(msbuild_path, $"/v:quiet /m /t:{TargetName.Replace('.', '_')} /p:OutputPath={stagingPath};Configuration=Release {SolutionName}.sln"); runCommand(msbuild_path, $"/v:quiet /m /t:{TargetName.Replace('.', '_')} /p:OutputPath={stagingPath};Targets=\"Clean;Build\";Configuration=Release {SolutionName}.sln");
write("Creating NuGet deployment package..."); write("Creating NuGet deployment package...");
runCommand(nuget_path, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}"); runCommand(nuget_path, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Desktop.Deploy</RootNamespace> <RootNamespace>osu.Desktop.Deploy</RootNamespace>
<AssemblyName>osu.Desktop.Deploy</AssemblyName> <AssemblyName>osu.Desktop.Deploy</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup> </PropertyGroup>
@ -66,22 +66,23 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SharpCompress, Version=0.17.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL"> <Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll</HintPath> <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath> <HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Squirrel, Version=1.7.5.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\Squirrel.dll</HintPath> <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />

View File

@ -6,9 +6,9 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
<packages> <packages>
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net452" /> <package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net452" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" /> <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" /> <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
<package id="NuGet.CommandLine" version="4.1.0" targetFramework="net452" developmentDependency="true" /> <package id="NuGet.CommandLine" version="4.3.0" targetFramework="net461" developmentDependency="true" />
<package id="SharpCompress" version="0.17.1" targetFramework="net452" /> <package id="SharpCompress" version="0.18.1" targetFramework="net461" />
<package id="Splat" version="2.0.0" targetFramework="net452" /> <package id="Splat" version="2.0.0" targetFramework="net452" />
<package id="squirrel.windows" version="1.7.5" targetFramework="net452" /> <package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
</packages> </packages>

View File

@ -0,0 +1,25 @@
<configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
<!-- XQuartz compatibility (X11 on Mac) -->
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>

View File

@ -1,20 +1,17 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Desktop.Platform; using osu.Framework.Desktop.Platform;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game; using osu.Game;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
[TestFixture]
public abstract class OsuTestCase : TestCase public abstract class OsuTestCase : TestCase
{ {
[Test]
public override void RunTest() public override void RunTest()
{ {
using (var host = new HeadlessGameHost()) using (var host = new HeadlessGameHost(realtime: false))
host.Run(new OsuTestCaseTestRunner(this)); host.Run(new OsuTestCaseTestRunner(this));
} }

View File

@ -12,50 +12,104 @@ namespace osu.Desktop.Tests.Visual
{ {
public override string Description => "BeatmapDetails tab of BeatmapDetailArea"; public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
private readonly BeatmapDetails details;
public TestCaseBeatmapDetails() public TestCaseBeatmapDetails()
{ {
BeatmapDetails details;
Add(details = new BeatmapDetails Add(details = new BeatmapDetails
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(150), Padding = new MarginPadding(150),
Beatmap = new BeatmapInfo });
AddStep("beatmap all metrics", () => details.Beatmap = new BeatmapInfo
{ {
Version = "VisualTest", Version = "All Metrics",
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
Source = "Some guy", Source = "osu!lazer",
Tags = "beatmap metadata example with a very very long list of tags and not much creativity", Tags = "this beatmap has all the metrics",
}, },
Difficulty = new BeatmapDifficulty Difficulty = new BeatmapDifficulty
{ {
CircleSize = 7, CircleSize = 7,
ApproachRate = 3.5f,
OverallDifficulty = 5.7f,
DrainRate = 1, DrainRate = 1,
OverallDifficulty = 5.7f,
ApproachRate = 3.5f,
}, },
StarDifficulty = 5.3f, StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 10), Ratings = Enumerable.Range(0, 10),
Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
}, },
}); });
AddRepeatStep("fail values", newRetryAndFailValues, 10); AddStep("beatmap ratings", () => details.Beatmap = new BeatmapInfo
}
private int lastRange = 1;
private void newRetryAndFailValues()
{ {
details.Beatmap.Metrics.Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6); Version = "Only Ratings",
details.Beatmap.Metrics.Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6); Metadata = new BeatmapMetadata
details.Beatmap = details.Beatmap; {
lastRange += 100; Source = "osu!lazer",
Tags = "this beatmap has ratings metrics but not retries or fails",
},
Difficulty = new BeatmapDifficulty
{
CircleSize = 6,
DrainRate = 9,
OverallDifficulty = 6,
ApproachRate = 6,
},
StarDifficulty = 4.8f,
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
},
});
AddStep("beatmap fails retries", () => details.Beatmap = new BeatmapInfo
{
Version = "Only Retries and Fails",
Metadata = new BeatmapMetadata
{
Source = "osu!lazer",
Tags = "this beatmap has retries and fails but no ratings",
},
Difficulty = new BeatmapDifficulty
{
CircleSize = 3.7f,
DrainRate = 6,
OverallDifficulty = 6,
ApproachRate = 7,
},
StarDifficulty = 2.91f,
Metrics = new BeatmapMetrics
{
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
});
AddStep("beatmap no metrics", () => details.Beatmap = new BeatmapInfo
{
Version = "No Metrics",
Metadata = new BeatmapMetadata
{
Source = "osu!lazer",
Tags = "this beatmap has no metrics",
},
Difficulty = new BeatmapDifficulty
{
CircleSize = 5,
DrainRate = 5,
OverallDifficulty = 5.5f,
ApproachRate = 6.5f,
},
StarDifficulty = 1.97f,
Metrics = new BeatmapMetrics(),
});
AddStep("null beatmap", () => details.Beatmap = null);
} }
} }
} }

View File

@ -69,28 +69,28 @@ namespace osu.Desktop.Tests.Visual
private class MyContextMenuContainer : Container, IHasContextMenu private class MyContextMenuContainer : Container, IHasContextMenu
{ {
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[] public MenuItem[] ContextMenuItems => new MenuItem[]
{ {
new OsuContextMenuItem(@"Some option"), new OsuMenuItem(@"Some option"),
new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted), new OsuMenuItem(@"Highlighted option", MenuItemType.Highlighted),
new OsuContextMenuItem(@"Another option"), new OsuMenuItem(@"Another option"),
new OsuContextMenuItem(@"Choose me please"), new OsuMenuItem(@"Choose me please"),
new OsuContextMenuItem(@"And me too"), new OsuMenuItem(@"And me too"),
new OsuContextMenuItem(@"Trying to fill"), new OsuMenuItem(@"Trying to fill"),
new OsuContextMenuItem(@"Destructive option", MenuItemType.Destructive), new OsuMenuItem(@"Destructive option", MenuItemType.Destructive),
}; };
} }
private class AnotherContextMenuContainer : Container, IHasContextMenu private class AnotherContextMenuContainer : Container, IHasContextMenu
{ {
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[] public MenuItem[] ContextMenuItems => new MenuItem[]
{ {
new OsuContextMenuItem(@"Simple option"), new OsuMenuItem(@"Simple option"),
new OsuContextMenuItem(@"Simple very very long option"), new OsuMenuItem(@"Simple very very long option"),
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint) }, new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint) }, new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint) }, new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint) }, new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
}; };
} }
} }

View File

@ -41,12 +41,14 @@ namespace osu.Desktop.Tests.Visual
{ {
new BeatmapSetInfo new BeatmapSetInfo
{ {
OnlineBeatmapSetID = 578332,
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
Title = @"OrVid", Title = @"OrVid",
Artist = @"An", Artist = @"An",
Author = @"RLC", Author = @"RLC",
Source = @"", Source = @"",
Tags = @"acuticnotes an-fillnote revid tear tearvid encrpted encryption axi axivid quad her hervid recoll",
}, },
OnlineInfo = new BeatmapSetOnlineInfo OnlineInfo = new BeatmapSetOnlineInfo
{ {
@ -71,12 +73,14 @@ namespace osu.Desktop.Tests.Visual
}, },
new BeatmapSetInfo new BeatmapSetInfo
{ {
OnlineBeatmapSetID = 599627,
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
Title = @"tiny lamp", Title = @"tiny lamp",
Artist = @"fhana", Artist = @"fhana",
Author = @"Sotarks", Author = @"Sotarks",
Source = @"ぎんぎつね", Source = @"ぎんぎつね",
Tags = @"lantis junichi sato yuxuki waga kevin mitsunaga towana gingitsune opening op full ver version kalibe collab collaboration",
}, },
OnlineInfo = new BeatmapSetOnlineInfo OnlineInfo = new BeatmapSetOnlineInfo
{ {
@ -101,12 +105,14 @@ namespace osu.Desktop.Tests.Visual
}, },
new BeatmapSetInfo new BeatmapSetInfo
{ {
OnlineBeatmapSetID = 513268,
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
Title = @"At Gwanghwamun", Title = @"At Gwanghwamun",
Artist = @"KYUHYUN", Artist = @"KYUHYUN",
Author = @"Cerulean Veyron", Author = @"Cerulean Veyron",
Source = @"", Source = @"",
Tags = @"soul ballad kh super junior sj suju 슈퍼주니어 kt뮤직 sm엔터테인먼트 s.m.entertainment kt music 1st mini album ep",
}, },
OnlineInfo = new BeatmapSetOnlineInfo OnlineInfo = new BeatmapSetOnlineInfo
{ {
@ -146,12 +152,14 @@ namespace osu.Desktop.Tests.Visual
}, },
new BeatmapSetInfo new BeatmapSetInfo
{ {
OnlineBeatmapSetID = 586841,
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
Title = @"RHAPSODY OF BLUE SKY", Title = @"RHAPSODY OF BLUE SKY",
Artist = @"fhana", Artist = @"fhana",
Author = @"[Kamiya]", Author = @"[Kamiya]",
Source = @"小林さんちのメイドラゴン", Source = @"小林さんちのメイドラゴン",
Tags = @"kobayashi san chi no maidragon aozora no opening anime maid dragon oblivion karen dynamix imoutosan pata-mon gxytcgxytc",
}, },
OnlineInfo = new BeatmapSetOnlineInfo OnlineInfo = new BeatmapSetOnlineInfo
{ {

View File

@ -0,0 +1,84 @@
// 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.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Menus;
namespace osu.Desktop.Tests.Visual
{
public class TestCaseEditorMenuBar : OsuTestCase
{
public TestCaseEditorMenuBar()
{
Add(new EditorMenuBar
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = 50,
Items = new[]
{
new EditorMenuBarItem("File")
{
Items = new[]
{
new EditorMenuItem("Clear All Notes"),
new EditorMenuItem("Open Difficulty..."),
new EditorMenuItem("Save"),
new EditorMenuItem("Create a new Difficulty..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Revert to Saved"),
new EditorMenuItem("Revert to Saved (Full)"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Test Beatmap"),
new EditorMenuItem("Open AiMod"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Upload Beatmap..."),
new EditorMenuItem("Export Package"),
new EditorMenuItem("Export Map Package"),
new EditorMenuItem("Import from..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Open Song Folder"),
new EditorMenuItem("Open .osu in Notepad"),
new EditorMenuItem("Open .osb in Notepad"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Exit"),
}
},
new EditorMenuBarItem("Timing")
{
Items = new[]
{
new EditorMenuItem("Time Signature"),
new EditorMenuItem("Metronome Clicks"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Add Timing Section"),
new EditorMenuItem("Add Inheriting Section"),
new EditorMenuItem("Reset Current Section"),
new EditorMenuItem("Delete Timing Section"),
new EditorMenuItem("Resnap Current Section"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Timing Setup"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
new EditorMenuItemSpacer(),
new EditorMenuItem("Set Current Position as Preview Point"),
}
},
new EditorMenuBarItem("Testing")
{
Items = new[]
{
new EditorMenuItem("Item 1"),
new EditorMenuItem("Item 2"),
new EditorMenuItem("Item 3"),
}
},
}
});
}
}
}

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using OpenTK; using OpenTK;
@ -110,10 +109,7 @@ namespace osu.Desktop.Tests.Visual
h.Depth = depth++; h.Depth = depth++;
if (auto) if (auto)
{
h.State = ArmedState.Hit; h.State = ArmedState.Hit;
h.Judgement = new OsuJudgement { Result = HitResult.Hit };
}
playfieldContainer.Add(h); playfieldContainer.Add(h);
var proxyable = h as IDrawableHitObjectWithProxiedApproach; var proxyable = h as IDrawableHitObjectWithProxiedApproach;

View File

@ -2,12 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
@ -41,38 +37,5 @@ namespace osu.Desktop.Tests.Visual
Add(kc); Add(kc);
} }
private class TestSliderBar<T> : SliderBar<T> where T : struct
{
public Color4 Color
{
get { return Box.Colour; }
set { Box.Colour = value; }
}
public Color4 SelectionColor
{
get { return SelectionBox.Colour; }
set { SelectionBox.Colour = value; }
}
protected readonly Box SelectionBox;
protected readonly Box Box;
public TestSliderBar()
{
Children = new Drawable[]
{
Box = new Box { RelativeSizeAxes = Axes.Both },
SelectionBox = new Box { RelativeSizeAxes = Axes.Both }
};
}
protected override void UpdateValue(float value)
{
SelectionBox.ScaleTo(
new Vector2(value, 1),
300, Easing.OutQuint);
}
}
} }
} }

View File

@ -1,13 +1,13 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users; using osu.Game.Users;
using OpenTK;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
@ -24,7 +24,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.XH, Rank = ScoreRank.XH,
Accuracy = 100, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -42,7 +42,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.X, Rank = ScoreRank.X,
Accuracy = 100, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -60,7 +60,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.SH, Rank = ScoreRank.SH,
Accuracy = 100, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -78,7 +78,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.S, Rank = ScoreRank.S,
Accuracy = 100, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -96,7 +96,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.A, Rank = ScoreRank.A,
Accuracy = 100, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -114,7 +114,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.B, Rank = ScoreRank.B,
Accuracy = 98.26, Accuracy = 0.9826,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -132,7 +132,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.C, Rank = ScoreRank.C,
Accuracy = 96.54, Accuracy = 0.9654,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -150,7 +150,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.F, Rank = ScoreRank.F,
Accuracy = 60.25, Accuracy = 0.6025,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -168,7 +168,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.F, Rank = ScoreRank.F,
Accuracy = 51.40, Accuracy = 0.5140,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@ -186,7 +186,7 @@ namespace osu.Desktop.Tests.Visual
new Score new Score
{ {
Rank = ScoreRank.F, Rank = ScoreRank.F,
Accuracy = 42.22, Accuracy = 0.4222,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },

View File

@ -3,6 +3,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using OpenTK; using OpenTK;
@ -40,8 +41,20 @@ namespace osu.Desktop.Tests.Visual
RelativeChildSize = new Vector2(1, 10000), RelativeChildSize = new Vector2(1, 10000),
Children = new[] Children = new[]
{ {
new DrawableNote(new Note { StartTime = 5000 }) { AccentColour = Color4.Red }, new DrawableNote(new Note(), ManiaAction.Key1)
new DrawableNote(new Note { StartTime = 6000 }) { AccentColour = Color4.Red } {
Y = 5000,
LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
},
new DrawableNote(new Note(), ManiaAction.Key1)
{
Y = 6000,
LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
}
} }
} }
} }
@ -62,11 +75,14 @@ namespace osu.Desktop.Tests.Visual
RelativeChildSize = new Vector2(1, 10000), RelativeChildSize = new Vector2(1, 10000),
Children = new[] Children = new[]
{ {
new DrawableHoldNote(new HoldNote new DrawableHoldNote(new HoldNote(), ManiaAction.Key1)
{ {
StartTime = 5000, Y = 5000,
Duration = 1000 Height = 1000,
}) { AccentColour = Color4.Red } LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
}
} }
} }
} }

View File

@ -3,108 +3,36 @@
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Configuration; using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Timing; using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.Timing;
using OpenTK; using osu.Game.Rulesets;
using OpenTK.Input; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
internal class TestCaseManiaPlayfield : OsuTestCase internal class TestCaseManiaPlayfield : OsuTestCase
{ {
private const double start_time = 500;
private const double duration = 500;
public override string Description => @"Mania playfield"; public override string Description => @"Mania playfield";
protected override double TimePerAction => 200; protected override double TimePerAction => 200;
private RulesetInfo maniaRuleset;
public TestCaseManiaPlayfield() public TestCaseManiaPlayfield()
{ {
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) => var rng = new Random(1337);
{
Clear();
Add(new ManiaPlayfield(cols)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
SpecialColumnPosition = pos,
Scale = new Vector2(1, -1)
});
};
const double start_time = 500;
const double duration = 500;
Func<double, bool, SpeedAdjustmentContainer> createTimingChange = (time, gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
{
TimingPoint = { BeatLength = 1000 }
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
Action<bool> createPlayfieldWithNotes = gravity =>
{
Clear();
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
ManiaPlayfield playField;
Add(playField = new ManiaPlayfield(4)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(1, -1),
Clock = new FramedClock(rateAdjustClock)
});
if (!gravity)
playField.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
for (double t = start_time; t <= start_time + duration; t += 100)
{
if (gravity)
playField.Columns.ElementAt(0).Add(createTimingChange(t, true));
playField.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 0
}, new Bindable<Key>(Key.D)));
if (gravity)
playField.Columns.ElementAt(3).Add(createTimingChange(t, true));
playField.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 3
}, new Bindable<Key>(Key.K)));
}
if (gravity)
playField.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
playField.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 1
}, new Bindable<Key>(Key.F)));
if (gravity)
playField.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
playField.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 2
}, new Bindable<Key>(Key.J)));
};
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal)); AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal)); AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
@ -114,29 +42,121 @@ namespace osu.Desktop.Tests.Visual
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal)); AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left)); AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right)); AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
AddStep("Reversed", () => createPlayfield(4, SpecialColumnPosition.Normal, true));
AddStep("Notes with input", () => createPlayfieldWithNotes(false)); AddStep("Notes with input", () => createPlayfieldWithNotes(false));
AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction)); AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(false, true));
AddStep("Notes with gravity", () => createPlayfieldWithNotes(true)); AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction)); AddStep("Notes with gravity (reversed)", () => createPlayfieldWithNotes(true, true));
}
private void triggerKeyDown(Column column) AddStep("Hit explosion", () =>
{ {
column.TriggerOnKeyDown(new InputState(), new KeyDownEventArgs var playfield = createPlayfield(4, SpecialColumnPosition.Normal);
int col = rng.Next(0, 4);
var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
{ {
Key = column.Key, AccentColour = playfield.Columns.ElementAt(col).AccentColour
Repeat = false };
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
}); });
} }
private void triggerKeyUp(Column column) [BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{ {
column.TriggerOnKeyUp(new InputState(), new KeyUpEventArgs maniaRuleset = rulesets.GetRuleset(3);
}
private SpeedAdjustmentContainer createTimingChange(double time, bool gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
{ {
Key = column.Key TimingPoint = { BeatLength = 1000 }
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
private ManiaPlayfield createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
{
Clear();
var inputManager = new ManiaInputManager(maniaRuleset, cols) { RelativeSizeAxes = Axes.Both };
Add(inputManager);
ManiaPlayfield playfield;
inputManager.Add(playfield = new ManiaPlayfield(cols)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
SpecialColumnPosition = specialPos
}); });
playfield.Inverted.Value = inverted;
return playfield;
}
private void createPlayfieldWithNotes(bool gravity, bool inverted = false)
{
Clear();
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
var inputManager = new ManiaInputManager(maniaRuleset, 4) { RelativeSizeAxes = Axes.Both };
Add(inputManager);
ManiaPlayfield playfield;
inputManager.Add(playfield = new ManiaPlayfield(4)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Clock = new FramedClock(rateAdjustClock)
});
playfield.Inverted.Value = inverted;
if (!gravity)
playfield.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
for (double t = start_time; t <= start_time + duration; t += 100)
{
if (gravity)
playfield.Columns.ElementAt(0).Add(createTimingChange(t, true));
playfield.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 0
}, ManiaAction.Key1));
if (gravity)
playfield.Columns.ElementAt(3).Add(createTimingChange(t, true));
playfield.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 3
}, ManiaAction.Key4));
}
if (gravity)
playfield.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
playfield.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 1
}, ManiaAction.Key2));
if (gravity)
playfield.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
playfield.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 2
}, ManiaAction.Key3));
} }
} }
} }

View File

@ -32,7 +32,7 @@ namespace osu.Desktop.Tests.Visual
backingDatabase.CreateTable<StoreVersion>(); backingDatabase.CreateTable<StoreVersion>();
rulesets = new RulesetStore(backingDatabase); rulesets = new RulesetStore(backingDatabase);
manager = new BeatmapManager(storage, null, backingDatabase, rulesets); manager = new BeatmapManager(storage, null, backingDatabase, rulesets, null);
for (int i = 0; i < 100; i += 10) for (int i = 0; i < 100; i += 10)
manager.Import(createTestBeatmapSet(i)); manager.Import(createTestBeatmapSet(i));

View File

@ -1,18 +1,18 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Desktop.Tests.Beatmaps; using osu.Desktop.Tests.Beatmaps;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Rulesets.Mods;
using System.Linq;
using osu.Game.Beatmaps.Formats;
using System.Text;
using System.IO;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
@ -33,55 +33,739 @@ namespace osu.Desktop.Tests.Visual
{ {
base.LoadComplete(); base.LoadComplete();
var objects = new List<HitObject>();
int time = 1500;
for (int i = 0; i < 50; i++)
{
objects.Add(new HitCircle
{
StartTime = time,
Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : OsuPlayfield.BASE_SIZE.X,
i % 4 < 2 ? 0 : OsuPlayfield.BASE_SIZE.Y),
NewCombo = i % 4 == 0
});
time += 500;
}
Beatmap b = new Beatmap
{
HitObjects = objects,
BeatmapInfo = new BeatmapInfo
{
Difficulty = new BeatmapDifficulty(),
Ruleset = rulesets.Query<RulesetInfo>().First(),
Metadata = new BeatmapMetadata
{
Artist = @"Unknown",
Title = @"Sample Beatmap",
Author = @"peppy",
}
}
};
WorkingBeatmap beatmap = new TestWorkingBeatmap(b);
Add(new Box Add(new Box
{ {
RelativeSizeAxes = Framework.Graphics.Axes.Both, RelativeSizeAxes = Framework.Graphics.Axes.Both,
Colour = Color4.Black, Colour = Color4.Black,
}); });
Add(Player = CreatePlayer(beatmap)); foreach (var r in rulesets.Query<RulesetInfo>())
AddStep(r.Name, () => loadPlayerFor(r));
loadPlayerFor(rulesets.Query<RulesetInfo>().First());
} }
protected virtual Player CreatePlayer(WorkingBeatmap beatmap) private void loadPlayerFor(RulesetInfo r)
{
Beatmap beatmap;
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data)))
using (var reader = new StreamReader(stream))
beatmap = BeatmapDecoder.GetDecoder(reader).Decode(reader);
beatmap.BeatmapInfo.Ruleset = r;
var instance = r.CreateInstance();
WorkingBeatmap working = new TestWorkingBeatmap(beatmap);
working.Mods.Value = new[] { instance.GetAllMods().First(m => m is ModNoFail) };
if (Player != null)
Remove(Player);
Add(Player = CreatePlayer(working, instance));
}
protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
{ {
return new Player return new Player
{ {
InitialBeatmap = beatmap InitialBeatmap = beatmap
}; };
} }
private const string test_beatmap_data =
@"osu file format v14
[General]
AudioLeadIn: 500
PreviewTime: 53498
Countdown: 0
SampleSet: Soft
StackLeniency: 0.7
Mode: 0
LetterboxInBreaks: 0
WidescreenStoryboard: 1
[Editor]
DistanceSpacing: 1.2
BeatDivisor: 4
GridSize: 4
TimelineZoom: 1
[Metadata]
Title:My Love
TitleUnicode:My Love
Artist:Kuba Oms
ArtistUnicode:Kuba Oms
Creator:W h i t e
Version:Hard
Source:ADHD
Tags:Monthly Beatmapping Contest Electronic folk pop w_h_i_t_e
BeatmapID:397534
BeatmapSetID:163112
[Difficulty]
HPDrainRate:5
CircleSize:4
OverallDifficulty:6
ApproachRate:7
SliderMultiplier:1.44
SliderTickRate:2
[Events]
//Break Periods
2,69870,83770
2,152170,158770
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Sound Samples
[TimingPoints]
2170,468.75,4,2,0,40,1,0
4045,-100,4,2,0,30,0,0
4162,-100,4,2,0,40,0,0
5920,-100,4,2,0,30,0,0
6037,-100,4,2,0,40,0,0
7795,-100,4,2,0,30,0,0
7912,-100,4,2,0,40,0,0
9670,-100,4,2,0,40,0,0
9787,-100,4,2,0,50,0,0
11545,-100,4,2,0,40,0,0
11662,-100,4,2,0,50,0,0
13420,-100,4,2,0,40,0,0
13537,-100,4,2,0,50,0,0
15295,-100,4,2,0,40,0,0
15412,-100,4,2,0,50,0,0
17170,-100,4,2,0,40,0,0
17287,-100,4,2,0,50,0,0
19045,-100,4,2,0,40,0,0
19162,-100,4,2,0,50,0,0
20920,-100,4,2,0,40,0,0
21037,-100,4,2,0,50,0,0
22795,-100,4,2,0,40,0,0
22912,-100,4,2,0,50,0,0
24670,-100,4,2,0,70,0,0
37560,-200,4,2,0,30,0,0
38263,-200,4,2,0,5,0,0
38966,-100,4,2,0,30,0,0
39670,-100,4,2,0,70,0,0
53732,-100,4,2,0,40,0,0
54670,-100,4,2,0,80,0,1
55138,-100,4,2,0,60,0,1
55255,-100,4,2,0,80,0,1
56076,-100,4,2,0,60,0,1
56193,-100,4,2,0,80,0,1
57013,-100,4,2,0,60,0,1
57130,-100,4,2,0,80,0,1
57951,-100,4,2,0,60,0,1
58068,-100,4,2,0,80,0,1
58888,-100,4,2,0,60,0,1
59005,-100,4,2,0,80,0,1
59826,-100,4,2,0,60,0,1
59943,-100,4,2,0,80,0,1
60763,-100,4,2,0,60,0,1
60880,-100,4,2,0,80,0,1
61701,-100,4,2,0,60,0,1
61818,-100,4,2,0,80,0,1
62638,-100,4,2,0,60,0,1
62755,-100,4,2,0,80,0,1
63576,-100,4,2,0,60,0,1
63693,-100,4,2,0,80,0,1
64513,-100,4,2,0,60,0,1
64630,-100,4,2,0,80,0,1
65451,-100,4,2,0,60,0,1
65568,-100,4,2,0,80,0,1
66388,-100,4,2,0,60,0,1
66505,-100,4,2,0,80,0,1
67326,-100,4,2,0,60,0,1
67443,-100,4,2,0,80,0,1
68263,-100,4,2,0,60,0,1
68380,-100,4,2,0,80,0,1
69201,-100,4,2,0,60,0,1
69318,-100,4,2,0,80,0,1
69670,-100,4,2,0,70,0,0
84670,-100,4,2,0,70,0,0
97560,-200,4,2,0,70,0,0
97795,-200,4,2,0,30,0,0
98966,-100,4,2,0,30,0,0
99670,-100,4,2,0,70,0,0
113732,-100,4,2,0,40,0,0
114670,-100,4,2,0,80,0,1
115138,-100,4,2,0,60,0,1
115255,-100,4,2,0,80,0,1
116076,-100,4,2,0,60,0,1
116193,-100,4,2,0,80,0,1
117013,-100,4,2,0,60,0,1
117130,-100,4,2,0,80,0,1
117951,-100,4,2,0,60,0,1
118068,-100,4,2,0,80,0,1
118888,-100,4,2,0,60,0,1
119005,-100,4,2,0,80,0,1
119826,-100,4,2,0,60,0,1
119943,-100,4,2,0,80,0,1
120763,-100,4,2,0,60,0,1
120880,-100,4,2,0,80,0,1
121701,-100,4,2,0,60,0,1
121818,-100,4,2,0,80,0,1
122638,-100,4,2,0,60,0,1
122755,-100,4,2,0,80,0,1
123576,-100,4,2,0,60,0,1
123693,-100,4,2,0,80,0,1
124513,-100,4,2,0,60,0,1
124630,-100,4,2,0,80,0,1
125451,-100,4,2,0,60,0,1
125568,-100,4,2,0,80,0,1
126388,-100,4,2,0,60,0,1
126505,-100,4,2,0,80,0,1
127326,-100,4,2,0,60,0,1
127443,-100,4,2,0,80,0,1
128263,-100,4,2,0,60,0,1
128380,-100,4,2,0,80,0,1
129201,-100,4,2,0,60,0,1
129318,-100,4,2,0,80,0,1
129670,-200,4,2,0,40,0,0
144670,-133.333333333333,4,2,0,40,0,0
159670,-133.333333333333,4,2,0,40,0,0
163420,-133.333333333333,4,2,0,45,0,0
163888,-125,4,2,0,50,0,0
164357,-117.647058823529,4,2,0,55,0,0
164826,-111.111111111111,4,2,0,60,0,0
165295,-105.263157894737,4,2,0,65,0,0
165763,-100,4,2,0,70,0,0
166232,-100,4,2,0,40,0,0
167170,-100,4,2,0,80,0,1
167638,-100,4,2,0,60,0,1
167755,-100,4,2,0,80,0,1
168576,-100,4,2,0,60,0,1
168693,-100,4,2,0,80,0,1
169513,-100,4,2,0,60,0,1
169630,-100,4,2,0,80,0,1
170451,-100,4,2,0,60,0,1
170568,-100,4,2,0,80,0,1
171388,-100,4,2,0,60,0,1
171505,-100,4,2,0,80,0,1
172326,-100,4,2,0,60,0,1
172443,-100,4,2,0,80,0,1
173263,-100,4,2,0,60,0,1
173380,-100,4,2,0,80,0,1
174201,-100,4,2,0,60,0,1
174318,-100,4,2,0,80,0,1
175138,-100,4,2,0,60,0,1
175255,-100,4,2,0,80,0,1
176076,-100,4,2,0,60,0,1
176193,-100,4,2,0,80,0,1
177013,-100,4,2,0,60,0,1
177130,-100,4,2,0,80,0,1
177951,-100,4,2,0,60,0,1
178068,-100,4,2,0,80,0,1
178888,-100,4,2,0,60,0,1
179005,-100,4,2,0,80,0,1
179826,-100,4,2,0,60,0,1
179943,-100,4,2,0,80,0,1
180763,-100,4,2,0,60,0,1
180880,-100,4,2,0,80,0,1
180998,-100,4,2,0,80,0,0
181466,-100,4,2,0,60,0,0
181584,-100,4,2,0,80,0,0
181935,-100,4,2,0,80,0,0
182170,-100,4,2,0,80,0,1
182638,-100,4,2,0,60,0,1
182755,-100,4,2,0,80,0,1
183576,-100,4,2,0,60,0,1
183693,-100,4,2,0,80,0,1
184513,-100,4,2,0,60,0,1
184630,-100,4,2,0,80,0,1
185451,-100,4,2,0,60,0,1
185568,-100,4,2,0,80,0,1
186388,-100,4,2,0,60,0,1
186505,-100,4,2,0,80,0,1
187326,-100,4,2,0,60,0,1
187443,-100,4,2,0,80,0,1
188263,-100,4,2,0,60,0,1
188380,-100,4,2,0,80,0,1
189201,-100,4,2,0,60,0,1
189318,-100,4,2,0,80,0,1
190138,-100,4,2,0,60,0,1
190255,-100,4,2,0,80,0,1
191076,-100,4,2,0,60,0,1
191193,-100,4,2,0,80,0,1
192013,-100,4,2,0,60,0,1
192130,-100,4,2,0,80,0,1
192951,-100,4,2,0,60,0,1
193068,-100,4,2,0,80,0,1
193888,-100,4,2,0,60,0,1
194005,-100,4,2,0,80,0,1
194826,-100,4,2,0,60,0,1
194943,-100,4,2,0,80,0,1
195295,-100,4,2,0,50,0,1
195529,-100,4,2,0,52,0,1
195646,-100,4,2,0,54,0,1
195763,-100,4,2,0,56,0,1
195880,-100,4,2,0,58,0,1
195998,-100,4,2,0,60,0,1
196115,-100,4,2,0,62,0,1
196232,-100,4,2,0,64,0,1
196349,-100,4,2,0,68,0,1
196466,-100,4,2,0,70,0,1
196584,-100,4,2,0,72,0,1
196701,-100,4,2,0,74,0,1
196818,-100,4,2,0,76,0,1
196935,-100,4,2,0,78,0,1
197052,-100,4,2,0,80,0,1
197170,-100,4,2,0,80,0,0
197873,-100,4,2,0,60,0,0
197990,-100,4,2,0,80,0,0
198341,-100,4,2,0,60,0,0
199045,-100,4,2,0,80,0,0
199279,-100,4,2,0,60,0,0
199630,-100,4,2,0,80,0,0
200216,-100,4,2,0,60,0,0
200334,-100,4,2,0,80,0,0
201623,-100,4,2,0,60,0,0
201740,-100,4,2,0,80,0,0
202326,-100,4,2,0,60,0,0
202443,-100,4,2,0,80,0,0
203029,-100,4,2,0,60,0,0
203498,-100,4,2,0,80,0,0
203966,-100,4,2,0,60,0,0
204201,-100,4,2,0,80,0,0
205373,-100,4,2,0,60,0,0
205490,-100,4,2,0,80,0,0
205841,-100,4,2,0,60,0,0
206076,-100,4,2,0,60,0,0
206545,-100,4,2,0,80,0,0
206779,-100,4,2,0,60,0,0
207130,-100,4,2,0,80,0,0
207716,-100,4,2,0,60,0,0
207951,-100,4,2,0,80,0,0
209123,-100,4,2,0,60,0,0
209240,-100,4,2,0,80,0,0
209826,-100,4,2,0,60,0,0
209943,-100,4,2,0,80,0,0
210529,-100,4,2,0,60,0,0
210880,-100,4,2,0,80,0,0
211232,-100,4,2,0,60,0,0
211701,-100,4,2,0,70,0,0
212170,-100,4,2,0,80,0,0
212873,-100,4,2,0,60,0,0
212990,-100,4,2,0,80,0,0
213341,-100,4,2,0,60,0,0
213576,-100,4,2,0,60,0,0
214045,-100,4,2,0,80,0,0
214279,-100,4,2,0,60,0,0
214630,-100,4,2,0,80,0,0
215216,-100,4,2,0,60,0,0
215451,-100,4,2,0,80,0,0
216623,-100,4,2,0,60,0,0
216740,-100,4,2,0,80,0,0
217326,-100,4,2,0,60,0,0
217443,-100,4,2,0,80,0,0
218029,-100,4,2,0,60,0,0
218498,-100,4,2,0,80,0,0
218732,-100,4,2,0,50,0,0
219670,-100,4,2,0,70,0,0
220138,-100,4,2,0,65,0,0
220373,-100,4,2,0,45,0,0
220490,-100,4,2,0,65,0,0
220607,-100,4,2,0,60,0,0
220841,-100,4,2,0,35,0,0
221076,-100,4,2,0,35,0,0
221545,-100,4,2,0,50,0,0
221779,-100,4,2,0,30,0,0
222013,-111.111111111111,4,2,0,25,0,0
222130,-111.111111111111,4,2,0,40,0,0
222482,-125,4,2,0,40,0,0
222716,-125,4,2,0,20,0,0
222951,-100,4,2,0,15,0,0
223420,-100,4,2,0,30,0,0
224357,-100,4,2,0,25,0,0
225295,-100,4,2,0,20,0,0
226232,-100,4,2,0,15,0,0
226701,-100,4,2,0,10,0,0
227170,-100,4,2,0,5,0,0
[Colours]
Combo1 : 17,254,176
Combo2 : 173,255,95
Combo3 : 255,88,100
Combo4 : 255,94,55
[HitObjects]
320,256,2170,6,0,P|256:284|192:256,1,144,4|0,0:0|0:0,0:0:0:0:
144,184,2873,1,0,0:0:0:0:
108,260,3107,2,0,P|112:296|100:336,1,72
28,288,3576,2,0,P|24:252|36:212,1,72,0|0,0:0|0:0,0:0:0:0:
76,140,4045,6,0,L|220:136,1,144,4|0,0:0|0:0,0:0:0:0:
292,88,4748,1,0,0:0:0:0:
292,88,4982,2,0,P|304:120|300:168,1,72
388,168,5451,2,0,P|396:133|416:103,1,72,0|0,0:0|0:0,0:0:0:0:
472,172,5920,6,0,B|470:200|457:222|457:222|488:256|476:308,1,144,4|0,0:0|0:0,0:0:0:0:
396,280,6623,1,0,0:0:0:0:
324,328,6857,2,0,P|288:332|252:324,1,72
180,280,7326,2,0,L|108:284,1,72,0|0,0:0|0:0,0:0:0:0:
256,192,7795,12,0,9670,0:0:0:0:
428,212,10138,1,0,0:0:0:0:
292,320,10607,1,0,0:0:0:0:
184,184,11076,2,0,L|112:180,1,72,0|0,0:0|0:0,0:0:0:0:
24,172,11545,5,6,0:0:0:0:
160,280,12013,1,0,0:0:0:0:
268,144,12482,1,0,0:0:0:0:
132,36,12951,2,0,L|204:32,1,72,0|0,0:0|0:0,0:0:0:0:
284,60,13420,6,0,P|340:100|344:180,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0:
268,144,14591,1,0,0:0:0:0:
284,228,14826,2,0,P|316:248|364:252,1,72,0|0,0:0|0:0,0:0:0:0:
436,248,15295,6,0,P|372:272|344:340,1,144,6|2,0:0|0:0,0:0:0:0:
168,338,16232,2,0,P|141:273|76:248,1,144,2|2,0:0|0:0,0:0:0:0:
4,296,16935,1,0,0:0:0:0:
80,336,17170,5,6,0:0:0:0:
44,168,17638,1,0,0:0:0:0:
212,128,18107,1,0,0:0:0:0:
248,296,18576,2,0,P|284:288|320:292,1,72,0|0,0:0|0:0,0:0:0:0:
400,324,19045,5,6,0:0:0:0:
280,200,19513,1,0,0:0:0:0:
368,52,19982,1,0,0:0:0:0:
488,176,20451,2,0,P|452:168|416:172,1,72,0|0,0:0|0:0,0:0:0:0:
336,200,20920,6,0,P|284:216|200:192,1,144,6|0,0:0|0:0,0:0:0:0:
200,192,21857,2,0,L|204:264,1,72,0|0,0:3|0:0,0:0:0:0:
117,244,22326,2,0,L|120:172,1,72,0|0,0:0|0:0,0:0:0:0:
40,152,22795,6,0,L|28:296,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0:
152,24,24201,1,0,0:0:0:0:
220,76,24435,1,0,3:0:0:0:
304,56,24670,6,0,P|288:120|296:196,1,144,4|2,0:3|0:3,0:0:0:0:
344,268,25373,1,0,0:0:0:0:
416,316,25607,2,0,P|452:312|508:316,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
244,344,26545,6,0,P|176:356|108:328,1,144,4|2,0:3|0:3,0:0:0:0:
60,256,27248,1,0,0:0:0:0:
36,172,27482,2,0,L|40:100,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
188,252,28420,6,0,P|192:184|196:100,1,144,4|2,0:3|0:3,0:0:0:0:
140,40,29123,1,0,0:0:0:0:
140,40,29357,2,0,B|172:16|220:24|220:24|288:36,1,144,0|2,0:0|0:3,0:0:0:0:
364,52,30060,1,0,0:0:0:0:
308,116,30295,6,0,B|300:168|300:168|328:256,1,144,4|2,0:3|0:3,0:0:0:0:
340,340,30998,1,0,0:0:0:0:
260,308,31232,2,0,L|188:304,1,72,0|2,0:0|0:3,0:0:0:0:
100,296,31701,1,2,0:3:0:0:
136,374,31935,1,0,0:0:0:0:
152,224,32170,6,0,P|160:152|132:88,1,144,4|2,0:3|0:3,0:0:0:0:
56,48,32873,1,0,0:0:0:0:
60,136,33107,2,0,L|56:208,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
224,76,34045,6,0,P|289:104|360:96,1,144,4|2,0:3|0:3,0:0:0:0:
432,48,34748,1,0,0:0:0:0:
440,132,34982,2,0,B|432:156|432:156|436:204,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
448,304,35920,6,0,B|412:315|380:292|380:292|348:269|312:280,1,144,4|2,0:3|0:3,0:0:0:0:
332,364,36623,1,0,0:0:0:0:
247,339,36857,2,0,P|230:308|225:273,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
312,280,37560,6,0,L|316:172,1,108
134,35,38966,5,0,0:0:0:0:
72,96,39201,2,0,P|119:119|171:111,1,108,0|0,0:0|0:0,0:0:0:0:
192,100,39670,6,0,L|200:172,1,72,4|2,0:0|0:0,0:0:0:0:
147,240,40138,2,0,P|133:272|132:308,1,72,0|2,1:0|0:0,0:0:0:0:
216,292,40607,2,0,B|260:308|260:308|356:292,1,144,4|0,2:3|1:0,1:0:0:0:
356,292,41310,1,2,0:0:0:0:
436,327,41545,6,0,P|441:292|435:257,1,72,4|2,0:3|0:0,0:0:0:0:
364,204,42013,2,0,P|336:144|352:68,1,144,0|4,1:0|2:3,1:0:0:0:
404,0,42716,1,2,0:0:0:0:
440,80,42951,2,0,B|464:84|464:84|512:80,1,72,0|2,1:0|0:0,0:0:0:0:
351,71,43420,6,0,B|296:68|296:68|268:76|268:76|196:72,1,144,4|0,2:3|1:0,1:0:0:0:
120,68,44123,1,2,0:0:0:0:
160,144,44357,2,0,P|172:180|168:232,1,72,4|2,0:3|0:0,0:0:0:0:
76,264,44826,2,0,P|76:228|88:194,1,72,0|2,1:0|0:0,0:0:0:0:
160,144,45295,5,4,0:3:0:0:
244,164,45529,1,2,0:0:0:0:
268,248,45763,2,0,L|344:252,1,72,0|2,1:0|0:0,0:0:0:0:
408,156,46232,2,0,L|336:159,1,72,4|2,0:3|0:0,0:0:0:0:
212,72,46701,2,0,L|288:76,1,72,0|2,1:0|0:0,0:0:0:0:
400,72,47170,6,0,P|464:96|488:172,1,144,4|0,2:0|1:0,1:0:0:0:
476,248,47873,1,2,0:0:0:0:
436,324,48107,2,0,L|284:320,1,144,4|0,2:3|1:0,1:0:0:0:
204,316,48810,1,2,0:0:0:0:
127,355,49045,6,0,P|120:321|124:285,1,72,4|2,0:3|0:0,0:0:0:0:
192,232,49513,2,0,L|335:228,1,144,0|4,1:0|2:3,1:0:0:0:
412,188,50216,1,2,0:0:0:0:
444,108,50451,2,0,P|452:72|448:36,1,72,0|2,1:0|0:0,0:0:0:0:
368,68,50920,6,0,B|332:79|300:56|300:56|268:33|232:44,1,144,4|0,2:3|1:0,1:0:0:0:
152,76,51623,1,2,0:0:0:0:
76,116,51857,2,0,L|80:268,1,144,4|0,2:3|1:0,1:0:0:0:
80,260,52560,1,2,0:0:0:0:
8,308,52795,6,0,P|34:334|69:346,1,72,4|2,0:3|0:0,0:0:0:0:
148,312,53263,2,0,P|163:278|162:241,1,72,0|2,1:0|0:0,0:0:0:0:
156,156,53732,5,0,3:0:0:0:
156,156,53966,1,2,0:0:0:0:
236,196,54201,2,0,L|312:192,1,72,8|0,0:3|0:0,0:0:0:0:
368,256,54670,6,0,P|392:216|352:116,1,144,4|2,0:0|1:2,0:0:0:0:
288,92,55373,1,0,0:0:0:0:
360,40,55607,2,0,L|432:36,1,72,4|0,0:3|3:0,0:0:0:0:
288,92,56076,2,0,L|216:88,1,72,2|0,1:2|0:0,0:0:0:0:
132,72,56545,6,0,P|172:88|200:184,1,144,4|2,0:3|1:2,0:0:0:0:
143,241,57248,1,0,0:0:0:0:
65,202,57482,2,0,P|87:174|119:157,1,72,4|0,0:3|3:0,0:0:0:0:
132,324,57951,2,0,P|98:312|72:288,1,72,2|0,1:2|0:0,0:0:0:0:
143,241,58420,6,0,L|288:240,1,144,4|2,0:3|1:2,0:0:0:0:
372,240,59123,1,0,0:0:0:0:
330,314,59357,2,0,P|318:350|322:390,1,72,4|0,0:3|3:0,0:0:0:0:
452,264,59826,2,0,P|453:228|442:194,1,72,2|0,1:2|0:0,0:0:0:0:
384,128,60295,6,0,B|336:144|336:144|244:128,1,144,4|2,0:3|1:2,0:0:0:0:
164,160,60998,2,0,P|160:116|168:88,1,72,0|4,0:0|0:3,0:0:0:0:
244,128,61466,2,0,P|248:172|240:200,1,72,0|2,3:0|1:2,0:0:0:0:
168,248,61935,1,0,0:0:0:0:
120,320,62170,6,0,P|196:328|252:272,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
80,244,63341,1,0,3:0:0:0:
100,160,63576,2,0,L|24:156,1,72,2|0,1:2|0:0,0:0:0:0:
180,128,64045,6,0,P|249:138|304:94,1,144,4|2,0:3|1:2,0:0:0:0:
226,57,64748,1,0,0:0:0:0:
304,94,64982,2,0,L|300:166,1,72,4|0,0:3|3:0,0:0:0:0:
377,203,65451,2,0,L|388:132,1,72,2|0,1:2|0:0,0:0:0:0:
468,180,65920,6,0,L|432:328,1,144,4|2,0:3|1:2,0:0:0:0:
276,252,66857,2,0,P|208:248|140:280,1,144,4|2,0:3|1:2,0:0:0:0:
84,344,67560,1,0,0:0:0:0:
56,260,67795,6,0,L|52:188,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
168,128,68732,2,0,L|172:56,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
244,168,69435,1,0,0:0:0:0:
332,164,69670,1,4,0:3:0:0:
208,328,84670,6,0,P|224:264|216:188,1,144,4|2,0:3|0:3,0:0:0:0:
168,116,85373,1,0,0:0:0:0:
96,68,85607,2,0,P|60:72|4:68,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
268,40,86545,6,0,P|336:28|404:56,1,144,4|2,0:3|0:3,0:0:0:0:
452,128,87248,1,0,0:0:0:0:
476,212,87482,2,0,L|472:284,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
324,132,88420,6,0,P|320:200|316:284,1,144,4|2,0:3|0:3,0:0:0:0:
372,344,89123,1,0,0:0:0:0:
372,344,89357,2,0,B|340:368|292:360|292:360|224:348,1,144,0|2,0:0|0:3,0:0:0:0:
148,332,90060,1,0,0:0:0:0:
204,268,90295,6,0,B|212:216|212:216|184:128,1,144,4|2,0:3|0:3,0:0:0:0:
172,44,90998,1,0,0:0:0:0:
252,76,91232,2,0,L|324:80,1,72,0|2,0:0|0:3,0:0:0:0:
412,88,91701,1,2,0:3:0:0:
377,9,91935,1,0,0:0:0:0:
360,160,92170,6,0,P|352:232|380:296,1,144,4|2,0:3|0:3,0:0:0:0:
456,336,92873,1,0,0:0:0:0:
452,248,93107,2,0,L|456:176,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
288,308,94045,6,0,P|223:280|152:288,1,144,4|2,0:3|0:3,0:0:0:0:
80,336,94748,1,0,0:0:0:0:
72,252,94982,2,0,B|80:228|80:228|76:180,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
64,80,95920,6,0,B|100:69|132:92|132:92|164:115|200:104,1,144,4|2,0:3|0:3,0:0:0:0:
180,20,96623,1,0,0:0:0:0:
265,45,96857,2,0,P|282:76|287:111,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
200,104,97560,1,0,0:0:0:0:
200,104,97677,1,0,0:0:0:0:
200,104,97795,6,0,B|196:142|217:166|217:166|176:180|160:220,1,144,4|0,0:3|0:0,0:0:0:0:
240,248,98966,5,0,0:0:0:0:
202,325,99201,2,0,P|254:333|301:309,1,108,0|0,0:0|0:0,0:0:0:0:
315,292,99670,6,0,L|323:220,1,72,4|2,0:0|0:0,0:0:0:0:
365,144,100138,2,0,P|379:112|380:76,1,72,0|2,1:0|0:0,0:0:0:0:
296,92,100607,2,0,B|252:76|252:76|156:92,1,144,4|0,2:3|1:0,1:0:0:0:
156,92,101310,1,2,0:0:0:0:
76,57,101545,6,0,P|71:92|77:127,1,72,4|2,0:3|0:0,0:0:0:0:
148,180,102013,2,0,P|176:240|160:316,1,144,0|4,1:0|2:3,1:0:0:0:
108,384,102716,1,2,0:0:0:0:
72,304,102951,2,0,B|48:300|48:300|0:304,1,72,0|2,1:0|0:0,0:0:0:0:
161,313,103420,6,0,B|216:316|216:316|244:308|244:308|316:312,1,144,4|0,2:3|1:0,1:0:0:0:
392,316,104123,1,2,0:0:0:0:
352,240,104357,2,0,P|340:204|344:152,1,72,4|2,0:3|0:0,0:0:0:0:
436,120,104826,2,0,P|436:156|424:190,1,72,0|2,1:0|0:0,0:0:0:0:
352,240,105295,5,4,0:3:0:0:
268,220,105529,1,2,0:0:0:0:
244,136,105763,2,0,L|168:132,1,72,0|2,1:0|0:0,0:0:0:0:
104,228,106232,2,0,L|176:225,1,72,4|2,0:3|0:0,0:0:0:0:
300,312,106701,2,0,L|224:308,1,72,0|2,1:0|0:0,0:0:0:0:
112,312,107170,6,0,P|48:288|24:212,1,144,4|0,2:0|1:0,1:0:0:0:
36,136,107873,1,2,0:0:0:0:
76,60,108107,2,0,L|228:64,1,144,4|0,2:3|1:0,1:0:0:0:
308,68,108810,1,2,0:0:0:0:
385,29,109045,6,0,P|392:63|388:99,1,72,4|2,0:3|0:0,0:0:0:0:
320,152,109513,2,0,L|177:156,1,144,0|4,1:0|2:3,1:0:0:0:
100,196,110216,1,2,0:0:0:0:
68,276,110451,2,0,P|60:312|64:348,1,72,0|2,1:0|0:0,0:0:0:0:
144,316,110920,6,0,B|180:305|212:328|212:328|244:351|280:340,1,144,4|0,2:3|1:0,1:0:0:0:
360,308,111623,1,2,0:0:0:0:
436,268,111857,2,0,L|432:116,1,144,4|0,2:3|1:0,1:0:0:0:
432,124,112560,1,2,0:0:0:0:
504,76,112795,6,0,P|478:50|443:38,1,72,4|2,0:3|0:0,0:0:0:0:
364,72,113263,2,0,P|349:106|350:143,1,72,0|2,1:0|0:0,0:0:0:0:
356,228,113732,5,0,3:0:0:0:
356,228,113966,1,2,0:0:0:0:
276,188,114201,2,0,L|200:192,1,72,8|0,0:3|0:0,0:0:0:0:
144,128,114670,6,0,P|120:168|160:268,1,144,4|2,0:0|1:2,0:0:0:0:
224,292,115373,1,0,0:0:0:0:
152,344,115607,2,0,L|80:348,1,72,4|0,0:3|3:0,0:0:0:0:
224,292,116076,2,0,L|296:296,1,72,2|0,1:2|0:0,0:0:0:0:
380,312,116545,6,0,P|340:296|312:200,1,144,4|2,0:3|1:2,0:0:0:0:
369,143,117248,1,0,0:0:0:0:
447,182,117482,2,0,P|425:210|393:227,1,72,4|0,0:3|3:0,0:0:0:0:
380,60,117951,2,0,P|414:72|440:96,1,72,2|0,1:2|0:0,0:0:0:0:
369,143,118420,6,0,L|224:144,1,144,4|2,0:3|1:2,0:0:0:0:
140,144,119123,1,0,0:0:0:0:
182,70,119357,2,0,P|194:34|190:-6,1,72,4|0,0:3|3:0,0:0:0:0:
60,120,119826,2,0,P|59:156|70:190,1,72,2|0,1:2|0:0,0:0:0:0:
128,256,120295,6,0,B|176:240|176:240|268:256,1,144,4|2,0:3|1:2,0:0:0:0:
348,224,120998,2,0,P|352:268|344:296,1,72,0|4,0:0|0:3,0:0:0:0:
268,256,121466,2,0,P|264:212|272:184,1,72,0|2,3:0|1:2,0:0:0:0:
344,136,121935,1,0,0:0:0:0:
392,64,122170,6,0,P|316:56|260:112,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
432,140,123341,1,0,3:0:0:0:
412,224,123576,2,0,L|488:228,1,72,2|0,1:2|0:0,0:0:0:0:
332,256,124045,6,0,P|263:246|208:290,1,144,4|2,0:3|1:2,0:0:0:0:
286,327,124748,1,0,0:0:0:0:
208,290,124982,2,0,L|212:218,1,72,4|0,0:3|3:0,0:0:0:0:
135,181,125451,2,0,L|124:252,1,72,2|0,1:2|0:0,0:0:0:0:
44,204,125920,6,0,L|80:56,1,144,4|2,0:3|1:2,0:0:0:0:
236,132,126857,2,0,P|304:136|372:104,1,144,4|2,0:3|1:2,0:0:0:0:
428,40,127560,1,0,0:0:0:0:
456,124,127795,6,0,L|460:196,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
344,256,128732,2,0,L|340:328,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
268,216,129435,1,0,0:0:0:0:
180,220,129670,5,4,2:0:0:0:
256,40,130373,1,2,0:0:0:0:
64,68,131076,1,2,0:0:0:0:
92,136,131310,1,0,0:0:0:0:
64,204,131545,6,0,L|60:288,1,72
31,343,132248,2,0,P|86:345|127:309,1,108
332,220,133420,5,2,0:0:0:0:
256,40,134123,1,2,0:0:0:0:
448,68,134826,1,2,0:0:0:0:
420,136,135060,1,0,0:0:0:0:
448,204,135295,6,0,L|452:288,1,72,2|0,0:0|0:0,0:0:0:0:
480,343,135998,2,0,P|426:345|385:309,1,108
256,192,137170,5,2,0:0:0:0:
156,360,137873,1,2,0:0:0:0:
356,360,138576,2,0,L|352:308,1,36,2|0,0:0|0:0,0:0:0:0:
304,268,139045,6,0,P|336:253|372:252,1,72
448,260,139748,2,0,L|444:152,1,108
256,192,140920,5,2,0:0:0:0:
356,24,141623,1,2,0:0:0:0:
156,24,142326,2,0,L|160:72,1,36,2|0,0:0|0:0,0:0:0:0:
208,116,142795,6,0,P|176:131|140:132,1,72,2|0,0:0|0:0,0:0:0:0:
64,124,143498,2,0,L|68:232,1,108
68,232,144670,5,4,0:3:0:0:
216,320,145138,1,4,0:3:0:0:
304,172,145607,1,4,0:3:0:0:
156,84,146075,1,4,0:3:0:0:
296,320,146545,5,4,0:3:0:0:
208,172,147013,1,4,0:3:0:0:
356,84,147482,1,4,0:3:0:0:
444,232,147950,1,4,0:3:0:0:
296,320,148420,6,0,P|252:328|192:296,2,108.000004119873,4|4|4,0:3|0:3|0:3,0:0:0:0:
260,248,149591,1,0,0:0:0:0:
320,196,149826,2,0,L|316:140,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0:
120,236,159670,6,0,L|176:232,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0:
160,152,160138,2,0,L|104:156,1,54.0000020599366,2|0,0:0|0:0,0:0:0:0:
240,180,160607,2,0,P|292:188|344:172,1,108.000004119873,4|2,0:3|0:0,3:0:0:0:
408,120,161310,1,0,3:0:0:0:
424,200,161545,6,0,L|420:256,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0:
376,320,162013,2,0,P|396:328|480:304,2,108.000004119873,2|6|2,2:0|0:3|2:0,3:0:0:0:
312,268,163185,1,0,0:0:0:0:
296,348,163420,6,0,L|240:344,1,54.0000020599366,4|0,3:0|3:0,0:0:0:0:
160,320,163888,2,0,L|100:316,1,57.6,4|0,3:0|3:0,0:0:0:0:
64,232,164357,6,0,L|128:228,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0:
204,200,164825,2,0,L|268:196,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0:
232,108,165295,6,0,L|164:104,1,68.399998173523,4|0,3:0|3:0,0:0:0:0:
80,84,165763,2,0,L|4:80,1,72,4|0,3:0|3:0,0:0:0:0:
324,120,167170,6,0,P|388:128|456:92,1,144,4|2,0:0|1:2,0:0:0:0:
496,168,167873,1,0,0:0:0:0:
496,168,168107,2,0,P|484:204|488:256,1,72,4|0,0:3|3:0,0:0:0:0:
408,296,168576,2,0,P|398:261|378:231,1,72,2|0,1:2|0:0,0:0:0:0:
296,200,169045,6,0,B|228:228|156:204,1,144,4|2,0:3|1:2,0:0:0:0:
84,156,169748,1,0,0:0:0:0:
80,244,169982,2,0,L|76:316,1,72,4|0,0:3|3:0,0:0:0:0:
170,274,170451,2,0,L|156:204,1,72,2|0,1:2|0:0,0:0:0:0:
216,140,170920,6,0,L|284:276,1,144,4|2,0:3|1:2,0:0:0:0:
320,344,171623,1,0,0:0:0:0:
372,276,171857,2,0,P|366:240|349:207,1,72,4|0,0:3|3:0,0:0:0:0:
312,132,172326,2,0,L|276:60,1,72,2|0,1:2|0:0,0:0:0:0:
208,20,172795,6,0,P|272:36|348:12,1,144,4|2,0:3|1:2,0:0:0:0:
424,48,173498,2,0,L|412:132,1,72,0|4,0:0|0:3,0:0:0:0:
484,168,173966,2,0,L|472:252,1,72,0|2,3:0|1:2,0:0:0:0:
400,280,174435,1,0,0:0:0:0:
346,348,174670,6,0,P|414:363|472:324,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
312,268,175841,1,0,3:0:0:0:
256,336,176076,2,0,L|184:332,1,72,2|0,1:2|0:0,0:0:0:0:
80,244,176545,6,0,B|140:248|140:248|164:244|164:244|223:247,1,144,4|2,0:3|1:2,0:0:0:0:
312,268,177248,1,0,0:0:0:0:
224,247,177482,2,0,P|240:215|272:187,1,72,4|0,0:3|3:0,0:0:0:0:
204,131,177951,2,0,P|233:111|275:103,1,72,2|0,1:2|0:0,0:0:0:0:
240,23,178420,6,0,B|280:15|316:35|316:35|376:71,1,144,4|2,0:3|1:2,0:0:0:0:
399,236,179357,2,0,B|359:244|323:224|323:224|263:188,1,144,4|2,0:3|1:2,0:0:0:0:
204,132,180060,1,0,0:0:0:0:
184,216,180295,6,0,L|188:288,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
120,156,180998,1,0,0:0:0:0:
56,96,181232,2,0,L|60:24,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
36,180,181935,1,0,0:0:0:0:
100,240,182170,6,0,P|144:300|116:380,2,144,4|2|4,0:0|1:2|0:3,0:0:0:0:
60,316,183341,1,0,0:0:0:0:
220,352,183576,2,0,L|308:348,1,72,2|0,1:2|0:0,0:0:0:0:
396,264,184045,6,0,B|336:268|336:268|312:264|312:264|253:267,1,144,4|2,0:3|1:2,0:0:0:0:
253,267,184748,1,0,0:0:0:0:
268,180,184982,2,0,L|339:177,1,72,4|0,0:3|0:0,0:0:0:0:
164,280,185451,2,0,L|92:282,1,72,2|0,1:2|0:0,0:0:0:0:
52,208,185920,6,0,P|8:268|32:344,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
140,212,187091,1,0,0:0:0:0:
92,284,187326,2,0,P|104:316|100:368,1,72,2|0,1:2|0:0,0:0:0:0:
52,208,187795,6,0,P|48:136|76:72,1,144,4|2,0:3|1:2,0:0:0:0:
160,52,188498,2,0,P|188:28|220:16,1,72,0|4,0:0|0:3,0:0:0:0:
232,100,188966,2,0,P|268:93|301:98,1,72,0|2,0:0|1:2,0:0:0:0:
372,152,189435,1,0,0:0:0:0:
420,224,189670,6,0,P|428:296|400:360,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
372,152,190841,1,0,0:0:0:0:
392,68,191076,2,0,L|465:64,1,72,2|0,1:2|0:0,0:0:0:0:
304,92,191545,6,0,P|236:104|168:76,1,144,4|2,0:3|1:2,0:0:0:0:
108,12,192248,1,0,0:0:0:0:
168,76,192482,2,0,L|172:152,1,72,4|0,0:3|0:0,0:0:0:0:
80,136,192951,2,0,L|101:204,1,72,2|0,1:2|0:0,0:0:0:0:
12,220,193420,6,0,B|50:279|50:279|80:300|120:292,1,144,4|2,0:3|1:2,0:0:0:0:
284,232,194357,2,0,B|320:221|352:244|352:244|384:267|420:256,1,144,4|2,0:3|1:2,0:0:0:0:
488,200,195060,1,0,0:0:0:0:
507,284,195295,6,0,P|492:315|464:338,1,72,4|0,0:0|0:0,0:0:0:0:
380,356,195763,2,0,L|236:352,1,144,0|4,1:0|0:3,0:0:0:0:
152,328,196466,1,0,3:0:0:0:
64,336,196701,2,0,P|29:325|4:300,1,72,0|0,1:0|0:0,0:0:0:0:
76,252,197170,6,0,P|108:188|96:116,1,144,4|0,0:0|1:0,0:0:0:0:
36,56,197873,1,2,0:0:0:0:
120,32,198107,2,0,L|192:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
248,152,199045,6,0,P|280:168|304:196,1,72,4|2,0:3|0:0,0:0:0:0:
336,277,199513,2,0,P|306:296|269:303,1,72,2|0,1:2|0:0,0:0:0:0:
183,290,199982,2,0,P|180:254|193:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
436,252,200920,6,0,P|404:188|416:116,1,144,4|0,0:3|1:0,0:0:0:0:
476,56,201623,1,2,0:0:0:0:
392,32,201857,2,0,L|320:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0:
264,152,202795,6,0,P|232:168|208:196,1,72,4|2,0:3|0:0,0:0:0:0:
176,277,203263,2,0,P|205:296|242:303,1,72,2|0,1:2|0:0,0:0:0:0:
329,290,203732,2,0,P|331:254|318:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
72,324,204670,6,0,B|60:272|60:272|76:180,1,144,4|0,0:0|1:0,0:0:0:0:
92,96,205373,1,2,0:0:0:0:
8,124,205607,2,0,P|5:88|14:53,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
168,192,206545,6,0,P|200:174|237:173,1,72,4|2,0:3|0:0,0:0:0:0:
320,160,207013,2,0,P|318:196|301:229,1,72,2|0,1:2|0:0,0:0:0:0:
272,307,207482,2,0,P|240:287|221:256,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
440,324,208420,6,0,B|452:272|452:272|436:180,1,144,4|0,0:3|1:0,0:0:0:0:
420,96,209123,1,2,0:0:0:0:
504,124,209357,2,0,P|507:88|498:53,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0:
344,192,210295,6,0,P|311:174|274:173,1,72,4|2,0:3|0:0,0:0:0:0:
190,156,210763,2,0,P|191:192|208:225,1,72,2|0,1:2|0:0,0:0:0:0:
288,256,211232,1,4,0:3:0:0:
132,332,211701,1,0,1:0:0:0:
28,192,212170,6,0,P|16:120|44:56,1,144,4|0,0:0|1:0,0:0:0:0:
120,16,212873,1,2,0:0:0:0:
204,32,213107,2,0,L|304:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
192,204,214045,6,0,P|196:240|216:272,1,72,4|2,0:3|0:0,0:0:0:0:
298,241,214513,2,0,P|327:219|345:186,1,72,6|0,1:2|0:0,0:0:0:0:
280,132,214982,2,0,P|246:117|209:118,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
484,192,215920,6,0,P|496:120|468:56,1,144,4|0,0:3|1:0,0:0:0:0:
392,16,216623,1,2,0:0:0:0:
308,32,216857,2,0,L|208:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0:
320,204,217795,6,0,P|316:240|296:272,1,72,4|2,0:3|0:0,0:0:0:0:
213,241,218263,2,0,P|184:219|166:186,1,72,2|0,1:2|0:0,0:0:0:0:
232,132,218732,2,0,B|260:112|300:116|300:116|384:128,1,144,4|0,0:3|1:0,0:0:0:0:
348,336,219670,6,0,B|320:356|280:352|280:352|196:340,1,144,4|0,0:0|1:0,0:0:0:0:
124,328,220373,1,2,0:0:0:0:
54,276,220607,2,0,P|41:308|39:345,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
156,80,221545,6,0,L|251:94,1,72,4|2,0:3|0:0,0:0:0:0:
212,169,222013,2,0,L|148:160,1,64.799998022461,2|0,1:2|0:0,0:0:0:0:
140,240,222482,2,0,L|216:252,2,57.6,4|2|0,0:3|0:0|1:0,0:0:0:0:
256,192,223420,12,0,227170,0:0:0:0:
";
} }
} }

View File

@ -2,9 +2,9 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Linq;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
@ -12,11 +12,10 @@ namespace osu.Desktop.Tests.Visual
{ {
public override string Description => @"Testing replay playback."; public override string Description => @"Testing replay playback.";
protected override Player CreatePlayer(WorkingBeatmap beatmap) protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
{ {
beatmap.Mods.Value = new Mod[] { new OsuModAutoplay() }; beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return base.CreatePlayer(beatmap, ruleset);
return base.CreatePlayer(beatmap);
} }
} }
} }

View File

@ -3,18 +3,23 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework;
using OpenTK; using OpenTK;
using osu.Desktop.Tests.Beatmaps; using osu.Desktop.Tests.Beatmaps;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Beatmaps; using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
@ -22,6 +27,7 @@ namespace osu.Desktop.Tests.Visual
/// <summary> /// <summary>
/// The most minimal implementation of a playfield with scrolling hit objects. /// The most minimal implementation of a playfield with scrolling hit objects.
/// </summary> /// </summary>
[TestFixture]
public class TestCaseScrollingPlayfield : OsuTestCase public class TestCaseScrollingPlayfield : OsuTestCase
{ {
public TestCaseScrollingPlayfield() public TestCaseScrollingPlayfield()
@ -58,12 +64,72 @@ namespace osu.Desktop.Tests.Visual
AddStep("Reverse direction", () => AddStep("Reverse direction", () =>
{ {
horizontalRulesetContainer.Playfield.Reversed.Toggle(); horizontalRulesetContainer.Playfield.Reverse();
verticalRulesetContainer.Playfield.Reversed.Toggle(); verticalRulesetContainer.Playfield.Reverse();
}); });
} }
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject, TestJudgement> [Test]
public void TestSpeedAdjustmentOrdering()
{
var hitObjectContainer = new ScrollingPlayfield.ScrollingHitObjectContainer(Axes.X);
var speedAdjustments = new[]
{
new SpeedAdjustmentContainer(new MultiplierControlPoint()),
new SpeedAdjustmentContainer(new MultiplierControlPoint(1000)
{
TimingPoint = new TimingControlPoint { BeatLength = 500 }
}),
new SpeedAdjustmentContainer(new MultiplierControlPoint(2000)
{
TimingPoint = new TimingControlPoint { BeatLength = 1000 },
DifficultyPoint = new DifficultyControlPoint { SpeedMultiplier = 2}
}),
new SpeedAdjustmentContainer(new MultiplierControlPoint(3000)
{
TimingPoint = new TimingControlPoint { BeatLength = 1000 },
DifficultyPoint = new DifficultyControlPoint { SpeedMultiplier = 1}
}),
};
var hitObjects = new[]
{
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = -1000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject()),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 1000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 2000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 3000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 4000 }),
};
hitObjects.ForEach(h => hitObjectContainer.Add(h));
speedAdjustments.ForEach(hitObjectContainer.AddSpeedAdjustment);
// The 0th index in hitObjectContainer.SpeedAdjustments is the "default" control point
// Check multiplier of the default speed adjustment
Assert.AreEqual(1, hitObjectContainer.SpeedAdjustments[0].ControlPoint.Multiplier);
Assert.AreEqual(1, speedAdjustments[0].ControlPoint.Multiplier);
Assert.AreEqual(2, speedAdjustments[1].ControlPoint.Multiplier);
Assert.AreEqual(2, speedAdjustments[2].ControlPoint.Multiplier);
Assert.AreEqual(1, speedAdjustments[3].ControlPoint.Multiplier);
// Check insertion of hit objects
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[4].Contains(hitObjects[0]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[2].Contains(hitObjects[2]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[1].Contains(hitObjects[3]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[0].Contains(hitObjects[4]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[0].Contains(hitObjects[5]));
hitObjectContainer.RemoveSpeedAdjustment(hitObjectContainer.SpeedAdjustments[3]);
// The hit object contained in this speed adjustment should be resorted into the one occuring before it
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
}
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject>
{ {
private readonly Axes scrollingAxes; private readonly Axes scrollingAxes;
@ -77,16 +143,18 @@ namespace osu.Desktop.Tests.Visual
public override ScoreProcessor CreateScoreProcessor() => new TestScoreProcessor(); public override ScoreProcessor CreateScoreProcessor() => new TestScoreProcessor();
public override PassThroughInputManager CreateInputManager() => new PassThroughInputManager();
protected override BeatmapConverter<TestHitObject> CreateBeatmapConverter() => new TestBeatmapConverter(); protected override BeatmapConverter<TestHitObject> CreateBeatmapConverter() => new TestBeatmapConverter();
protected override Playfield<TestHitObject, TestJudgement> CreatePlayfield() => new TestPlayfield(scrollingAxes); protected override Playfield CreatePlayfield() => new TestPlayfield(scrollingAxes);
protected override DrawableHitObject<TestHitObject, TestJudgement> GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h); protected override DrawableHitObject<TestHitObject> GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h);
} }
private class TestScoreProcessor : ScoreProcessor<TestHitObject, TestJudgement> private class TestScoreProcessor : ScoreProcessor<TestHitObject>
{ {
protected override void OnNewJudgement(TestJudgement judgement) protected override void OnNewJudgement(Judgement judgement)
{ {
} }
} }
@ -101,7 +169,7 @@ namespace osu.Desktop.Tests.Visual
} }
} }
private class DrawableTestHitObject : DrawableScrollingHitObject<TestHitObject, TestJudgement> private class DrawableTestHitObject : DrawableScrollingHitObject<TestHitObject>
{ {
public DrawableTestHitObject(Axes scrollingAxes, TestHitObject hitObject) public DrawableTestHitObject(Axes scrollingAxes, TestHitObject hitObject)
: base(hitObject) : base(hitObject)
@ -117,14 +185,12 @@ namespace osu.Desktop.Tests.Visual
}); });
} }
protected override TestJudgement CreateJudgement() => new TestJudgement();
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {
} }
} }
private class TestPlayfield : ScrollingPlayfield<TestHitObject, TestJudgement> private class TestPlayfield : ScrollingPlayfield
{ {
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content; private readonly Container<Drawable> content;
@ -142,17 +208,13 @@ namespace osu.Desktop.Tests.Visual
content = new Container { RelativeSizeAxes = Axes.Both } content = new Container { RelativeSizeAxes = Axes.Both }
}; };
} }
public void Reverse() => Reversed.Toggle();
} }
private class TestHitObject : HitObject private class TestHitObject : HitObject
{ {
} }
private class TestJudgement : Judgement
{
public override string ResultString { get { throw new NotImplementedException(); } }
public override string MaxResultString { get { throw new NotImplementedException(); } }
}
} }
} }

View File

@ -0,0 +1,90 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Storyboards.Drawables;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseStoryboard : OsuTestCase
{
public override string Description => @"Tests storyboards.";
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
private readonly Container<DrawableStoryboard> storyboardContainer;
private DrawableStoryboard storyboard;
public TestCaseStoryboard()
{
Clock = new FramedClock();
Add(new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
storyboardContainer = new Container<DrawableStoryboard>
{
RelativeSizeAxes = Axes.Both,
},
},
});
Add(new MusicController
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
State = Visibility.Visible,
});
AddStep("Restart", restart);
AddToggleStep("Passing", passing => { if (storyboard != null) storyboard.Passing = passing; });
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
beatmapBacking.BindTo(game.Beatmap);
beatmapBacking.ValueChanged += beatmapChanged;
}
private void beatmapChanged(WorkingBeatmap working)
=> loadStoryboard(working);
private void restart()
{
var track = beatmapBacking.Value.Track;
track.Reset();
loadStoryboard(beatmapBacking.Value);
track.Start();
}
private void loadStoryboard(WorkingBeatmap working)
{
if (storyboard != null)
storyboardContainer.Remove(storyboard);
var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true };
decoupledClock.ChangeSource(working.Track);
storyboardContainer.Clock = decoupledClock;
storyboardContainer.Add(storyboard = working.Beatmap.Storyboard.CreateDrawable());
storyboard.Passing = false;
}
}
}

View File

@ -14,6 +14,11 @@ using osu.Game.Rulesets.Taiko.UI;
using OpenTK; using OpenTK;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Desktop.Tests.Beatmaps;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
@ -27,10 +32,11 @@ namespace osu.Desktop.Tests.Visual
protected override double TimePerAction => default_duration * 2; protected override double TimePerAction => default_duration * 2;
private readonly Random rng = new Random(1337); private readonly Random rng = new Random(1337);
private readonly TaikoPlayfield playfield; private TaikoRulesetContainer rulesetContainer;
private readonly Container playfieldContainer; private Container playfieldContainer;
public TestCaseTaikoPlayfield() [BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{ {
AddStep("Hit!", () => addHitJudgement(false)); AddStep("Hit!", () => addHitJudgement(false));
AddStep("Kiai hit", () => addHitJudgement(true)); AddStep("Kiai hit", () => addHitJudgement(true));
@ -51,6 +57,25 @@ namespace osu.Desktop.Tests.Visual
AddStep("Height test 5", () => changePlayfieldSize(5)); AddStep("Height test 5", () => changePlayfieldSize(5));
AddStep("Reset height", () => changePlayfieldSize(6)); AddStep("Reset height", () => changePlayfieldSize(6));
var controlPointInfo = new ControlPointInfo();
controlPointInfo.TimingPoints.Add(new TimingControlPoint());
WorkingBeatmap beatmap = new TestWorkingBeatmap(new Beatmap
{
HitObjects = new List<HitObject> { new CentreHit() },
BeatmapInfo = new BeatmapInfo
{
Difficulty = new BeatmapDifficulty(),
Metadata = new BeatmapMetadata
{
Artist = @"Unknown",
Title = @"Sample Beatmap",
Author = @"peppy",
},
},
ControlPointInfo = controlPointInfo
});
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 }; var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
Add(playfieldContainer = new Container Add(playfieldContainer = new Container
@ -58,12 +83,9 @@ namespace osu.Desktop.Tests.Visual
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = TaikoPlayfield.DEFAULT_HEIGHT, Height = 768,
Clock = new FramedClock(rateAdjustClock), Clock = new FramedClock(rateAdjustClock),
Children = new[] Children = new[] { rulesetContainer = new TaikoRulesetContainer(rulesets.GetRuleset(1).CreateInstance(), beatmap, true) }
{
playfield = new TaikoPlayfield()
}
}); });
} }
@ -106,7 +128,7 @@ namespace osu.Desktop.Tests.Visual
private void addHitJudgement(bool kiai) private void addHitJudgement(bool kiai)
{ {
TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great; HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
var cpi = new ControlPointInfo(); var cpi = new ControlPointInfo();
cpi.EffectPoints.Add(new EffectControlPoint cpi.EffectPoints.Add(new EffectControlPoint
@ -117,56 +139,35 @@ namespace osu.Desktop.Tests.Visual
Hit hit = new Hit(); Hit hit = new Hit();
hit.ApplyDefaults(cpi, new BeatmapDifficulty()); hit.ApplyDefaults(cpi, new BeatmapDifficulty());
var h = new DrawableTestHit(hit) var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
{
X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f),
Judgement = new TaikoJudgement
{
Result = HitResult.Hit,
TaikoResult = hitResult,
TimeOffset = 0
}
};
playfield.OnJudgement(h); rulesetContainer.Playfield.OnJudgement(h, new TaikoJudgement { Result = hitResult });
if (RNG.Next(10) == 0) if (RNG.Next(10) == 0)
{ {
h.Judgement.SecondHit = true; rulesetContainer.Playfield.OnJudgement(h, new TaikoJudgement { Result = hitResult });
playfield.OnJudgement(h); rulesetContainer.Playfield.OnJudgement(h, new TaikoStrongHitJudgement());
} }
} }
private void addMissJudgement() private void addMissJudgement()
{ {
playfield.OnJudgement(new DrawableTestHit(new Hit()) rulesetContainer.Playfield.OnJudgement(new DrawableTestHit(new Hit()), new TaikoJudgement { Result = HitResult.Miss });
{
Judgement = new TaikoJudgement
{
Result = HitResult.Miss,
TimeOffset = 0
}
});
} }
private void addBarLine(bool major, double delay = scroll_time) private void addBarLine(bool major, double delay = scroll_time)
{ {
BarLine bl = new BarLine BarLine bl = new BarLine { StartTime = rulesetContainer.Playfield.Time.Current + delay };
{
StartTime = playfield.Time.Current + delay,
ScrollTime = scroll_time
};
playfield.AddBarLine(major ? new DrawableBarLineMajor(bl) : new DrawableBarLine(bl)); rulesetContainer.Playfield.Add(major ? new DrawableBarLineMajor(bl) : new DrawableBarLine(bl));
} }
private void addSwell(double duration = default_duration) private void addSwell(double duration = default_duration)
{ {
playfield.Add(new DrawableSwell(new Swell rulesetContainer.Playfield.Add(new DrawableSwell(new Swell
{ {
StartTime = playfield.Time.Current + scroll_time, StartTime = rulesetContainer.Playfield.Time.Current + scroll_time,
Duration = duration, Duration = duration,
ScrollTime = scroll_time
})); }));
} }
@ -177,54 +178,49 @@ namespace osu.Desktop.Tests.Visual
var d = new DrumRoll var d = new DrumRoll
{ {
StartTime = playfield.Time.Current + scroll_time, StartTime = rulesetContainer.Playfield.Time.Current + scroll_time,
IsStrong = strong, IsStrong = strong,
Duration = duration, Duration = duration,
ScrollTime = scroll_time,
}; };
playfield.Add(new DrawableDrumRoll(d)); rulesetContainer.Playfield.Add(new DrawableDrumRoll(d));
} }
private void addCentreHit(bool strong) private void addCentreHit(bool strong)
{ {
Hit h = new Hit Hit h = new Hit
{ {
StartTime = playfield.Time.Current + scroll_time, StartTime = rulesetContainer.Playfield.Time.Current + scroll_time,
ScrollTime = scroll_time,
IsStrong = strong IsStrong = strong
}; };
if (strong) if (strong)
playfield.Add(new DrawableCentreHitStrong(h)); rulesetContainer.Playfield.Add(new DrawableCentreHitStrong(h));
else else
playfield.Add(new DrawableCentreHit(h)); rulesetContainer.Playfield.Add(new DrawableCentreHit(h));
} }
private void addRimHit(bool strong) private void addRimHit(bool strong)
{ {
Hit h = new Hit Hit h = new Hit
{ {
StartTime = playfield.Time.Current + scroll_time, StartTime = rulesetContainer.Playfield.Time.Current + scroll_time,
ScrollTime = scroll_time,
IsStrong = strong IsStrong = strong
}; };
if (strong) if (strong)
playfield.Add(new DrawableRimHitStrong(h)); rulesetContainer.Playfield.Add(new DrawableRimHitStrong(h));
else else
playfield.Add(new DrawableRimHit(h)); rulesetContainer.Playfield.Add(new DrawableRimHit(h));
} }
private class DrawableTestHit : DrawableHitObject<TaikoHitObject, TaikoJudgement> private class DrawableTestHit : DrawableHitObject<TaikoHitObject>
{ {
public DrawableTestHit(TaikoHitObject hitObject) public DrawableTestHit(TaikoHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
} }
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {
} }

View File

@ -33,14 +33,11 @@ namespace osu.Desktop.Tests.Visual
Rank = 2148, Rank = 2148,
PP = 4567.89m PP = 4567.89m
}, },
AllRankHistories = new User.RankHistories RankHistory = new User.RankHistoryData
{
Osu = new User.RankHistory
{ {
Mode = @"osu", Mode = @"osu",
Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray()
} }
}
}, false)); }, false));
AddStep("Show ppy", () => profile.ShowUser(new User AddStep("Show ppy", () => profile.ShowUser(new User
{ {

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Desktop.Tests</RootNamespace> <RootNamespace>osu.Desktop.Tests</RootNamespace>
<AssemblyName>osu.Desktop.Tests</AssemblyName> <AssemblyName>osu.Desktop.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -35,14 +35,15 @@
<ItemGroup> <ItemGroup>
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference> </Reference>
<Reference Include="nunit.framework, Version=3.7.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll</HintPath> <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath> <HintPath>$(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
@ -87,9 +88,11 @@
<Compile Include="Visual\TestCaseManiaHitObjects.cs" /> <Compile Include="Visual\TestCaseManiaHitObjects.cs" />
<Compile Include="Visual\TestCaseManiaPlayfield.cs" /> <Compile Include="Visual\TestCaseManiaPlayfield.cs" />
<Compile Include="Visual\TestCaseMedalOverlay.cs" /> <Compile Include="Visual\TestCaseMedalOverlay.cs" />
<Compile Include="Visual\TestCaseEditorMenuBar.cs" />
<Compile Include="Visual\TestCaseMenuButtonSystem.cs" /> <Compile Include="Visual\TestCaseMenuButtonSystem.cs" />
<Compile Include="Visual\TestCaseMenuOverlays.cs" /> <Compile Include="Visual\TestCaseMenuOverlays.cs" />
<Compile Include="Visual\TestCaseMods.cs" /> <Compile Include="Visual\TestCaseMods.cs" />
<Compile Include="Visual\TestCaseStoryboard.cs" />
<Compile Include="Visual\TestCaseMusicController.cs" /> <Compile Include="Visual\TestCaseMusicController.cs" />
<Compile Include="Visual\TestCaseNotificationOverlay.cs" /> <Compile Include="Visual\TestCaseNotificationOverlay.cs" />
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" /> <Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
@ -155,6 +158,7 @@
<Link>osu.licenseheader</Link> <Link>osu.licenseheader</Link>
</None> </None>
<None Include="app.config" /> <None Include="app.config" />
<None Include="OpenTK.dll.config" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,9 +4,9 @@ Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
--> -->
<packages> <packages>
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" /> <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
<package id="NUnit" version="3.7.1" targetFramework="net45" /> <package id="NUnit" version="3.8.1" targetFramework="net461" />
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" /> <package id="OpenTK" version="3.0.0-git00009" targetFramework="net461" />
<package id="SQLite.Net.Core-PCL" version="3.1.1" 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="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" /> <package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />

View File

@ -22,7 +22,7 @@
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent> <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
<TargetZone>LocalIntranet</TargetZone> <TargetZone>LocalIntranet</TargetZone>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl> <PublishUrl>publish\</PublishUrl>
<Install>true</Install> <Install>true</Install>

View File

@ -1,7 +1,3 @@
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<configuration> <configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/> <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/> <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>

View File

@ -20,16 +20,11 @@ namespace osu.Desktop
{ {
internal class OsuGameDesktop : OsuGame internal class OsuGameDesktop : OsuGame
{ {
private readonly VersionManager versionManager; private VersionManager versionManager;
public OsuGameDesktop(string[] args = null) public OsuGameDesktop(string[] args = null)
: base(args) : base(args)
{ {
versionManager = new VersionManager
{
Depth = int.MinValue,
State = Visibility.Hidden
};
} }
public override Storage GetStorageForStableInstall() public override Storage GetStorageForStableInstall()
@ -88,11 +83,15 @@ namespace osu.Desktop
{ {
base.LoadComplete(); base.LoadComplete();
LoadComponentAsync(versionManager, Add); LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue });
ScreenChanged += s => ScreenChanged += s =>
{ {
if (!versionManager.IsPresent && s is Intro) if (s is Intro && s.ChildScreen == null)
{
Add(versionManager);
versionManager.State = Visibility.Visible; versionManager.State = Visibility.Visible;
}
}; };
} }

View File

@ -24,11 +24,6 @@ namespace osu.Desktop
public override void SetHost(GameHost host) public override void SetHost(GameHost host)
{ {
base.SetHost(host); base.SetHost(host);
host.UpdateThread.InactiveHz = host.UpdateThread.ActiveHz;
host.DrawThread.InactiveHz = host.DrawThread.ActiveHz;
host.InputThread.InactiveHz = host.InputThread.ActiveHz;
host.Window.CursorState |= CursorState.Hidden; host.Window.CursorState |= CursorState.Hidden;
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
@ -19,6 +20,7 @@ using OpenTK.Graphics;
using System.Net.Http; using System.Net.Http;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game; using osu.Game;
using osu.Game.Configuration;
namespace osu.Desktop.Overlays namespace osu.Desktop.Overlays
{ {
@ -26,17 +28,22 @@ namespace osu.Desktop.Overlays
{ {
private UpdateManager updateManager; private UpdateManager updateManager;
private NotificationOverlay notificationOverlay; private NotificationOverlay notificationOverlay;
private OsuConfigManager config;
private OsuGameBase game;
public override bool HandleInput => false; public override bool HandleInput => false;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game) private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
{ {
notificationOverlay = notification; notificationOverlay = notification;
this.config = config;
this.game = game;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Anchor = Anchor.BottomCentre; Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre; Origin = Anchor.BottomCentre;
Alpha = 0; Alpha = 0;
Children = new Drawable[] Children = new Drawable[]
@ -91,6 +98,42 @@ namespace osu.Desktop.Overlays
checkForUpdateAsync(); checkForUpdateAsync();
} }
protected override void LoadComplete()
{
base.LoadComplete();
var version = game.Version;
var lastVersion = config.Get<string>(OsuSetting.Version);
if (game.IsDeployedBuild && version != lastVersion)
{
config.Set(OsuSetting.Version, version);
// only show a notification if we've previously saved a version to the config file (ie. not the first run).
if (!string.IsNullOrEmpty(lastVersion))
Scheduler.AddDelayed(() => notificationOverlay.Post(new UpdateCompleteNotification(version)), 5000);
}
}
private class UpdateCompleteNotification : SimpleNotification
{
public UpdateCompleteNotification(string version)
{
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
Icon = FontAwesome.fa_check_square;
Activated = delegate
{
Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}");
return true;
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
IconBackgound.Colour = colours.BlueDark;
}
}
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);

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

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

View File

@ -22,7 +22,7 @@
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent> <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
<TargetZone>LocalIntranet</TargetZone> <TargetZone>LocalIntranet</TargetZone>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl> <PublishUrl>publish\</PublishUrl>
<Install>true</Install> <Install>true</Install>
@ -69,7 +69,8 @@
<DebugType>none</DebugType> <DebugType>none</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>CuttingEdge NoUpdate</DefineConstants> <DefineConstants>
</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib> <NoStdLib>true</NoStdLib>
@ -104,6 +105,7 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<StartArguments>--tests</StartArguments> <StartArguments>--tests</StartArguments>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL"> <Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
@ -136,36 +138,28 @@
</Reference> </Reference>
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\NuGet.Squirrel.dll</HintPath> <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath> <HintPath>$(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SharpCompress, Version=0.17.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL"> <Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll</HintPath> <HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath> <HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Squirrel, Version=1.7.5.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\Squirrel.dll</HintPath> <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.WebRequest" /> <Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
</ItemGroup> </ItemGroup>
@ -173,6 +167,7 @@
<None Include="..\osu.licenseheader"> <None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link> <Link>osu.licenseheader</Link>
</None> </None>
<None Include="app.config" />
<None Include="OpenTK.dll.config" /> <None Include="OpenTK.dll.config" />
<None Include="osu!.res" /> <None Include="osu!.res" />
<None Include="packages.config" /> <None Include="packages.config" />

View File

@ -5,10 +5,9 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
--> -->
<packages> <packages>
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" /> <package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" /> <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" /> <package id="OpenTK" version="3.0.0-git00009" targetFramework="net461" />
<package id="SharpCompress" version="0.17.1" targetFramework="net45" /> <package id="SharpCompress" version="0.18.1" targetFramework="net461" />
<package id="Splat" version="2.0.0" targetFramework="net45" /> <package id="Splat" version="2.0.0" targetFramework="net45" />
<package id="squirrel.windows" version="1.7.5" targetFramework="net45" /> <package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
</packages> </packages>

View File

@ -3,11 +3,11 @@
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch namespace osu.Game.Rulesets.Catch
{ {
public class CatchInputManager : DatabasedKeyBindingInputManager<CatchAction> public class CatchInputManager : RulesetInputManager<CatchAction>
{ {
public CatchInputManager(RulesetInfo ruleset) public CatchInputManager(RulesetInfo ruleset)
: base(ruleset, 0, SimultaneousBindingMode.Unique) : base(ruleset, 0, SimultaneousBindingMode.Unique)

View File

@ -1,18 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Input;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
namespace osu.Game.Rulesets.Catch namespace osu.Game.Rulesets.Catch
@ -23,12 +19,12 @@ namespace osu.Game.Rulesets.Catch
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[] public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{ {
new KeyBinding(Key.Z, CatchAction.MoveLeft), new KeyBinding(InputKey.Z, CatchAction.MoveLeft),
new KeyBinding(Key.Left, CatchAction.MoveLeft), new KeyBinding(InputKey.Left, CatchAction.MoveLeft),
new KeyBinding(Key.X, CatchAction.MoveRight), new KeyBinding(InputKey.X, CatchAction.MoveRight),
new KeyBinding(Key.Right, CatchAction.MoveRight), new KeyBinding(InputKey.Right, CatchAction.MoveRight),
new KeyBinding(Key.LShift, CatchAction.Dash), new KeyBinding(InputKey.Shift, CatchAction.Dash),
new KeyBinding(Key.RShift, CatchAction.Dash), new KeyBinding(InputKey.Shift, CatchAction.Dash),
}; };
public override IEnumerable<Mod> GetModsFor(ModType type) public override IEnumerable<Mod> GetModsFor(ModType type)
@ -95,23 +91,12 @@ namespace osu.Game.Rulesets.Catch
} }
} }
public override Mod GetAutoplayMod() => new ModAutoplay();
public override string Description => "osu!catch"; public override string Description => "osu!catch";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[]
{
new KeyCounterKeyboard(Key.ShiftLeft),
new KeyCounterMouse(MouseButton.Left),
new KeyCounterMouse(MouseButton.Right)
};
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor();
public override int LegacyID => 2; public override int LegacyID => 2;
public CatchRuleset(RulesetInfo rulesetInfo) public CatchRuleset(RulesetInfo rulesetInfo)

View File

@ -7,8 +7,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
{ {
public class CatchJudgement : Judgement public class CatchJudgement : Judgement
{ {
public override string ResultString => string.Empty; // todo: wangs
public override string MaxResultString => string.Empty;
} }
} }

View File

@ -9,14 +9,14 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
public class DrawableFruit : DrawableScrollingHitObject<CatchBaseHit, CatchJudgement> public class DrawableFruit : DrawableScrollingHitObject<CatchBaseHit>
{ {
private const float pulp_size = 30; private const float pulp_size = 30;
@ -98,14 +98,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
}; };
} }
protected override CatchJudgement CreateJudgement() => new CatchJudgement();
private const float preempt = 1000; private const float preempt = 1000;
protected override void CheckJudgement(bool userTriggered) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (Judgement.TimeOffset > 0) if (timeOffset > 0)
Judgement.Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Hit : HitResult.Miss; AddJudgement(new Judgement { Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Perfect : HitResult.Miss });
} }
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)

View File

@ -1,7 +1,3 @@
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<configuration> <configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/> <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/> <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>

View File

@ -1,34 +1,21 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch.Scoring namespace osu.Game.Rulesets.Catch.Scoring
{ {
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgement> internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit>
{ {
public CatchScoreProcessor() public CatchScoreProcessor()
{ {
} }
public CatchScoreProcessor(RulesetContainer<CatchBaseHit, CatchJudgement> rulesetContainer) public CatchScoreProcessor(RulesetContainer<CatchBaseHit> rulesetContainer)
: base(rulesetContainer) : base(rulesetContainer)
{ {
} }
protected override void Reset()
{
base.Reset();
Health.Value = 1;
Accuracy.Value = 1;
}
protected override void OnNewJudgement(CatchJudgement judgement)
{
}
} }
} }

View File

@ -2,17 +2,16 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using OpenTK; using OpenTK;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Catch.UI namespace osu.Game.Rulesets.Catch.UI
{ {
public class CatchPlayfield : ScrollingPlayfield<CatchBaseHit, CatchJudgement> public class CatchPlayfield : ScrollingPlayfield
{ {
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content; private readonly Container<Drawable> content;
@ -44,22 +43,23 @@ namespace osu.Game.Rulesets.Catch.UI
}; };
} }
public override void Add(DrawableHitObject<CatchBaseHit, CatchJudgement> h) public override void Add(DrawableHitObject h)
{ {
h.Depth = (float)h.HitObject.StartTime;
base.Add(h); base.Add(h);
var fruit = (DrawableFruit)h; var fruit = (DrawableFruit)h;
fruit.CheckPosition = catcherArea.CheckIfWeCanCatch; fruit.CheckPosition = catcherArea.CheckIfWeCanCatch;
fruit.OnJudgement += Fruit_OnJudgement;
} }
private void Fruit_OnJudgement(DrawableHitObject<CatchBaseHit, CatchJudgement> obj) public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{ {
if (obj.Judgement.Result == HitResult.Hit) if (judgement.IsHit)
{ {
Vector2 screenPosition = obj.ScreenSpaceDrawQuad.Centre; Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre;
Remove(obj); Remove(judgedObject);
catcherArea.Add(obj, screenPosition); catcherArea.Add(judgedObject, screenPosition);
} }
} }
} }

View File

@ -5,7 +5,6 @@ using osu.Framework.Input;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Beatmaps; using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Scoring;
@ -15,7 +14,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch.UI namespace osu.Game.Rulesets.Catch.UI
{ {
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchBaseHit, CatchJudgement> public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchBaseHit>
{ {
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(ruleset, beatmap, isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset)
@ -26,11 +25,11 @@ namespace osu.Game.Rulesets.Catch.UI
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter(); protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield(); protected override Playfield CreatePlayfield() => new CatchPlayfield();
public override PassThroughInputManager CreateKeyBindingInputManager() => new CatchInputManager(Ruleset?.RulesetInfo); public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h) protected override DrawableHitObject<CatchBaseHit> GetVisualRepresentation(CatchBaseHit h)
{ {
if (h is Fruit) if (h is Fruit)
return new DrawableFruit(h); return new DrawableFruit(h);

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
private Catcher catcher; private Catcher catcher;
public void Add(DrawableHitObject<CatchBaseHit, CatchJudgement> fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition); public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.Position) < catcher.DrawSize.X / DrawSize.X / 2; public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.Position) < catcher.DrawSize.X / DrawSize.X / 2;
@ -85,7 +84,7 @@ namespace osu.Game.Rulesets.Catch.UI
var additive = createCatcherSprite(); var additive = createCatcherSprite();
additive.RelativePositionAxes = Axes.Both; additive.RelativePositionAxes = Axes.Both;
additive.BlendingMode = BlendingMode.Additive; additive.Blending = BlendingMode.Additive;
additive.Position = Position; additive.Position = Position;
additive.Scale = Scale; additive.Scale = Scale;
@ -152,7 +151,7 @@ namespace osu.Game.Rulesets.Catch.UI
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime / 1800 * speed, 0, 1); X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime / 1800 * speed, 0, 1);
} }
public void AddToStack(DrawableHitObject<CatchBaseHit, CatchJudgement> fruit, Vector2 absolutePosition) public void AddToStack(DrawableHitObject fruit, Vector2 absolutePosition)
{ {
fruit.RelativePositionAxes = Axes.None; fruit.RelativePositionAxes = Axes.None;
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0); fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
@ -161,11 +160,10 @@ namespace osu.Game.Rulesets.Catch.UI
fruit.Origin = Anchor.BottomCentre; fruit.Origin = Anchor.BottomCentre;
fruit.Scale *= 0.7f; fruit.Scale *= 0.7f;
fruit.LifetimeEnd = double.MaxValue; fruit.LifetimeEnd = double.MaxValue;
fruit.Depth = (float)Time.Current;
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
while (Children.OfType<DrawableFruit>().Any(f => Vector2.DistanceSquared(f.Position, fruit.Position) < distance * distance)) while (Children.OfType<DrawableFruit>().Any(f => Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
{ {
fruit.X += RNG.Next(-5, 5); fruit.X += RNG.Next(-5, 5);
fruit.Y -= RNG.Next(0, 5); fruit.Y -= RNG.Next(0, 5);

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-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Game.Rulesets.Catch</RootNamespace> <RootNamespace>osu.Game.Rulesets.Catch</RootNamespace>
<AssemblyName>osu.Game.Rulesets.Catch</AssemblyName> <AssemblyName>osu.Game.Rulesets.Catch</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -34,7 +34,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath> <HintPath>$(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
@ -69,6 +69,7 @@
<None Include="..\osu.licenseheader"> <None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link> <Link>osu.licenseheader</Link>
</None> </None>
<None Include="app.config" />
<None Include="OpenTK.dll.config" /> <None Include="OpenTK.dll.config" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>

View File

@ -1,9 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<packages> <packages>
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" /> <package id="OpenTK" version="3.0.0-git00009" targetFramework="net461" />
</packages> </packages>

View File

@ -28,12 +28,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private Pattern lastPattern = new Pattern(); private Pattern lastPattern = new Pattern();
private FastRandom random; private FastRandom random;
private Beatmap beatmap; private Beatmap beatmap;
private bool isForCurrentRuleset;
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) private readonly int availableColumns;
private readonly bool isForCurrentRuleset;
public ManiaBeatmapConverter(bool isForCurrentRuleset, int availableColumns)
{ {
this.isForCurrentRuleset = isForCurrentRuleset; if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
this.isForCurrentRuleset = isForCurrentRuleset;
this.availableColumns = availableColumns;
}
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original)
{
beatmap = original; beatmap = original;
BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty; BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty;
@ -41,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
random = new FastRandom(seed); random = new FastRandom(seed);
return base.ConvertBeatmap(original, isForCurrentRuleset); return base.ConvertBeatmap(original);
} }
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap) protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
@ -89,7 +97,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <returns>The hit objects generated.</returns> /// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original) private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
{ {
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern); var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, availableColumns, lastPattern);
Pattern newPattern = generator.Generate(); Pattern newPattern = generator.Generate();
lastPattern = newPattern; lastPattern = newPattern;
@ -113,14 +121,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
Patterns.PatternGenerator conversion = null; Patterns.PatternGenerator conversion = null;
if (distanceData != null) if (distanceData != null)
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern); conversion = new DistanceObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern);
else if (endTimeData != null) else if (endTimeData != null)
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap); conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, availableColumns);
else if (positionData != null) else if (positionData != null)
{ {
computeDensity(original.StartTime); computeDensity(original.StartTime);
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair); conversion = new HitObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern, lastTime, lastPosition, density, lastStair);
recordNote(original.StartTime, positionData.Position); recordNote(original.StartTime, positionData.Position);
} }
@ -142,8 +150,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary> /// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{ {
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern) : base(random, hitObject, beatmap, availableColumns, previousPattern)
{ {
} }

View File

@ -29,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private PatternType convertType; private PatternType convertType;
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern) : base(random, hitObject, beatmap, availableColumns, previousPattern)
{ {
convertType = PatternType.None; convertType = PatternType.None;
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode) if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// The true distance, accounting for any repeats // The true distance, accounting for any repeats
double distance = (distanceData?.Distance ?? 0) * repeatCount; double distance = (distanceData?.Distance ?? 0) * repeatCount;
// The velocity of the osu! hit object - calculated as the velocity of a slider // The velocity of the osu! hit object - calculated as the velocity of a slider
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / (timingPoint.BeatLength * difficultyPoint.SpeedMultiplier); double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
// The duration of the osu! hit object // The duration of the osu! hit object
double osuDuration = distance / osuVelocity; double osuDuration = distance / osuVelocity;

View File

@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
private readonly double endTime; private readonly double endTime;
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap) public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns)
: base(random, hitObject, beatmap, new Pattern()) : base(random, hitObject, beatmap, availableColumns, new Pattern())
{ {
var endtimeData = HitObject as IHasEndTime; var endtimeData = HitObject as IHasEndTime;

View File

@ -20,9 +20,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly PatternType convertType; private readonly PatternType convertType;
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair) public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
: base(random, hitObject, beatmap, previousPattern) : base(random, hitObject, beatmap, availableColumns, previousPattern)
{ {
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
if (density < 0) throw new ArgumentOutOfRangeException(nameof(density));
StairType = lastStair; StairType = lastStair;
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime); TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);

View File

@ -25,11 +25,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// </summary> /// </summary>
protected readonly FastRandom Random; protected readonly FastRandom Random;
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
: base(hitObject, beatmap, previousPattern) : base(hitObject, beatmap, availableColumns, previousPattern)
{ {
Random = random; if (random == null) throw new ArgumentNullException(nameof(random));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
Random = random;
RandomStart = AvailableColumns == 8 ? 1 : 0; RandomStart = AvailableColumns == 8 ? 1 : 0;
} }
@ -62,6 +66,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <returns>The amount of notes to be generated.</returns> /// <returns>The amount of notes to be generated.</returns>
protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0) protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0)
{ {
if (p2 < 0 || p2 > 1) throw new ArgumentOutOfRangeException(nameof(p2));
if (p3 < 0 || p3 > 1) throw new ArgumentOutOfRangeException(nameof(p3));
if (p4 < 0 || p4 > 1) throw new ArgumentOutOfRangeException(nameof(p4));
if (p5 < 0 || p5 > 1) throw new ArgumentOutOfRangeException(nameof(p5));
if (p6 < 0 || p6 > 1) throw new ArgumentOutOfRangeException(nameof(p6));
double val = Random.NextDouble(); double val = Random.NextDouble();
if (val >= 1 - p6) if (val >= 1 - p6)
return 6; return 6;

View File

@ -32,13 +32,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
/// </summary> /// </summary>
protected readonly Beatmap Beatmap; protected readonly Beatmap Beatmap;
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, Pattern previousPattern) protected PatternGenerator(HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
{ {
PreviousPattern = previousPattern; if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
HitObject = hitObject; HitObject = hitObject;
Beatmap = beatmap; Beatmap = beatmap;
AvailableColumns = availableColumns;
AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); PreviousPattern = previousPattern;
} }
/// <summary> /// <summary>

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Judgements namespace osu.Game.Rulesets.Mania.Judgements
{ {
@ -145,18 +146,18 @@ namespace osu.Game.Rulesets.Mania.Judgements
/// </summary> /// </summary>
/// <param name="hitOffset">The time offset.</param> /// <param name="hitOffset">The time offset.</param>
/// <returns>The hit result, or null if the time offset results in a miss.</returns> /// <returns>The hit result, or null if the time offset results in a miss.</returns>
public ManiaHitResult? ResultFor(double hitOffset) public HitResult? ResultFor(double hitOffset)
{ {
if (hitOffset <= Perfect / 2) if (hitOffset <= Perfect / 2)
return ManiaHitResult.Perfect; return HitResult.Perfect;
if (hitOffset <= Great / 2) if (hitOffset <= Great / 2)
return ManiaHitResult.Great; return HitResult.Great;
if (hitOffset <= Good / 2) if (hitOffset <= Good / 2)
return ManiaHitResult.Good; return HitResult.Good;
if (hitOffset <= Ok / 2) if (hitOffset <= Ok / 2)
return ManiaHitResult.Ok; return HitResult.Ok;
if (hitOffset <= Bad / 2) if (hitOffset <= Bad / 2)
return ManiaHitResult.Bad; return HitResult.Meh;
return null; return null;
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Judgements namespace osu.Game.Rulesets.Mania.Judgements
{ {
public class HoldNoteTailJudgement : ManiaJudgement public class HoldNoteTailJudgement : ManiaJudgement
@ -10,27 +12,15 @@ namespace osu.Game.Rulesets.Mania.Judgements
/// </summary> /// </summary>
public bool HasBroken; public bool HasBroken;
public override int NumericResultForScore(ManiaHitResult result) protected override int NumericResultFor(HitResult result)
{ {
switch (result) switch (result)
{ {
default: default:
return base.NumericResultForScore(result); return base.NumericResultFor(result);
case ManiaHitResult.Great: case HitResult.Great:
case ManiaHitResult.Perfect: case HitResult.Perfect:
return base.NumericResultForScore(HasBroken ? ManiaHitResult.Good : result); return base.NumericResultFor(HasBroken ? HitResult.Good : result);
}
}
public override int NumericResultForAccuracy(ManiaHitResult result)
{
switch (result)
{
default:
return base.NumericResultForAccuracy(result);
case ManiaHitResult.Great:
case ManiaHitResult.Perfect:
return base.NumericResultForAccuracy(HasBroken ? ManiaHitResult.Good : result);
} }
} }
} }

View File

@ -1,13 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Judgements namespace osu.Game.Rulesets.Mania.Judgements
{ {
public class HoldNoteTickJudgement : ManiaJudgement public class HoldNoteTickJudgement : ManiaJudgement
{ {
public override bool AffectsCombo => false; public override bool AffectsCombo => false;
public override int NumericResultForScore(ManiaHitResult result) => 20; protected override int NumericResultFor(HitResult result) => 20;
public override int NumericResultForAccuracy(ManiaHitResult result) => 0; // Don't count ticks into accuracy
} }
} }

View File

@ -1,21 +0,0 @@
// 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.ComponentModel;
namespace osu.Game.Rulesets.Mania.Judgements
{
public enum ManiaHitResult
{
[Description("PERFECT")]
Perfect,
[Description("GREAT")]
Great,
[Description("GOOD")]
Good,
[Description("OK")]
Ok,
[Description("BAD")]
Bad
}
}

View File

@ -8,75 +8,22 @@ namespace osu.Game.Rulesets.Mania.Judgements
{ {
public class ManiaJudgement : Judgement public class ManiaJudgement : Judgement
{ {
/// <summary> protected override int NumericResultFor(HitResult result)
/// The maximum possible hit result.
/// </summary>
public const ManiaHitResult MAX_HIT_RESULT = ManiaHitResult.Perfect;
/// <summary>
/// The result value for the combo portion of the score.
/// </summary>
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(ManiaResult);
/// <summary>
/// The result value for the accuracy portion of the score.
/// </summary>
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(ManiaResult);
/// <summary>
/// The maximum result value for the combo portion of the score.
/// </summary>
public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
/// <summary>
/// The maximum result value for the accuracy portion of the score.
/// </summary>
public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
public override string ResultString => string.Empty;
public override string MaxResultString => string.Empty;
/// <summary>
/// The hit result.
/// </summary>
public ManiaHitResult ManiaResult;
public virtual int NumericResultForScore(ManiaHitResult result)
{ {
switch (result) switch (result)
{ {
default: default:
return 0; return 0;
case ManiaHitResult.Bad: case HitResult.Meh:
return 50; return 50;
case ManiaHitResult.Ok: case HitResult.Ok:
return 100; return 100;
case ManiaHitResult.Good: case HitResult.Good:
return 200; return 200;
case ManiaHitResult.Great: case HitResult.Great:
case ManiaHitResult.Perfect: case HitResult.Perfect:
return 300; return 300;
} }
} }
public virtual int NumericResultForAccuracy(ManiaHitResult result)
{
switch (result)
{
default:
return 0;
case ManiaHitResult.Bad:
return 50;
case ManiaHitResult.Ok:
return 100;
case ManiaHitResult.Good:
return 200;
case ManiaHitResult.Great:
return 300;
case ManiaHitResult.Perfect:
return 305;
}
}
} }
} }

View File

@ -6,6 +6,7 @@ using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using System.Collections.Generic; using System.Collections.Generic;
using System;
namespace osu.Game.Rulesets.Mania namespace osu.Game.Rulesets.Mania
{ {
@ -21,6 +22,6 @@ namespace osu.Game.Rulesets.Mania
return 0; return 0;
} }
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(); protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize)));
} }
} }

View File

@ -0,0 +1,41 @@
// 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.ComponentModel;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania
{
public class ManiaInputManager : RulesetInputManager<ManiaAction>
{
public ManiaInputManager(RulesetInfo ruleset, int variant)
: base(ruleset, variant, SimultaneousBindingMode.Unique)
{
}
}
public enum ManiaAction
{
[Description("Special")]
Special,
[Description("Key 1")]
Key1 = 10,
[Description("Key 2")]
Key2,
[Description("Key 3")]
Key3,
[Description("Key 4")]
Key4,
[Description("Key 5")]
Key5,
[Description("Key 6")]
Key6,
[Description("Key 7")]
Key7,
[Description("Key 8")]
Key8,
[Description("Key 9")]
Key9
}
}

View File

@ -6,12 +6,10 @@ using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania namespace osu.Game.Rulesets.Mania
{ {
@ -93,7 +91,7 @@ namespace osu.Game.Rulesets.Mania
{ {
Mods = new Mod[] Mods = new Mod[]
{ {
new ModAutoplay(), new ManiaModAutoplay(),
new ModCinema(), new ModCinema(),
}, },
}, },
@ -105,23 +103,55 @@ namespace osu.Game.Rulesets.Mania
} }
} }
public override Mod GetAutoplayMod() => new ModAutoplay();
public override string Description => "osu!mania"; public override string Description => "osu!mania";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[] { /* Todo: Should be keymod specific */ };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
public override int LegacyID => 3; public override int LegacyID => 3;
public ManiaRuleset(RulesetInfo rulesetInfo) public ManiaRuleset(RulesetInfo rulesetInfo)
: base(rulesetInfo) : base(rulesetInfo)
{ {
} }
public override IEnumerable<int> AvailableVariants => new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
{
var leftKeys = new[]
{
InputKey.A,
InputKey.S,
InputKey.D,
InputKey.F
};
var rightKeys = new[]
{
InputKey.J,
InputKey.K,
InputKey.L,
InputKey.Semicolon
};
ManiaAction currentKey = ManiaAction.Key1;
var bindings = new List<KeyBinding>();
for (int i = leftKeys.Length - variant / 2; i < leftKeys.Length; i++)
bindings.Add(new KeyBinding(leftKeys[i], currentKey++));
for (int i = 0; i < variant / 2; i++)
bindings.Add(new KeyBinding(rightKeys[i], currentKey++));
if (variant % 2 == 1)
bindings.Add(new KeyBinding(InputKey.Space, ManiaAction.Special));
return bindings;
}
public override string GetVariantName(int variant) => $"{variant}K";
} }
} }

View File

@ -4,6 +4,16 @@
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using System; using System;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Mods namespace osu.Game.Rulesets.Mania.Mods
{ {
@ -68,6 +78,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModFadeIn : Mod public class ManiaModFadeIn : Mod
{ {
public override string Name => "FadeIn"; public override string Name => "FadeIn";
public override string ShortenedName => "FI";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden; public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease; public override ModType Type => ModType.DifficultyIncrease;
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;
@ -75,15 +86,27 @@ namespace osu.Game.Rulesets.Mania.Mods
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };
} }
public class ManiaModRandom : Mod public class ManiaModRandom : Mod, IApplicableMod<ManiaHitObject>
{ {
public override string Name => "Random"; public override string Name => "Random";
public override string ShortenedName => "RD";
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
public override string Description => @"Shuffle around the notes!"; public override string Description => @"Shuffle around the notes!";
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{
int availableColumns = ((ManiaRulesetContainer)rulesetContainer).AvailableColumns;
var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList();
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = shuffledColumns[h.Column]);
}
} }
public abstract class ManiaKeyMod : Mod public abstract class ManiaKeyMod : Mod
{ {
public override string ShortenedName => Name;
public abstract int KeyCount { get; } public abstract int KeyCount { get; }
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
public override bool Ranked => true; public override bool Ranked => true;
@ -146,8 +169,29 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKeyCoop : Mod public class ManiaModKeyCoop : Mod
{ {
public override string Name => "KeyCoop"; public override string Name => "KeyCoop";
public override string ShortenedName => "2P";
public override string Description => @"Double the key amount, double the fun!"; public override string Description => @"Double the key amount, double the fun!";
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;
public override bool Ranked => true; public override bool Ranked => true;
} }
public class ManiaModAutoplay : ModAutoplay<ManiaHitObject>
{
private int availableColumns;
public override void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{
// Todo: This shouldn't be done, we should be getting a ManiaBeatmap which should store AvailableColumns
// But this is dependent on a _lot_ of refactoring
var maniaRulesetContainer = (ManiaRulesetContainer)rulesetContainer;
availableColumns = maniaRulesetContainer.AvailableColumns;
base.ApplyToRulesetContainer(rulesetContainer);
}
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap) => new Score
{
User = new User { Username = "osu!topus!" },
Replay = new ManiaAutoGenerator(beatmap, availableColumns).Generate(),
};
}
} }

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -15,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModGravity : Mod, IGenerateSpeedAdjustments public class ManiaModGravity : Mod, IGenerateSpeedAdjustments
{ {
public override string Name => "Gravity"; public override string Name => "Gravity";
public override string ShortenedName => "GR";
public override double ScoreMultiplier => 0; public override double ScoreMultiplier => 0;
@ -23,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public void ApplyToRulesetContainer(ManiaRulesetContainer rulesetContainer, ref List<SpeedAdjustmentContainer>[] hitObjectTimingChanges, ref List<SpeedAdjustmentContainer> barlineTimingChanges) public void ApplyToRulesetContainer(ManiaRulesetContainer rulesetContainer, ref List<SpeedAdjustmentContainer>[] hitObjectTimingChanges, ref List<SpeedAdjustmentContainer> barlineTimingChanges)
{ {
// We have to generate one speed adjustment per hit object for gravity // We have to generate one speed adjustment per hit object for gravity
foreach (ManiaHitObject obj in rulesetContainer.Objects) foreach (ManiaHitObject obj in rulesetContainer.Objects.OfType<ManiaHitObject>())
{ {
MultiplierControlPoint controlPoint = rulesetContainer.CreateControlPointAt(obj.StartTime); MultiplierControlPoint controlPoint = rulesetContainer.CreateControlPointAt(obj.StartTime);
// Beat length has too large of an effect for gravity, so we'll force it to a constant value for now // Beat length has too large of an effect for gravity, so we'll force it to a constant value for now

View File

@ -1,30 +1,32 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Configuration;
using OpenTK.Input;
using osu.Framework.Input;
using OpenTK; using OpenTK;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Input.Bindings;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
/// <summary> /// <summary>
/// Visualises a <see cref="HoldNote"/> hit object. /// Visualises a <see cref="HoldNote"/> hit object.
/// </summary> /// </summary>
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote> public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
{ {
private readonly DrawableNote head; private readonly DrawableNote head;
private readonly DrawableNote tail; private readonly DrawableNote tail;
private readonly GlowPiece glowPiece;
private readonly BodyPiece bodyPiece; private readonly BodyPiece bodyPiece;
private readonly Container<DrawableHoldNoteTick> tickContainer; private readonly Container<DrawableHoldNoteTick> tickContainer;
private readonly Container fullHeightContainer;
/// <summary> /// <summary>
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note. /// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
@ -36,21 +38,26 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
private bool hasBroken; private bool hasBroken;
public DrawableHoldNote(HoldNote hitObject, Bindable<Key> key = null) public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
: base(hitObject, key) : base(hitObject, action)
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Height = (float)HitObject.Duration; Height = (float)HitObject.Duration;
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
// For now the body piece covers the entire height of the container // The hit object itself cannot be used for various elements because the tail overshoots it
// whereas possibly in the future we don't want to extend under the head/tail. // So a specialized container that is updated to contain the tail height is used
// This will be fixed when new designs are given or the current design is finalized. fullHeightContainer = new Container
{
RelativeSizeAxes = Axes.X,
Child = glowPiece = new GlowPiece()
},
bodyPiece = new BodyPiece bodyPiece = new BodyPiece
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
}, },
tickContainer = new Container<DrawableHoldNoteTick> tickContainer = new Container<DrawableHoldNoteTick>
{ {
@ -58,12 +65,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime), RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime),
RelativeChildSize = new Vector2(1, (float)HitObject.Duration) RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
}, },
head = new DrawableHeadNote(this, key) head = new DrawableHeadNote(this, action)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
}, },
tail = new DrawableTailNote(this, key) tail = new DrawableTailNote(this, action)
{ {
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
@ -96,6 +103,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
tickContainer.Children.ForEach(t => t.AccentColour = value); tickContainer.Children.ForEach(t => t.AccentColour = value);
glowPiece.AccentColour = value;
bodyPiece.AccentColour = value; bodyPiece.AccentColour = value;
head.AccentColour = value; head.AccentColour = value;
tail.AccentColour = value; tail.AccentColour = value;
@ -106,16 +114,26 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override void Update()
{ {
// Make sure the keypress happened within the body of the hold note base.Update();
// Make the body piece not lie under the head note
bodyPiece.Y = head.Height;
bodyPiece.Height = DrawHeight - head.Height;
// Make the fullHeightContainer "contain" the height of the tail note, keeping in mind
// that the tail note overshoots the height of this hit object
fullHeightContainer.Height = DrawHeight + tail.Height;
}
public bool OnPressed(ManiaAction action)
{
// Make sure the action happened within the body of the hold note
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime) if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
return false; return false;
if (args.Key != Key) if (action != Action)
return false;
if (args.Repeat)
return false; return false;
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed // The user has pressed during the body of the hold note, after the head note and its hit windows have passed
@ -126,19 +144,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return true; return true;
} }
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) public bool OnReleased(ManiaAction action)
{ {
// Make sure that the user started holding the key during the hold note // Make sure that the user started holding the key during the hold note
if (!holdStartTime.HasValue) if (!holdStartTime.HasValue)
return false; return false;
if (args.Key != Key) if (action != Action)
return false; return false;
holdStartTime = null; holdStartTime = null;
// If the key has been released too early, the user should not receive full score for the release // If the key has been released too early, the user should not receive full score for the release
if (!tail.Judged) if (!tail.AllJudged)
hasBroken = true; hasBroken = true;
return true; return true;
@ -151,26 +169,28 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
private readonly DrawableHoldNote holdNote; private readonly DrawableHoldNote holdNote;
public DrawableHeadNote(DrawableHoldNote holdNote, Bindable<Key> key = null) public DrawableHeadNote(DrawableHoldNote holdNote, ManiaAction action)
: base(holdNote.HitObject.Head, key) : base(holdNote.HitObject.Head, action)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
RelativePositionAxes = Axes.None; RelativePositionAxes = Axes.None;
Y = 0; Y = 0;
// Life time managed by the parent DrawableHoldNote
LifetimeStart = double.MinValue;
LifetimeEnd = double.MaxValue;
GlowPiece.Alpha = 0;
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public override bool OnPressed(ManiaAction action)
{ {
if (!base.OnKeyDown(state, args)) if (!base.OnPressed(action))
return false;
// We only want to trigger a holding state from the head if the head has received a judgement
if (!Judged)
return false; return false;
// If the key has been released too early, the user should not receive full score for the release // If the key has been released too early, the user should not receive full score for the release
if (Judgement.Result == HitResult.Miss) if (Judgements.Any(j => j.Result == HitResult.Miss))
holdNote.hasBroken = true; holdNote.hasBroken = true;
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held // The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
@ -188,38 +208,58 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
private readonly DrawableHoldNote holdNote; private readonly DrawableHoldNote holdNote;
public DrawableTailNote(DrawableHoldNote holdNote, Bindable<Key> key = null) public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
: base(holdNote.HitObject.Tail, key) : base(holdNote.HitObject.Tail, action)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
RelativePositionAxes = Axes.None; RelativePositionAxes = Axes.None;
Y = 0; Y = 0;
// Life time managed by the parent DrawableHoldNote
LifetimeStart = double.MinValue;
LifetimeEnd = double.MaxValue;
GlowPiece.Alpha = 0;
} }
protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement(); protected override void CheckForJudgements(bool userTriggered, double timeOffset)
protected override void CheckJudgement(bool userTriggered)
{ {
base.CheckJudgement(userTriggered); if (!userTriggered)
{
if (timeOffset > HitObject.HitWindows.Bad / 2)
{
AddJudgement(new HoldNoteTailJudgement
{
Result = HitResult.Miss,
HasBroken = holdNote.hasBroken
});
}
var tailJudgement = Judgement as HoldNoteTailJudgement; return;
if (tailJudgement == null) }
double offset = Math.Abs(timeOffset);
if (offset > HitObject.HitWindows.Miss / 2)
return; return;
tailJudgement.HasBroken = holdNote.hasBroken; AddJudgement(new HoldNoteTailJudgement
{
Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss,
HasBroken = holdNote.hasBroken
});
} }
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down
public override bool OnReleased(ManiaAction action)
{ {
// Make sure that the user started holding the key during the hold note // Make sure that the user started holding the key during the hold note
if (!holdNote.holdStartTime.HasValue) if (!holdNote.holdStartTime.HasValue)
return false; return false;
if (Judgement.Result != HitResult.None) if (action != Action)
return false;
if (args.Key != Key)
return false; return false;
UpdateJudgement(true); UpdateJudgement(true);
@ -227,12 +267,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
// Handled by the hold note, which will set holding = false // Handled by the hold note, which will set holding = false
return false; return false;
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
// Tail doesn't handle key down
return false;
}
} }
} }
} }

View File

@ -23,11 +23,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public Func<double?> HoldStartTime; public Func<double?> HoldStartTime;
/// <summary>
/// References whether the user is currently holding the hold note.
/// </summary>
public Func<bool> IsHolding;
private readonly Container glowContainer; private readonly Container glowContainer;
public DrawableHoldNoteTick(HoldNoteTick hitObject) public DrawableHoldNoteTick(HoldNoteTick hitObject)
@ -36,9 +31,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.TopCentre; Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre; Origin = Anchor.TopCentre;
Y = (float)HitObject.StartTime;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Size = new Vector2(1); Size = new Vector2(1);
// Life time managed by the parent DrawableHoldNote
LifetimeStart = double.MinValue;
LifetimeEnd = double.MaxValue;
Children = new[] Children = new[]
{ {
glowContainer = new CircularContainer glowContainer = new CircularContainer
@ -58,9 +59,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
} }
} }
}; };
// Set the default glow
AccentColour = Color4.White;
} }
public override Color4 AccentColour public override Color4 AccentColour
@ -80,9 +78,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
} }
} }
protected override ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement(); protected override void CheckForJudgements(bool userTriggered, double timeOffset)
protected override void CheckJudgement(bool userTriggered)
{ {
if (!userTriggered) if (!userTriggered)
return; return;
@ -93,8 +89,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (HoldStartTime?.Invoke() > HitObject.StartTime) if (HoldStartTime?.Invoke() > HitObject.StartTime)
return; return;
Judgement.ManiaResult = ManiaHitResult.Perfect; AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
Judgement.Result = HitResult.Hit;
} }
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
@ -109,10 +104,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected override void Update() protected override void Update()
{ {
if (Judgement.Result != HitResult.None) if (AllJudged)
return; return;
if (IsHolding?.Invoke() != true) if (HoldStartTime?.Invoke() == null)
return; return;
UpdateJudgement(true); UpdateJudgement(true);

View File

@ -1,31 +1,30 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
public abstract class DrawableManiaHitObject<TObject> : DrawableScrollingHitObject<ManiaHitObject, ManiaJudgement> public abstract class DrawableManiaHitObject<TObject> : DrawableScrollingHitObject<ManiaHitObject>
where TObject : ManiaHitObject where TObject : ManiaHitObject
{ {
/// <summary> /// <summary>
/// The key that will trigger input for this hit object. /// The key that will trigger input for this hit object.
/// </summary> /// </summary>
protected Bindable<Key> Key { get; private set; } = new Bindable<Key>(); protected ManiaAction Action { get; }
public new TObject HitObject; public new TObject HitObject;
protected DrawableManiaHitObject(TObject hitObject, Bindable<Key> key = null) protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null)
: base(hitObject) : base(hitObject)
{ {
RelativePositionAxes = Axes.Y;
HitObject = hitObject; HitObject = hitObject;
if (key != null) if (action != null)
Key.BindTo(key); Action = action.Value;
} }
public override Color4 AccentColour public override Color4 AccentColour
@ -38,7 +37,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.AccentColour = value; base.AccentColour = value;
} }
} }
protected override ManiaJudgement CreateJudgement() => new ManiaJudgement();
} }
} }

View File

@ -3,10 +3,8 @@
using System; using System;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -16,21 +14,33 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// <summary> /// <summary>
/// Visualises a <see cref="Note"/> hit object. /// Visualises a <see cref="Note"/> hit object.
/// </summary> /// </summary>
public class DrawableNote : DrawableManiaHitObject<Note> public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
{ {
protected readonly GlowPiece GlowPiece;
private readonly LaneGlowPiece laneGlowPiece;
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, Bindable<Key> key = null) public DrawableNote(Note hitObject, ManiaAction action)
: base(hitObject, key) : base(hitObject, action)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 100; AutoSizeAxes = Axes.Y;
Add(headPiece = new NotePiece Children = new Drawable[]
{
laneGlowPiece = new LaneGlowPiece
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
GlowPiece = new GlowPiece(),
headPiece = new NotePiece
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
}); }
};
} }
public override Color4 AccentColour public override Color4 AccentColour
@ -42,57 +52,41 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return; return;
base.AccentColour = value; base.AccentColour = value;
laneGlowPiece.AccentColour = value;
GlowPiece.AccentColour = value;
headPiece.AccentColour = value; headPiece.AccentColour = value;
} }
} }
protected override void CheckJudgement(bool userTriggered) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (!userTriggered) if (!userTriggered)
{ {
if (Judgement.TimeOffset > HitObject.HitWindows.Bad / 2) if (timeOffset > HitObject.HitWindows.Bad / 2)
Judgement.Result = HitResult.Miss; AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
return; return;
} }
double offset = Math.Abs(Judgement.TimeOffset); double offset = Math.Abs(timeOffset);
if (offset > HitObject.HitWindows.Miss / 2) if (offset > HitObject.HitWindows.Miss / 2)
return; return;
ManiaHitResult? tmpResult = HitObject.HitWindows.ResultFor(offset); AddJudgement(new ManiaJudgement { Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss });
if (tmpResult.HasValue)
{
Judgement.Result = HitResult.Hit;
Judgement.ManiaResult = tmpResult.Value;
}
else
Judgement.Result = HitResult.Miss;
} }
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {
switch (State)
{
case ArmedState.Hit:
Colour = Color4.Green;
break;
}
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public virtual bool OnPressed(ManiaAction action)
{ {
if (Judgement.Result != HitResult.None) if (action != Action)
return false;
if (args.Key != Key)
return false;
if (args.Repeat)
return false; return false;
return UpdateJudgement(true); return UpdateJudgement(true);
} }
public virtual bool OnReleased(ManiaAction action) => false;
} }
} }

View File

@ -1,7 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Caching;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -14,22 +17,61 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary> /// </summary>
internal class BodyPiece : Container, IHasAccentColour internal class BodyPiece : Container, IHasAccentColour
{ {
private readonly Box box; private readonly Container subtractionLayer;
private readonly Drawable background;
private readonly BufferedContainer foreground;
private readonly BufferedContainer subtractionContainer;
public BodyPiece() public BodyPiece()
{ {
RelativeSizeAxes = Axes.Both; Blending = BlendingMode.Additive;
Children = new[] Children = new[]
{ {
box = new Box background = new Box { RelativeSizeAxes = Axes.Both },
foreground = new BufferedContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.3f CacheDrawnFrameBuffer = true,
Children = new Drawable[]
{
new Box { RelativeSizeAxes = Axes.Both },
subtractionContainer = new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
// This is needed because we're blending with another object
BackgroundColour = Color4.White.Opacity(0),
CacheDrawnFrameBuffer = true,
// The 'hole' is achieved by subtracting the result of this container with the parent
Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract },
Child = subtractionLayer = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
// Height computed in Update
Width = 1,
Masking = true,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
}
}
} }
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
updateAccentColour();
}
private Color4 accentColour; private Color4 accentColour;
public Color4 AccentColour public Color4 AccentColour
{ {
@ -40,8 +82,51 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
return; return;
accentColour = value; accentColour = value;
box.Colour = accentColour; updateAccentColour();
} }
}
private Cached subtractionCache = new Cached();
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) > 0)
subtractionCache.Invalidate();
return base.Invalidate(invalidation, source, shallPropagate);
}
protected override void Update()
{
base.Update();
if (!subtractionCache.IsValid)
{
subtractionLayer.Width = 5;
subtractionLayer.Height = Math.Max(0, DrawHeight - DrawWidth);
subtractionLayer.EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.White,
Type = EdgeEffectType.Glow,
Radius = DrawWidth
};
foreground.ForceRedraw();
subtractionContainer.ForceRedraw();
subtractionCache.Validate();
}
}
private void updateAccentColour()
{
if (!IsLoaded)
return;
foreground.Colour = AccentColour.Opacity(0.4f);
background.Colour = AccentColour.Opacity(0.2f);
subtractionCache.Invalidate();
} }
} }
} }

View File

@ -0,0 +1,65 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{
public class GlowPiece : CompositeDrawable, IHasAccentColour
{
private const float glow_alpha = 0.7f;
private const float glow_radius = 5;
public GlowPiece()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
InternalChild = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
};
}
protected override void LoadComplete()
{
base.LoadComplete();
updateGlow();
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
updateGlow();
}
}
private void updateGlow()
{
if (!IsLoaded)
return;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = AccentColour.Opacity(glow_alpha),
Radius = glow_radius,
Hollow = true
};
}
}
}

View File

@ -0,0 +1,85 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{
public class LaneGlowPiece : CompositeDrawable, IHasAccentColour
{
private const float total_height = 100;
private const float glow_height = 50;
private const float glow_alpha = 0.4f;
private const float edge_alpha = 0.3f;
public LaneGlowPiece()
{
BypassAutoSizeAxes = Axes.Both;
RelativeSizeAxes = Axes.X;
Height = total_height;
InternalChildren = new[]
{
new Container
{
Name = "Left edge",
RelativeSizeAxes = Axes.Y,
Width = 1,
Children = createGradient(edge_alpha)
},
new Container
{
Name = "Right edge",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = 1,
Children = createGradient(edge_alpha)
},
new Container
{
Name = "Glow",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Height = glow_height,
Children = createGradient(glow_alpha)
}
};
}
private Drawable[] createGradient(float alpha) => new Drawable[]
{
new Box
{
Name = "Top",
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Blending = BlendingMode.Additive,
Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha))
},
new Box
{
Name = "Bottom",
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Blending = BlendingMode.Additive,
Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent)
}
};
public Color4 AccentColour
{
get { return Colour; }
set { Colour = value; }
}
}
}

View File

@ -37,6 +37,17 @@ namespace osu.Game.Rulesets.Mania.Objects
} }
} }
public override int Column
{
get { return base.Column; }
set
{
base.Column = value;
Head.Column = value;
Tail.Column = value;
}
}
/// <summary> /// <summary>
/// The head note of the hold. /// The head note of the hold.
/// </summary> /// </summary>
@ -80,7 +91,8 @@ namespace osu.Game.Rulesets.Mania.Objects
{ {
ret.Add(new HoldNoteTick ret.Add(new HoldNoteTick
{ {
StartTime = t StartTime = t,
Column = Column
}); });
} }

View File

@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Mania.Objects
{ {
public abstract class ManiaHitObject : HitObject, IHasColumn public abstract class ManiaHitObject : HitObject, IHasColumn
{ {
public int Column { get; set; } public virtual int Column { get; set; }
} }
} }

View File

@ -1,7 +1,3 @@
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<configuration> <configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/> <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/> <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>

View File

@ -0,0 +1,133 @@
// 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.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
namespace osu.Game.Rulesets.Mania.Replays
{
internal class ManiaAutoGenerator : AutoGenerator<ManiaHitObject>
{
private const double release_delay = 20;
private readonly int availableColumns;
public ManiaAutoGenerator(Beatmap<ManiaHitObject> beatmap, int availableColumns)
: base(beatmap)
{
this.availableColumns = availableColumns;
Replay = new Replay { User = new User { Username = @"Autoplay" } };
}
protected Replay Replay;
public override Replay Generate()
{
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
Replay.Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None));
double[] holdEndTimes = new double[availableColumns];
for (int i = 0; i < availableColumns; i++)
holdEndTimes[i] = double.NegativeInfinity;
// Notes are handled row-by-row
foreach (var objGroup in Beatmap.HitObjects.GroupBy(h => h.StartTime))
{
double groupTime = objGroup.Key;
int activeColumns = 0;
// Get the previously held-down active columns
for (int i = 0; i < availableColumns; i++)
{
if (holdEndTimes[i] > groupTime)
activeColumns |= 1 << i;
}
// Add on the group columns, keeping track of the held notes for the next rows
foreach (var obj in objGroup)
{
var holdNote = obj as HoldNote;
if (holdNote != null)
holdEndTimes[obj.Column] = Math.Max(holdEndTimes[obj.Column], holdNote.EndTime);
activeColumns |= 1 << obj.Column;
}
Replay.Frames.Add(new ReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None));
// Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated
foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key))
{
var groupEndTime = obj.Key;
int activeColumnsAtEnd = 0;
for (int i = 0; i < availableColumns; i++)
{
if (holdEndTimes[i] > groupEndTime)
activeColumnsAtEnd |= 1 << i;
}
Replay.Frames.Add(new ReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None));
}
}
Replay.Frames = Replay.Frames
// Pick the maximum activeColumns for all frames at the same time
.GroupBy(f => f.Time)
.Select(g => new ReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None))
// The addition of release frames above maybe result in unordered frames, but we need them ordered
.OrderBy(f => f.Time)
.ToList();
return Replay;
}
/// <summary>
/// Finds the maximum <see cref="ReplayFrame.MouseX"/> by count of bits from a grouping of <see cref="ReplayFrame"/>s.
/// </summary>
/// <param name="group">The <see cref="ReplayFrame"/> grouping to search.</param>
/// <returns>The maximum <see cref="ReplayFrame.MouseX"/> by count of bits.</returns>
private float maxMouseX(IGrouping<double, ReplayFrame> group)
{
int currentCount = -1;
int currentMax = 0;
foreach (var val in group)
{
int newCount = countBits((int)(val.MouseX ?? 0));
if (newCount > currentCount)
{
currentCount = newCount;
currentMax = (int)(val.MouseX ?? 0);
}
}
return currentMax;
}
/// <summary>
/// Counts the number of bits set in a value.
/// </summary>
/// <param name="value">The value to count.</param>
/// <returns>The number of set bits.</returns>
private int countBits(int value)
{
int count = 0;
while (value > 0)
{
if ((value & 1) > 0)
count++;
value >>= 1;
}
return count;
}
}
}

View File

@ -0,0 +1,35 @@
// 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.Input;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Mania.Replays
{
internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler
{
public ManiaFramedReplayInputHandler(Replay replay)
: base(replay)
{
}
public override List<InputState> GetPendingStates()
{
var actions = new List<ManiaAction>();
int activeColumns = (int)(CurrentFrame.MouseX ?? 0);
int counter = 0;
while (activeColumns > 0)
{
if ((activeColumns & 1) > 0)
actions.Add(ManiaAction.Key1 + counter);
counter++;
activeColumns >>= 1;
}
return new List<InputState> { new ReplayState<ManiaAction> { PressedActions = actions } };
}
}
}

View File

@ -1,9 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -12,34 +12,8 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Scoring namespace osu.Game.Rulesets.Mania.Scoring
{ {
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject, ManiaJudgement> internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject>
{ {
/// <summary>
/// The maximum score achievable.
/// Does _not_ include bonus score - for bonus score see <see cref="bonusScore"/>.
/// </summary>
private const int max_score = 1000000;
/// <summary>
/// The amount of the score attributed to combo.
/// </summary>
private const double combo_portion_max = max_score * 0.2;
/// <summary>
/// The amount of the score attributed to accuracy.
/// </summary>
private const double accuracy_portion_max = max_score * 0.8;
/// <summary>
/// The factor used to determine relevance of combos.
/// </summary>
private const double combo_base = 4;
/// <summary>
/// The combo value at which hit objects result in the max score possible.
/// </summary>
private const int combo_relevance_cap = 400;
/// <summary> /// <summary>
/// The hit HP multiplier at OD = 0. /// The hit HP multiplier at OD = 0.
/// </summary> /// </summary>
@ -115,52 +89,16 @@ namespace osu.Game.Rulesets.Mania.Scoring
/// </summary> /// </summary>
private double hpMultiplier = 1; private double hpMultiplier = 1;
/// <summary>
/// The cumulative combo portion of the score.
/// </summary>
private double comboScore => combo_portion_max * comboPortion / maxComboPortion;
/// <summary>
/// The cumulative accuracy portion of the score.
/// </summary>
private double accuracyScore => accuracy_portion_max * Math.Pow(Accuracy, 4) * totalHits / maxTotalHits;
/// <summary>
/// The cumulative bonus score.
/// This is added on top of <see cref="max_score"/>, thus the total score can exceed <see cref="max_score"/>.
/// </summary>
private double bonusScore;
/// <summary>
/// The <see cref="comboPortion"/> achieved by a perfect playthrough.
/// </summary>
private double maxComboPortion;
/// <summary>
/// The portion of the score dedicated to combo.
/// </summary>
private double comboPortion;
/// <summary>
/// The <see cref="totalHits"/> achieved by a perfect playthrough.
/// </summary>
private int maxTotalHits;
/// <summary>
/// The total hits.
/// </summary>
private int totalHits;
public ManiaScoreProcessor() public ManiaScoreProcessor()
{ {
} }
public ManiaScoreProcessor(RulesetContainer<ManiaHitObject, ManiaJudgement> rulesetContainer) public ManiaScoreProcessor(RulesetContainer<ManiaHitObject> rulesetContainer)
: base(rulesetContainer) : base(rulesetContainer)
{ {
} }
protected override void ComputeTargets(Beatmap<ManiaHitObject> beatmap) protected override void SimulateAutoplay(Beatmap<ManiaHitObject> beatmap)
{ {
BeatmapDifficulty difficulty = beatmap.BeatmapInfo.Difficulty; BeatmapDifficulty difficulty = beatmap.BeatmapInfo.Difficulty;
hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max); hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max);
@ -172,40 +110,18 @@ namespace osu.Game.Rulesets.Mania.Scoring
{ {
var holdNote = obj as HoldNote; var holdNote = obj as HoldNote;
if (obj is Note) if (holdNote != null)
{
AddJudgement(new ManiaJudgement
{
Result = HitResult.Hit,
ManiaResult = ManiaHitResult.Perfect
});
}
else if (holdNote != null)
{ {
// Head // Head
AddJudgement(new ManiaJudgement AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
{
Result = HitResult.Hit,
ManiaResult = ManiaJudgement.MAX_HIT_RESULT
});
// Ticks // Ticks
int tickCount = holdNote.Ticks.Count(); int tickCount = holdNote.Ticks.Count();
for (int i = 0; i < tickCount; i++) for (int i = 0; i < tickCount; i++)
{ AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
AddJudgement(new HoldNoteTickJudgement
{
Result = HitResult.Hit,
ManiaResult = ManiaJudgement.MAX_HIT_RESULT,
});
} }
AddJudgement(new HoldNoteTailJudgement AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
{
Result = HitResult.Hit,
ManiaResult = ManiaJudgement.MAX_HIT_RESULT
});
}
} }
if (!HasFailed) if (!HasFailed)
@ -214,81 +130,45 @@ namespace osu.Game.Rulesets.Mania.Scoring
hpMultiplier *= 1.01; hpMultiplier *= 1.01;
hpMissMultiplier *= 0.98; hpMissMultiplier *= 0.98;
Reset(); Reset(false);
}
} }
maxTotalHits = totalHits; protected override void OnNewJudgement(Judgement judgement)
maxComboPortion = comboPortion;
}
protected override void OnNewJudgement(ManiaJudgement judgement)
{ {
base.OnNewJudgement(judgement);
bool isTick = judgement is HoldNoteTickJudgement; bool isTick = judgement is HoldNoteTickJudgement;
if (!isTick) if (isTick)
totalHits++; {
if (judgement.IsHit)
Health.Value += hpMultiplier * hp_increase_tick;
}
else
{
switch (judgement.Result) switch (judgement.Result)
{ {
case HitResult.Miss: case HitResult.Miss:
Health.Value += hpMissMultiplier * hp_increase_miss; Health.Value += hpMissMultiplier * hp_increase_miss;
break; break;
case HitResult.Hit: case HitResult.Meh:
if (isTick)
{
Health.Value += hpMultiplier * hp_increase_tick;
bonusScore += judgement.ResultValueForScore;
}
else
{
switch (judgement.ManiaResult)
{
case ManiaHitResult.Bad:
Health.Value += hpMultiplier * hp_increase_bad; Health.Value += hpMultiplier * hp_increase_bad;
break; break;
case ManiaHitResult.Ok: case HitResult.Ok:
Health.Value += hpMultiplier * hp_increase_ok; Health.Value += hpMultiplier * hp_increase_ok;
break; break;
case ManiaHitResult.Good: case HitResult.Good:
Health.Value += hpMultiplier * hp_increase_good; Health.Value += hpMultiplier * hp_increase_good;
break; break;
case ManiaHitResult.Great: case HitResult.Great:
Health.Value += hpMultiplier * hp_increase_great; Health.Value += hpMultiplier * hp_increase_great;
break; break;
case ManiaHitResult.Perfect: case HitResult.Perfect:
Health.Value += hpMultiplier * hp_increase_perfect; Health.Value += hpMultiplier * hp_increase_perfect;
break; break;
} }
}
// A factor that is applied to make higher combos more relevant
double comboRelevance = Math.Min(Math.Max(0.5, Math.Log(Combo.Value, combo_base)), Math.Log(combo_relevance_cap, combo_base));
comboPortion += judgement.ResultValueForScore * comboRelevance;
}
break;
}
int scoreForAccuracy = 0;
int maxScoreForAccuracy = 0;
foreach (var j in Judgements)
{
scoreForAccuracy += j.ResultValueForAccuracy;
maxScoreForAccuracy += j.MaxResultValueForAccuracy;
}
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
TotalScore.Value = comboScore + accuracyScore + bonusScore;
}
protected override void Reset()
{
base.Reset();
Health.Value = 1;
bonusScore = 0;
comboPortion = 0;
totalHits = 0;
} }
} }
} }

View File

@ -3,24 +3,21 @@
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using System; using System;
using osu.Framework.Configuration; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class Column : ScrollingPlayfield<ManiaHitObject, ManiaJudgement>, IHasAccentColour public class Column : ScrollingPlayfield, IHasAccentColour
{ {
private const float key_icon_size = 10; private const float key_icon_size = 10;
private const float key_icon_corner_radius = 3; private const float key_icon_corner_radius = 3;
@ -32,18 +29,21 @@ namespace osu.Game.Rulesets.Mania.UI
private const float column_width = 45; private const float column_width = 45;
private const float special_column_width = 70; private const float special_column_width = 70;
/// <summary> public ManiaAction Action;
/// The key that will trigger input actions for this column and hit objects contained inside it.
/// </summary>
public Bindable<Key> Key = new Bindable<Key>();
private readonly Box background; private readonly Box background;
private readonly Container hitTargetBar; private readonly Container hitTargetBar;
private readonly Container keyIcon; private readonly Container keyIcon;
internal readonly Container TopLevelContainer;
private readonly Container explosionContainer;
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content; private readonly Container<Drawable> content;
private const float opacity_released = 0.1f;
private const float opacity_pressed = 0.25f;
public Column() public Column()
: base(Axes.Y) : base(Axes.Y)
{ {
@ -53,9 +53,9 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
background = new Box background = new Box
{ {
Name = "Foreground", Name = "Background",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.2f Alpha = opacity_released
}, },
new Container new Container
{ {
@ -101,8 +101,13 @@ namespace osu.Game.Rulesets.Mania.UI
// For column lighting, we need to capture input events before the notes // For column lighting, we need to capture input events before the notes
new InputTarget new InputTarget
{ {
KeyDown = onKeyDown, Pressed = onPressed,
KeyUp = onKeyUp Released = onReleased
},
explosionContainer = new Container
{
Name = "Hit explosions",
RelativeSizeAxes = Axes.Both
} }
} }
}, },
@ -141,8 +146,11 @@ namespace osu.Game.Rulesets.Mania.UI
} }
} }
} }
} },
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
}; };
TopLevelContainer.Add(explosionContainer.CreateProxy());
} }
public override Axes RelativeSizeAxes => Axes.Y; public override Axes RelativeSizeAxes => Axes.Y;
@ -193,31 +201,38 @@ namespace osu.Game.Rulesets.Mania.UI
/// Adds a DrawableHitObject to this Playfield. /// Adds a DrawableHitObject to this Playfield.
/// </summary> /// </summary>
/// <param name="hitObject">The DrawableHitObject to add.</param> /// <param name="hitObject">The DrawableHitObject to add.</param>
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject) public override void Add(DrawableHitObject hitObject)
{ {
hitObject.Depth = (float)hitObject.HitObject.StartTime;
hitObject.AccentColour = AccentColour; hitObject.AccentColour = AccentColour;
HitObjects.Add(hitObject); HitObjects.Add(hitObject);
} }
private bool onKeyDown(InputState state, KeyDownEventArgs args) public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{ {
if (args.Repeat) if (!judgement.IsHit)
return false; return;
if (args.Key == Key) explosionContainer.Add(new HitExplosion(judgedObject));
}
private bool onPressed(ManiaAction action)
{ {
background.FadeTo(background.Alpha + 0.2f, 50, Easing.OutQuint); if (action == Action)
{
background.FadeTo(opacity_pressed, 50, Easing.OutQuint);
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint); keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
} }
return false; return false;
} }
private bool onKeyUp(InputState state, KeyUpEventArgs args) private bool onReleased(ManiaAction action)
{ {
if (args.Key == Key) if (action == Action)
{ {
background.FadeTo(0.2f, 800, Easing.OutQuart); background.FadeTo(opacity_released, 800, Easing.OutQuart);
keyIcon.ScaleTo(1f, 400, Easing.OutQuart); keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
} }
@ -227,10 +242,10 @@ namespace osu.Game.Rulesets.Mania.UI
/// <summary> /// <summary>
/// This is a simple container which delegates various input events that have to be captured before the notes. /// This is a simple container which delegates various input events that have to be captured before the notes.
/// </summary> /// </summary>
private class InputTarget : Container private class InputTarget : Container, IKeyBindingHandler<ManiaAction>
{ {
public Func<InputState, KeyDownEventArgs, bool> KeyDown; public Func<ManiaAction, bool> Pressed;
public Func<InputState, KeyUpEventArgs, bool> KeyUp; public Func<ManiaAction, bool> Released;
public InputTarget() public InputTarget()
{ {
@ -239,8 +254,8 @@ namespace osu.Game.Rulesets.Mania.UI
Alpha = 0; Alpha = 0;
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => KeyDown?.Invoke(state, args) ?? false; public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false;
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => KeyUp?.Invoke(state, args) ?? false; public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false;
} }
} }
} }

View File

@ -0,0 +1,34 @@
// 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.Graphics;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Mania.UI
{
internal class DrawableManiaJudgement : DrawableJudgement
{
public DrawableManiaJudgement(Judgement judgement)
: base(judgement)
{
JudgementText.TextSize = 25;
}
protected override void LoadComplete()
{
base.LoadComplete();
this.FadeInFromZero(50, Easing.OutQuint);
if (Judgement.IsHit)
{
this.ScaleTo(0.8f);
this.ScaleTo(1, 250, Easing.OutElastic);
this.Delay(50).FadeOut(200).ScaleTo(0.75f, 250);
}
Expire();
}
}
}

View File

@ -0,0 +1,64 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.UI
{
internal class HitExplosion : CompositeDrawable
{
private readonly Box inner;
public HitExplosion(DrawableHitObject judgedObject)
{
bool isTick = judgedObject is DrawableHoldNoteTick;
Anchor = Anchor.TopCentre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
Size = new Vector2(isTick ? 0.5f : 1);
FillMode = FillMode.Fit;
Blending = BlendingMode.Additive;
Color4 accent = isTick ? Color4.White : judgedObject.AccentColour;
InternalChild = new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = 1,
BorderColour = accent,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = accent,
Radius = 10,
Hollow = true
},
Child = inner = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = accent,
Alpha = 1,
AlwaysPresent = true,
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500).Expire();
inner.FadeOut(250);
}
}
}

View File

@ -6,30 +6,24 @@ using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using System; using System;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using OpenTK.Input;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaPlayfield : ScrollingPlayfield<ManiaHitObject, ManiaJudgement> public class ManiaPlayfield : ScrollingPlayfield
{ {
public const float HIT_TARGET_POSITION = 50; public const float HIT_TARGET_POSITION = 50;
/// <summary>
/// Default column keys, expanding outwards from the middle as more column are added.
/// E.g. 2 columns use FJ, 4 columns use DFJK, 6 use SDFJKL, etc...
/// </summary>
private static readonly Key[] default_keys = { Key.A, Key.S, Key.D, Key.F, Key.J, Key.K, Key.L, Key.Semicolon };
private SpecialColumnPosition specialColumnPosition; private SpecialColumnPosition specialColumnPosition;
/// <summary> /// <summary>
/// The style to use for the special column. /// The style to use for the special column.
@ -45,6 +39,11 @@ namespace osu.Game.Rulesets.Mania.UI
} }
} }
/// <summary>
/// Whether this playfield should be inverted. This flips everything inside the playfield.
/// </summary>
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
private readonly FlowContainer<Column> columns; private readonly FlowContainer<Column> columns;
public IEnumerable<Column> Columns => columns.Children; public IEnumerable<Column> Columns => columns.Children;
@ -54,6 +53,8 @@ namespace osu.Game.Rulesets.Mania.UI
private List<Color4> normalColumnColours = new List<Color4>(); private List<Color4> normalColumnColours = new List<Color4>();
private Color4 specialColumnColour; private Color4 specialColumnColour;
private readonly Container<DrawableManiaJudgement> judgements;
private readonly int columnCount; private readonly int columnCount;
public ManiaPlayfield(int columnCount) public ManiaPlayfield(int columnCount)
@ -64,21 +65,23 @@ namespace osu.Game.Rulesets.Mania.UI
if (columnCount <= 0) if (columnCount <= 0)
throw new ArgumentException("Can't have zero or fewer columns."); throw new ArgumentException("Can't have zero or fewer columns.");
Inverted.Value = true;
Container topLevelContainer;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new Container new Container
{ {
Name = "Playfield elements",
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Y,
Masking = true, AutoSizeAxes = Axes.X,
Children = new Drawable[] Children = new Drawable[]
{ {
new Container new Container
{ {
Name = "Masked elements", Name = "Columns mask",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Masking = true, Masking = true,
@ -86,6 +89,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
new Box new Box
{ {
Name = "Background",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Black Colour = Color4.Black
}, },
@ -97,39 +101,63 @@ namespace osu.Game.Rulesets.Mania.UI
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Left = 1, Right = 1 }, Padding = new MarginPadding { Left = 1, Right = 1 },
Spacing = new Vector2(1, 0) Spacing = new Vector2(1, 0)
} },
} }
}, },
new Container new Container
{ {
Name = "Barlines mask",
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Y,
Padding = new MarginPadding { Top = HIT_TARGET_POSITION }, Width = 1366, // Bar lines should only be masked on the vertical axis
Children = new[] BypassAutoSizeAxes = Axes.Both,
{ Masking = true,
content = new Container Child = content = new Container
{ {
Name = "Bar lines", Name = "Bar lines",
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
// Width is set in the Update method Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
}
}
} }
},
judgements = new Container<DrawableManiaJudgement>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Y = HIT_TARGET_POSITION + 150,
BypassAutoSizeAxes = Axes.Both
},
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
} }
} }
}; };
var currentAction = ManiaAction.Key1;
for (int i = 0; i < columnCount; i++) for (int i = 0; i < columnCount; i++)
{ {
var c = new Column(); var c = new Column();
c.VisibleTimeRange.BindTo(VisibleTimeRange); c.VisibleTimeRange.BindTo(VisibleTimeRange);
c.IsSpecial = isSpecialColumn(i);
c.Action = c.IsSpecial ? ManiaAction.Special : currentAction++;
topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
columns.Add(c); columns.Add(c);
AddNested(c); AddNested(c);
} }
Inverted.ValueChanged += invertedChanged;
Inverted.TriggerChange();
}
private void invertedChanged(bool newValue)
{
Scale = new Vector2(1, newValue ? -1 : 1);
judgements.Scale = Scale;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -144,15 +172,11 @@ namespace osu.Game.Rulesets.Mania.UI
specialColumnColour = colours.BlueDark; specialColumnColour = colours.BlueDark;
// Set the special column + colour + key // Set the special column + colour + key
for (int i = 0; i < columnCount; i++) foreach (var column in Columns)
{ {
Column column = Columns.ElementAt(i);
column.IsSpecial = isSpecialColumn(i);
if (!column.IsSpecial) if (!column.IsSpecial)
continue; continue;
column.Key.Value = Key.Space;
column.AccentColour = specialColumnColour; column.AccentColour = specialColumnColour;
} }
@ -166,21 +190,19 @@ namespace osu.Game.Rulesets.Mania.UI
nonSpecialColumns[i].AccentColour = colour; nonSpecialColumns[i].AccentColour = colour;
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour; nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
} }
// We'll set the keys for non-special columns in another separate loop because it's not mirrored like the above colours
// Todo: This needs to go when we get to bindings and use Button1, ..., ButtonN instead
for (int i = 0; i < nonSpecialColumns.Count; i++)
{
Column column = nonSpecialColumns[i];
int keyOffset = default_keys.Length / 2 - nonSpecialColumns.Count / 2 + i;
if (keyOffset >= 0 && keyOffset < default_keys.Length)
column.Key.Value = default_keys[keyOffset];
else
// There is no default key defined for this column. Let's set this to Unknown for now
// however note that this will be gone after bindings are in place
column.Key.Value = Key.Unknown;
} }
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
var maniaObject = (ManiaHitObject)judgedObject.HitObject;
columns[maniaObject.Column].OnJudgement(judgedObject, judgement);
judgements.Clear();
judgements.Add(new DrawableManiaJudgement(judgement)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
} }
/// <summary> /// <summary>
@ -202,7 +224,8 @@ namespace osu.Game.Rulesets.Mania.UI
} }
} }
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> h) => Columns.ElementAt(h.HitObject.Column).Add(h); public override void Add(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column).Add(h);
public void Add(DrawableBarLine barline) => HitObjects.Add(barline); public void Add(DrawableBarLine barline) => HitObjects.Add(barline);
protected override void Update() protected override void Update()

View File

@ -5,36 +5,37 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenTK; using OpenTK;
using OpenTK.Input;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Lists; using osu.Framework.Lists;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Beatmaps; using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mania.Timing; using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject, ManiaJudgement> public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject>
{ {
/// <summary> /// <summary>
/// Preferred column count. This will only have an effect during the initialization of the play field. /// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which
/// the beatmap converter will attempt to convert beatmaps to use.
/// </summary> /// </summary>
public int PreferredColumns; public int AvailableColumns { get; private set; }
public IEnumerable<DrawableBarLine> BarLines; public IEnumerable<DrawableBarLine> BarLines;
@ -75,36 +76,47 @@ namespace osu.Game.Rulesets.Mania.UI
BarLines.ForEach(Playfield.Add); BarLines.ForEach(Playfield.Add);
} }
protected override void ApplyBeatmap() protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(AvailableColumns)
{
base.ApplyBeatmap();
PreferredColumns = (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize));
}
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(PreferredColumns)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
// Invert by default for now (should be moved to config/skin later)
Scale = new Vector2(1, -1)
}; };
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(); public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, AvailableColumns);
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h) protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter()
{ {
Bindable<Key> key = Playfield.Columns.ElementAt(h.Column).Key; if (IsForCurrentRuleset)
AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize));
else
{
float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count;
if (percentSliderOrSpinner < 0.2)
AvailableColumns = 7;
else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5)
AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6)
AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4;
else
AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7));
}
return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns);
}
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
{
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
var holdNote = h as HoldNote; var holdNote = h as HoldNote;
if (holdNote != null) if (holdNote != null)
return new DrawableHoldNote(holdNote, key); return new DrawableHoldNote(holdNote, action);
var note = h as Note; var note = h as Note;
if (note != null) if (note != null)
return new DrawableNote(note, key); return new DrawableNote(note, action);
return null; return null;
} }
@ -112,5 +124,7 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f); protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic); protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic);
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
} }
} }

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-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Game.Rulesets.Mania</RootNamespace> <RootNamespace>osu.Game.Rulesets.Mania</RootNamespace>
<AssemblyName>osu.Game.Rulesets.Mania</AssemblyName> <AssemblyName>osu.Game.Rulesets.Mania</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -34,7 +34,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath> <HintPath>$(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
@ -60,7 +60,6 @@
<Compile Include="Judgements\HitWindows.cs" /> <Compile Include="Judgements\HitWindows.cs" />
<Compile Include="Judgements\HoldNoteTailJudgement.cs" /> <Compile Include="Judgements\HoldNoteTailJudgement.cs" />
<Compile Include="Judgements\HoldNoteTickJudgement.cs" /> <Compile Include="Judgements\HoldNoteTickJudgement.cs" />
<Compile Include="Judgements\ManiaHitResult.cs" />
<Compile Include="Judgements\ManiaJudgement.cs" /> <Compile Include="Judgements\ManiaJudgement.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" /> <Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="Mods\IGenerateSpeedAdjustments.cs" /> <Compile Include="Mods\IGenerateSpeedAdjustments.cs" />
@ -70,8 +69,12 @@
<Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" /> <Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
<Compile Include="Objects\Drawables\DrawableNote.cs" /> <Compile Include="Objects\Drawables\DrawableNote.cs" />
<Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\LaneGlowPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\NotePiece.cs" /> <Compile Include="Objects\Drawables\Pieces\NotePiece.cs" />
<Compile Include="Objects\Types\IHasColumn.cs" /> <Compile Include="Objects\Types\IHasColumn.cs" />
<Compile Include="Replays\ManiaAutoGenerator.cs" />
<Compile Include="Replays\ManiaFramedReplayInputHandler.cs" />
<Compile Include="Scoring\ManiaScoreProcessor.cs" /> <Compile Include="Scoring\ManiaScoreProcessor.cs" />
<Compile Include="Objects\BarLine.cs" /> <Compile Include="Objects\BarLine.cs" />
<Compile Include="Objects\HoldNote.cs" /> <Compile Include="Objects\HoldNote.cs" />
@ -79,9 +82,12 @@
<Compile Include="Objects\ManiaHitObject.cs" /> <Compile Include="Objects\ManiaHitObject.cs" />
<Compile Include="Objects\Note.cs" /> <Compile Include="Objects\Note.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ManiaInputManager.cs" />
<Compile Include="Timing\GravityScrollingContainer.cs" /> <Compile Include="Timing\GravityScrollingContainer.cs" />
<Compile Include="Timing\ScrollingAlgorithm.cs" /> <Compile Include="Timing\ScrollingAlgorithm.cs" />
<Compile Include="UI\Column.cs" /> <Compile Include="UI\Column.cs" />
<Compile Include="UI\DrawableManiaJudgement.cs" />
<Compile Include="UI\HitExplosion.cs" />
<Compile Include="UI\ManiaRulesetContainer.cs" /> <Compile Include="UI\ManiaRulesetContainer.cs" />
<Compile Include="UI\ManiaPlayfield.cs" /> <Compile Include="UI\ManiaPlayfield.cs" />
<Compile Include="ManiaRuleset.cs" /> <Compile Include="ManiaRuleset.cs" />
@ -95,14 +101,6 @@
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project> <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name> <Name>osu.Framework</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj"> <ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project> <Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
<Name>osu.Game</Name> <Name>osu.Game</Name>
@ -112,6 +110,7 @@
<None Include="..\osu.licenseheader"> <None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link> <Link>osu.licenseheader</Link>
</None> </None>
<None Include="app.config" />
<None Include="OpenTK.dll.config" /> <None Include="OpenTK.dll.config" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>

View File

@ -1,8 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<packages> <packages>
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" /> <package id="OpenTK" version="3.0.0-git00009" targetFramework="net461" />
</packages> </packages>

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK; using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Beatmaps; using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
@ -64,8 +64,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
//We are no longer within stacking range of the next object. //We are no longer within stacking range of the next object.
break; break;
if (Vector2.Distance(stackBaseObject.Position, objectN.Position) < stack_distance || if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance ||
stackBaseObject is Slider && Vector2.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance) stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
{ {
stackBaseIndex = n; stackBaseIndex = n;
@ -130,14 +130,14 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
* o <- hitCircle has stack of -1 * o <- hitCircle has stack of -1
* o <- hitCircle has stack of -2 * o <- hitCircle has stack of -2
*/ */
if (objectN is Slider && Vector2.Distance(objectN.EndPosition, objectI.Position) < stack_distance) if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{ {
int offset = objectI.StackHeight - objectN.StackHeight + 1; int offset = objectI.StackHeight - objectN.StackHeight + 1;
for (int j = n + 1; j <= i; j++) for (int j = n + 1; j <= i; j++)
{ {
//For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above). //For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above).
OsuHitObject objectJ = beatmap.HitObjects[j]; OsuHitObject objectJ = beatmap.HitObjects[j];
if (Vector2.Distance(objectN.EndPosition, objectJ.Position) < stack_distance) if (Vector2Extensions.Distance(objectN.EndPosition, objectJ.Position) < stack_distance)
objectJ.StackHeight -= offset; objectJ.StackHeight -= offset;
} }
@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
break; break;
} }
if (Vector2.Distance(objectN.Position, objectI.Position) < stack_distance) if (Vector2Extensions.Distance(objectN.Position, objectI.Position) < stack_distance)
{ {
//Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out. //Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out.
//NOTE: Sliders with start positions stacking are a special case that is also handled here. //NOTE: Sliders with start positions stacking are a special case that is also handled here.
@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
//We are no longer within stacking range of the previous object. //We are no longer within stacking range of the previous object.
break; break;
if (Vector2.Distance(objectN.EndPosition, objectI.Position) < stack_distance) if (Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{ {
objectN.StackHeight = objectI.StackHeight + 1; objectN.StackHeight = objectI.StackHeight + 1;
objectI = objectN; objectI = objectN;

View File

@ -4,49 +4,31 @@
using OpenTK; using OpenTK;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Framework.Extensions; using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Judgements namespace osu.Game.Rulesets.Osu.Judgements
{ {
public class OsuJudgement : Judgement public class OsuJudgement : Judgement
{ {
public override HitResult MaxResult => HitResult.Great;
/// <summary> /// <summary>
/// The positional hit offset. /// The positional hit offset.
/// </summary> /// </summary>
public Vector2 PositionOffset; public Vector2 PositionOffset;
/// <summary> protected override int NumericResultFor(HitResult result)
/// The score the user achieved.
/// </summary>
public OsuScoreResult Score;
/// <summary>
/// The score which would be achievable on a perfect hit.
/// </summary>
public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
public override string ResultString => Score.GetDescription();
public override string MaxResultString => MaxScore.GetDescription();
public int ScoreValue => scoreToInt(Score);
public int MaxScoreValue => scoreToInt(MaxScore);
private int scoreToInt(OsuScoreResult result)
{ {
switch (result) switch (result)
{ {
default: default:
return 0; return 0;
case OsuScoreResult.Hit50: case HitResult.Meh:
return 50; return 50;
case OsuScoreResult.Hit100: case HitResult.Good:
return 100; return 100;
case OsuScoreResult.Hit300: case HitResult.Great:
return 300; return 300;
case OsuScoreResult.SliderTick:
return 10;
} }
} }

View File

@ -7,8 +7,13 @@ using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Mods namespace osu.Game.Rulesets.Osu.Mods
{ {
@ -28,10 +33,23 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
} }
public class OsuModHardRock : ModHardRock public class OsuModHardRock : ModHardRock, IApplicableMod<OsuHitObject>
{ {
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
public override bool Ranked => true; public override bool Ranked => true;
public void ApplyToRulesetContainer(RulesetContainer<OsuHitObject> rulesetContainer)
{
rulesetContainer.Objects.OfType<OsuHitObject>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Y));
rulesetContainer.Objects.OfType<Slider>().ForEach(s =>
{
var newControlPoints = new List<Vector2>();
s.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y)));
s.ControlPoints = newControlPoints;
s.Curve?.Calculate(); // Recalculate the slider curve
});
}
} }
public class OsuModSuddenDeath : ModSuddenDeath public class OsuModSuddenDeath : ModSuddenDeath
@ -78,6 +96,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModSpunOut : Mod public class OsuModSpunOut : Mod
{ {
public override string Name => "Spun Out"; public override string Name => "Spun Out";
public override string ShortenedName => "SO";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout; public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
public override string Description => @"Spinners will be automatically completed"; public override string Description => @"Spinners will be automatically completed";
public override double ScoreMultiplier => 0.9; public override double ScoreMultiplier => 0.9;
@ -88,6 +107,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModAutopilot : Mod public class OsuModAutopilot : Mod
{ {
public override string Name => "Autopilot"; public override string Name => "Autopilot";
public override string ShortenedName => "AP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot; public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
public override string Description => @"Automatic cursor movement - just follow the rhythm."; public override string Description => @"Automatic cursor movement - just follow the rhythm.";
public override double ScoreMultiplier => 0; public override double ScoreMultiplier => 0;
@ -108,6 +128,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModTarget : Mod public class OsuModTarget : Mod
{ {
public override string Name => "Target"; public override string Name => "Target";
public override string ShortenedName => "TP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target; public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
public override string Description => @""; public override string Description => @"";
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;

View File

@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
new Box new Box
{ {
Size = new Vector2(width), Size = new Vector2(width),
BlendingMode = BlendingMode.Additive, Blending = BlendingMode.Additive,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Alpha = 0.5f, Alpha = 0.5f,

View File

@ -7,6 +7,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using OpenTK; using OpenTK;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
@ -38,9 +39,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Colour = AccentColour, Colour = AccentColour,
Hit = () => Hit = () =>
{ {
if (Judgement.Result != HitResult.None) return false; if (AllJudged)
return false;
Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value
UpdateJudgement(true); UpdateJudgement(true);
return true; return true;
}, },
@ -65,24 +66,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Size = circle.DrawSize; Size = circle.DrawSize;
} }
protected override void CheckJudgement(bool userTriggered) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (!userTriggered) if (!userTriggered)
{ {
if (Judgement.TimeOffset > HitObject.HitWindowFor(OsuScoreResult.Hit50)) if (timeOffset > HitObject.HitWindowFor(HitResult.Meh))
Judgement.Result = HitResult.Miss; AddJudgement(new OsuJudgement { Result = HitResult.Miss });
return; return;
} }
double hitOffset = Math.Abs(Judgement.TimeOffset); AddJudgement(new OsuJudgement
if (hitOffset < HitObject.HitWindowFor(OsuScoreResult.Hit50))
{ {
Judgement.Result = HitResult.Hit; Result = HitObject.ScoreResultForOffset(Math.Abs(timeOffset)),
Judgement.Score = HitObject.ScoreResultForOffset(hitOffset); PositionOffset = Vector2.Zero //todo: set to correct value
} });
else
Judgement.Result = HitResult.Miss;
} }
protected override void UpdateInitialState() protected override void UpdateInitialState()

View File

@ -3,12 +3,12 @@
using System.ComponentModel; using System.ComponentModel;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using System.Linq;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject, OsuJudgement> public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject>
{ {
public const float TIME_PREEMPT = 600; public const float TIME_PREEMPT = 600;
public const float TIME_FADEIN = 400; public const float TIME_FADEIN = 400;
@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Alpha = 0; Alpha = 0;
} }
protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.Hit300 };
protected sealed override void UpdateState(ArmedState state) protected sealed override void UpdateState(ArmedState state)
{ {
FinishTransforms(); FinishTransforms();
@ -33,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
UpdatePreemptState(); UpdatePreemptState();
using (BeginDelayedSequence(TIME_PREEMPT + Judgement.TimeOffset, true)) using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
UpdateCurrentState(state); UpdateCurrentState(state);
} }
} }
@ -51,6 +49,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected virtual void UpdateCurrentState(ArmedState state) protected virtual void UpdateCurrentState(ArmedState state)
{ {
} }
private OsuInputManager osuActionInputManager;
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
} }
public enum ComboResult public enum ComboResult
@ -62,18 +63,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
[Description(@"Amazing")] [Description(@"Amazing")]
Perfect Perfect
} }
public enum OsuScoreResult
{
[Description(@"Miss")]
Miss,
[Description(@"50")]
Hit50,
[Description(@"100")]
Hit100,
[Description(@"300")]
Hit300,
[Description(@"10")]
SliderTick
}
} }

View File

@ -9,9 +9,10 @@ using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
public class DrawableOsuJudgement : DrawableJudgement<OsuJudgement> public class DrawableOsuJudgement : DrawableJudgement
{ {
public DrawableOsuJudgement(OsuJudgement judgement) : base(judgement) public DrawableOsuJudgement(OsuJudgement judgement)
: base(judgement)
{ {
} }

View File

@ -8,6 +8,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
@ -64,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Scale = s.Scale, Scale = s.Scale,
ComboColour = s.ComboColour, ComboColour = s.ComboColour,
Samples = s.Samples, Samples = s.Samples,
}), })
}; };
components.Add(body); components.Add(body);
@ -114,33 +115,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
bouncer2.Position = slider.Curve.PositionAt(body.SnakedEnd ?? 0); bouncer2.Position = slider.Curve.PositionAt(body.SnakedEnd ?? 0);
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice. //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
if (initialCircle.Judgement?.Result != HitResult.Hit) if (!initialCircle.Judgements.Any(j => j.IsHit))
initialCircle.Position = slider.Curve.PositionAt(progress); initialCircle.Position = slider.Curve.PositionAt(progress);
foreach (var c in components) c.UpdateProgress(progress, repeat); foreach (var c in components) c.UpdateProgress(progress, repeat);
foreach (var t in ticks.Children) t.Tracking = ball.Tracking; foreach (var t in ticks.Children) t.Tracking = ball.Tracking;
} }
protected override void CheckJudgement(bool userTriggered) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (!userTriggered && Time.Current >= slider.EndTime) if (!userTriggered && Time.Current >= slider.EndTime)
{ {
var ticksCount = ticks.Children.Count + 1; var ticksCount = ticks.Children.Count + 1;
var ticksHit = ticks.Children.Count(t => t.Judgement.Result == HitResult.Hit); var ticksHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit));
if (initialCircle.Judgement.Result == HitResult.Hit) if (initialCircle.Judgements.Any(j => j.IsHit))
ticksHit++; ticksHit++;
var hitFraction = (double)ticksHit / ticksCount; var hitFraction = (double)ticksHit / ticksCount;
if (hitFraction == 1 && initialCircle.Judgement.Score == OsuScoreResult.Hit300) if (hitFraction == 1 && initialCircle.Judgements.Any(j => j.Result == HitResult.Great))
Judgement.Score = OsuScoreResult.Hit300; AddJudgement(new OsuJudgement { Result = HitResult.Great });
else if (hitFraction >= 0.5 && initialCircle.Judgement.Score >= OsuScoreResult.Hit100) else if (hitFraction >= 0.5 && initialCircle.Judgements.Any(j => j.Result >= HitResult.Good))
Judgement.Score = OsuScoreResult.Hit100; AddJudgement(new OsuJudgement { Result = HitResult.Good });
else if (hitFraction > 0) else if (hitFraction > 0)
Judgement.Score = OsuScoreResult.Hit50; AddJudgement(new OsuJudgement { Result = HitResult.Meh });
else else
Judgement.Score = OsuScoreResult.Miss; AddJudgement(new OsuJudgement { Result = HitResult.Miss });
Judgement.Result = Judgement.Score != OsuScoreResult.Miss ? HitResult.Hit : HitResult.Miss;
} }
} }

View File

@ -4,10 +4,10 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public override bool RemoveWhenNotAlive => false; public override bool RemoveWhenNotAlive => false;
protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.SliderTick };
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick) public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
{ {
this.sliderTick = sliderTick; this.sliderTick = sliderTick;
@ -49,13 +47,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}; };
} }
protected override void CheckJudgement(bool userTriggered) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (Judgement.TimeOffset >= 0) if (timeOffset >= 0)
{ AddJudgement(new OsuJudgement { Result = Tracking ? HitResult.Great : HitResult.Miss });
Judgement.Result = Tracking ? HitResult.Hit : HitResult.Miss;
Judgement.Score = Tracking ? OsuScoreResult.SliderTick : OsuScoreResult.Miss;
}
} }
protected override void UpdatePreemptState() protected override void UpdatePreemptState()

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -10,6 +11,7 @@ using OpenTK.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Screens.Ranking; using osu.Game.Screens.Ranking;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
@ -106,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1); public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1);
protected override void CheckJudgement(bool userTriggered) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (Time.Current < HitObject.StartTime) return; if (Time.Current < HitObject.StartTime) return;
@ -128,26 +130,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (!userTriggered && Time.Current >= spinner.EndTime) if (!userTriggered && Time.Current >= spinner.EndTime)
{ {
if (Progress >= 1) if (Progress >= 1)
{ AddJudgement(new OsuJudgement { Result = HitResult.Great });
Judgement.Score = OsuScoreResult.Hit300;
Judgement.Result = HitResult.Hit;
}
else if (Progress > .9) else if (Progress > .9)
{ AddJudgement(new OsuJudgement { Result = HitResult.Good });
Judgement.Score = OsuScoreResult.Hit100;
Judgement.Result = HitResult.Hit;
}
else if (Progress > .75) else if (Progress > .75)
{ AddJudgement(new OsuJudgement { Result = HitResult.Meh });
Judgement.Score = OsuScoreResult.Hit50; else if (Time.Current >= spinner.EndTime)
Judgement.Result = HitResult.Hit; AddJudgement(new OsuJudgement { Result = HitResult.Miss });
}
else
{
Judgement.Score = OsuScoreResult.Miss;
if (Time.Current >= spinner.EndTime)
Judgement.Result = HitResult.Miss;
}
} }
} }
@ -165,6 +154,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
glow.Colour = colours.BlueDark; glow.Colour = colours.BlueDark;
} }
protected override void Update()
{
disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton);
base.Update();
}
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
new TrianglesPiece new TrianglesPiece
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
BlendingMode = BlendingMode.Additive, Blending = BlendingMode.Additive,
Alpha = 0.5f, Alpha = 0.5f,
} }
}; };

View File

@ -16,14 +16,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
BlendingMode = BlendingMode.Additive; Blending = BlendingMode.Additive;
Alpha = 0; Alpha = 0;
Children = new Drawable[] Children = new Drawable[]
{ {
new TrianglesPiece new TrianglesPiece
{ {
BlendingMode = BlendingMode.Additive, Blending = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.2f, Alpha = 0.2f,
} }

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
BlendingMode = BlendingMode.Additive; Blending = BlendingMode.Additive;
Alpha = 0; Alpha = 0;
Children = new Drawable[] Children = new Drawable[]

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
BlendingMode = BlendingMode.Additive, Blending = BlendingMode.Additive,
Alpha = 0.5f Alpha = 0.5f
} }
}; };

View File

@ -1,10 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
@ -37,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
this.slider = slider; this.slider = slider;
Masking = true; Masking = true;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
BlendingMode = BlendingMode.Additive; Blending = BlendingMode.Additive;
Origin = Anchor.Centre; Origin = Anchor.Centre;
BorderThickness = 10; BorderThickness = 10;
BorderColour = Color4.Orange; BorderColour = Color4.Orange;
@ -96,11 +98,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return base.OnMouseMove(state); return base.OnMouseMove(state);
} }
// If the current time is between the start and end of the slider, we should track mouse input regardless of the cursor position.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => canCurrentlyTrack || base.ReceiveMouseInputAt(screenSpacePos);
private bool tracking; private bool tracking;
public bool Tracking public bool Tracking
{ {
get { return tracking; } get { return tracking; }
set private set
{ {
if (value == tracking) return; if (value == tracking) return;
@ -117,8 +122,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{ {
base.Update(); base.Update();
// Make sure to use the base version of ReceiveMouseInputAt so that we correctly check the position.
if (Time.Current < slider.EndTime) if (Time.Current < slider.EndTime)
Tracking = canCurrentlyTrack && lastState != null && ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && lastState.Mouse.HasMainButtonPressed; Tracking = canCurrentlyTrack && lastState != null && base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false);
} }
public void UpdateProgress(double progress, int repeat) public void UpdateProgress(double progress, int repeat)

Some files were not shown because too many files have changed in this diff Show More