1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-06 07:42:55 +08:00

Merge branch 'master' into mania-step-interval

This commit is contained in:
Dean Herbert 2018-06-07 20:26:33 +09:00 committed by GitHub
commit 2c25e5e8da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
78 changed files with 551 additions and 679 deletions

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (catch)" type="DotNetProject" factoryName=".NET Project"> <configuration default="false" name="RulesetTests (catch)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe" /> <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" /> <option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj" /> <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" /> <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project"> <configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe" /> <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" /> <option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj" /> <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" /> <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project"> <configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe" /> <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" /> <option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj" /> <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" /> <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (taiko)" type="DotNetProject" factoryName=".NET Project"> <configuration default="false" name="RulesetTests (taiko)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe" /> <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" /> <option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj" /> <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" /> <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="VisualTests (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs />
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Tests/osu.Game.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<method />
</configuration>
</component>

View File

@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net471/osu!.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs />
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<method />
</configuration>
</component>

72
.vscode/launch.json vendored
View File

@ -2,63 +2,7 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "VisualTests (Debug, net471)", "name": "VisualTests (Debug)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Release/net471/osu.Game.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net471/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net471/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Debug, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
@ -66,12 +10,12 @@
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll" "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll"
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Debug, dotnet)", "preLaunchTask": "Build tests (Debug)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Release, netcoreapp2.1)", "name": "VisualTests (Release)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
@ -79,12 +23,12 @@
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll" "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll"
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Release, dotnet)", "preLaunchTask": "Build tests (Release)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! (Debug, netcoreapp2.1)", "name": "osu! (Debug)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
@ -92,12 +36,12 @@
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll", "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug, dotnet)", "preLaunchTask": "Build osu! (Debug)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! (Release, netcoreapp2.1)", "name": "osu! (Release)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
@ -105,7 +49,7 @@
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll", "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release, dotnet)", "preLaunchTask": "Build osu! (Release)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
} }

44
.vscode/tasks.json vendored
View File

@ -4,34 +4,7 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "Build (Debug, msbuild)", "label": "Build osu! (Debug)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build (Release, msbuild)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:Configuration=Release",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build osu! (Debug, dotnet)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
@ -47,7 +20,7 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build osu! (Release, dotnet)", "label": "Build osu! (Release)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
@ -64,7 +37,7 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build tests (Debug, dotnet)", "label": "Build tests (Debug)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
@ -80,7 +53,7 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build tests (Release, dotnet)", "label": "Build tests (Release)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
@ -96,15 +69,6 @@
"group": "build", "group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
"restore"
],
"problemMatcher": []
},
{ {
"label": "Restore (netcoreapp2.1)", "label": "Restore (netcoreapp2.1)",
"type": "shell", "type": "shell",

View File

@ -53,10 +53,10 @@ namespace osu.Game.Rulesets.Catch.Tests
return beatmap; return beatmap;
} }
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return base.CreatePlayer(beatmap, ruleset); return base.CreatePlayer(ruleset);
} }
} }
} }

View File

@ -98,17 +98,12 @@ namespace osu.Game.Rulesets.Mania.Tests
}); });
} }
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(RulesetStore rulesets, SettingsStore settings) private void load(RulesetStore rulesets, SettingsStore settings)
{ {
maniaRuleset = rulesets.GetRuleset(3); maniaRuleset = rulesets.GetRuleset(3);
dependencies.Cache(new ManiaConfigManager(settings, maniaRuleset, 4)); Dependencies.Cache(new ManiaConfigManager(settings, maniaRuleset, 4));
} }
private ManiaPlayfield createPlayfield(int cols, bool inverted = false) private ManiaPlayfield createPlayfield(int cols, bool inverted = false)

View File

@ -5,6 +5,7 @@ using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(barLine) : base(barLine)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 1; Height = 2f;
AddInternal(new Box AddInternal(new Box
{ {
@ -36,6 +37,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = new Color4(255, 204, 33, 255),
}); });
bool isMajor = barLine.BeatIndex % (int)barLine.ControlPoint.TimeSignature == 0; bool isMajor = barLine.BeatIndex % (int)barLine.ControlPoint.TimeSignature == 0;

View File

@ -2,7 +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.Linq; using System.Linq;
using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Extensions.IEnumerableExtensions;
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;
@ -23,9 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
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 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.
@ -37,25 +35,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
private bool hasBroken; private bool hasBroken;
private readonly Container<DrawableHoldNoteTick> tickContainer;
public DrawableHoldNote(HoldNote hitObject, ManiaAction action) public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
: base(hitObject, action) : base(hitObject, action)
{ {
Container<DrawableHoldNoteTick> tickContainer;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
// The hit object itself cannot be used for various elements because the tail overshoots it
// So a specialized container that is updated to contain the tail height is used
fullHeightContainer = new Container
{
RelativeSizeAxes = Axes.X,
Child = glowPiece = new GlowPiece()
},
bodyPiece = new BodyPiece bodyPiece = new BodyPiece
{ {
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}, },
tickContainer = new Container<DrawableHoldNoteTick> tickContainer = new Container<DrawableHoldNoteTick>
@ -92,21 +82,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
base.AccentColour = value; base.AccentColour = value;
glowPiece.AccentColour = value;
bodyPiece.AccentColour = value; bodyPiece.AccentColour = value;
head.AccentColour = value; head.AccentColour = value;
tail.AccentColour = value; tail.AccentColour = value;
} tickContainer.ForEach(t => t.AccentColour = value);
}
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
// Good enough for now, we just want them to have a lifetime end
this.Delay(2000).Expire();
break;
} }
} }
@ -121,12 +100,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.Update(); base.Update();
// Make the body piece not lie under the head note // Make the body piece not lie under the head note
bodyPiece.Y = head.Height; bodyPiece.Y = head.Height / 2;
bodyPiece.Height = DrawHeight - head.Height; bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2;
// 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) public bool OnPressed(ManiaAction action)
@ -175,8 +150,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(holdNote.HitObject.Head, action) : base(holdNote.HitObject.Head, action)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
GlowPiece.Alpha = 0;
} }
public override bool OnPressed(ManiaAction action) public override bool OnPressed(ManiaAction action)
@ -194,11 +167,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return true; return true;
} }
protected override void UpdateState(ArmedState state)
{
// The holdnote keeps scrolling through for now, so having the head disappear looks weird
}
} }
/// <summary> /// <summary>
@ -219,8 +187,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(holdNote.HitObject.Tail, action) : base(holdNote.HitObject.Tail, action)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
GlowPiece.Alpha = 0;
} }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
@ -253,11 +219,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}); });
} }
protected override void UpdateState(ArmedState state)
{
// The holdnote keeps scrolling through, so having the tail disappear looks weird
}
public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down
public override bool OnReleased(ManiaAction action) public override bool OnReleased(ManiaAction action)

View File

@ -8,7 +8,6 @@ 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.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -87,16 +86,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect }); AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
} }
protected override void UpdateState(ArmedState state)
{
switch (State.Value)
{
case ArmedState.Hit:
AccentColour = Color4.Green;
break;
}
}
protected override void Update() protected override void Update()
{ {
if (AllJudged) if (AllJudged)

View File

@ -27,5 +27,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (action != null) if (action != null)
Action = action.Value; Action = action.Value;
} }
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Miss:
this.FadeOut(150, Easing.In).Expire();
break;
case ArmedState.Hit:
this.FadeOut(150, Easing.OutQuint).Expire();
break;
}
}
} }
} }

View File

@ -1,12 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 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.Extensions.Color4Extensions;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings; 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.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
@ -16,9 +17,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction> 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, ManiaAction action) public DrawableNote(Note hitObject, ManiaAction action)
@ -27,14 +25,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
CornerRadius = 5;
Masking = true;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
laneGlowPiece = new LaneGlowPiece
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
GlowPiece = new GlowPiece(),
headPiece = new NotePiece headPiece = new NotePiece
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
@ -49,9 +44,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
set set
{ {
base.AccentColour = value; base.AccentColour = value;
laneGlowPiece.AccentColour = AccentColour;
GlowPiece.AccentColour = AccentColour;
headPiece.AccentColour = AccentColour; headPiece.AccentColour = AccentColour;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = AccentColour.Lighten(1f).Opacity(0.6f),
Radius = 10,
};
} }
} }
@ -71,17 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddJudgement(new ManiaJudgement { Result = result }); AddJudgement(new ManiaJudgement { Result = result });
} }
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
case ArmedState.Miss:
this.FadeOut(100).Expire();
break;
}
}
public virtual bool OnPressed(ManiaAction action) public virtual bool OnPressed(ManiaAction action)
{ {
if (action != Action) if (action != Action)

View File

@ -123,8 +123,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
if (!IsLoaded) if (!IsLoaded)
return; return;
foreground.Colour = AccentColour.Opacity(0.4f); foreground.Colour = AccentColour.Opacity(0.9f);
background.Colour = AccentColour.Opacity(0.2f); background.Colour = AccentColour.Opacity(0.6f);
subtractionCache.Invalidate(); subtractionCache.Invalidate();
} }

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary> /// </summary>
internal class NotePiece : Container, IHasAccentColour internal class NotePiece : Container, IHasAccentColour
{ {
private const float head_height = 10; public const float NOTE_HEIGHT = 10;
private const float head_colour_height = 6; private const float head_colour_height = 6;
private readonly Box colouredBox; private readonly Box colouredBox;
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public NotePiece() public NotePiece()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = head_height; Height = NOTE_HEIGHT;
Children = new[] Children = new[]
{ {

View File

@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Mania.UI
public ManiaAction Action; public ManiaAction Action;
private readonly Box background; private readonly Box background;
private readonly Box backgroundOverlay;
private readonly Container hitTargetBar; private readonly Container hitTargetBar;
private readonly Container keyIcon; private readonly Container keyIcon;
@ -42,22 +43,32 @@ namespace osu.Game.Rulesets.Mania.UI
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(ScrollingDirection.Up) : base(ScrollingDirection.Up)
{ {
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Width = column_width; Width = column_width;
Masking = true;
CornerRadius = 5;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
background = new Box background = new Box
{ {
Name = "Background", Name = "Background",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = opacity_released Alpha = 0.3f
},
backgroundOverlay = new Box
{
Name = "Background Gradient Overlay",
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Blending = BlendingMode.Additive,
Alpha = 0
}, },
new Container new Container
{ {
@ -182,6 +193,7 @@ namespace osu.Game.Rulesets.Mania.UI
accentColour = value; accentColour = value;
background.Colour = accentColour; background.Colour = accentColour;
backgroundOverlay.Colour = ColourInfo.GradientVertical(accentColour.Opacity(0.6f), accentColour.Opacity(0));
hitTargetBar.EdgeEffect = new EdgeEffectParameters hitTargetBar.EdgeEffect = new EdgeEffectParameters
{ {
@ -223,8 +235,8 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
if (action == Action) if (action == Action)
{ {
background.FadeTo(opacity_pressed, 50, Easing.OutQuint); backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint); keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
} }
return false; return false;
@ -234,8 +246,8 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
if (action == Action) if (action == Action)
{ {
background.FadeTo(opacity_released, 800, Easing.OutQuart); backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
keyIcon.ScaleTo(1f, 400, Easing.OutQuart); keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
} }
return false; return false;

View File

@ -1,19 +1,21 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 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 OpenTK.Graphics; using OpenTK.Graphics;
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.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
internal class HitExplosion : CompositeDrawable internal class HitExplosion : CompositeDrawable
{ {
private readonly Box inner; private readonly CircularContainer circle;
public HitExplosion(DrawableHitObject judgedObject) public HitExplosion(DrawableHitObject judgedObject)
{ {
@ -22,33 +24,32 @@ namespace osu.Game.Rulesets.Mania.UI
Anchor = Anchor.TopCentre; Anchor = Anchor.TopCentre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.X;
Size = new Vector2(isTick ? 0.5f : 1); Y = NotePiece.NOTE_HEIGHT / 2;
FillMode = FillMode.Fit; Height = NotePiece.NOTE_HEIGHT;
Blending = BlendingMode.Additive; // scale roughly in-line with visual appearance of notes
Scale = new Vector2(isTick ? 0.4f : 0.8f);
Color4 accent = isTick ? Color4.White : judgedObject.AccentColour; InternalChild = circle = new CircularContainer
InternalChild = new CircularContainer
{ {
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
BorderThickness = 1, // we want our size to be very small so the glow dominates it.
BorderColour = accent, Size = new Vector2(0.1f),
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = accent, Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour, Color4.White, 0, 1),
Radius = 10, Radius = 100,
Hollow = true
}, },
Child = inner = new Box Child = new Box
{ {
Alpha = 0,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = accent, AlwaysPresent = true
Alpha = 1,
AlwaysPresent = true,
} }
}; };
} }
@ -57,8 +58,8 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
base.LoadComplete(); base.LoadComplete();
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500); circle.ResizeTo(circle.Size * new Vector2(4, 20), 1000, Easing.OutQuint);
inner.FadeOut(250); this.FadeIn(16).Then().FadeOut(500, Easing.OutQuint);
Expire(true); Expire(true);
} }

View File

@ -9,7 +9,6 @@ using osu.Framework.Configuration;
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.Game.Graphics;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
@ -78,6 +77,7 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Masking = true, Masking = true,
CornerRadius = 5,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box new Box
@ -183,15 +183,15 @@ namespace osu.Game.Rulesets.Mania.UI
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load()
{ {
normalColumnColours = new List<Color4> normalColumnColours = new List<Color4>
{ {
colours.RedDark, new Color4(94, 0, 57, 255),
colours.GreenDark new Color4(6, 84, 0, 255)
}; };
specialColumnColour = colours.BlueDark; specialColumnColour = new Color4(0, 48, 63, 255);
// Set the special column + colour + key // Set the special column + colour + key
foreach (var column in Columns) foreach (var column in Columns)

View File

@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private Bindable<double> cursorScale; private Bindable<double> cursorScale;
private Bindable<bool> autoCursorScale; private Bindable<bool> autoCursorScale;
private Bindable<WorkingBeatmap> beatmap; private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
public OsuCursor() public OsuCursor()
{ {
@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config, OsuGameBase game) private void load(OsuConfigManager config, IBindableBeatmap beatmap)
{ {
Child = cursorContainer = new SkinnableDrawable("cursor", _ => new CircularContainer Child = cursorContainer = new SkinnableDrawable("cursor", _ => new CircularContainer
{ {
@ -160,7 +160,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}; };
beatmap = game.Beatmap.GetBoundCopy(); this.beatmap.BindTo(beatmap);
beatmap.ValueChanged += v => calculateScale(); beatmap.ValueChanged += v => calculateScale();
cursorScale = config.GetBindable<double>(OsuSetting.GameplayCursorSize); cursorScale = config.GetBindable<double>(OsuSetting.GameplayCursorSize);

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
Assert.AreEqual("Deif", meta.AuthorString); Assert.AreEqual("Deif", meta.AuthorString);
Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile);
Assert.AreEqual(164471 + LegacyBeatmapDecoder.UniversalOffset, meta.PreviewTime); Assert.AreEqual(164471, meta.PreviewTime);
Assert.AreEqual(string.Empty, meta.Source); Assert.AreEqual(string.Empty, meta.Source);
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags);
Assert.AreEqual("Renatus", meta.Title); Assert.AreEqual("Renatus", meta.Title);

View File

@ -3,7 +3,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -13,12 +12,11 @@ namespace osu.Game.Tests.Visual
[Description("Player instantiated with an autoplay mod.")] [Description("Player instantiated with an autoplay mod.")]
public class TestCaseAutoplay : TestCasePlayer public class TestCaseAutoplay : TestCasePlayer
{ {
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return new ScoreAccessiblePlayer return new ScoreAccessiblePlayer
{ {
InitialBeatmap = beatmap,
AllowPause = false, AllowPause = false,
AllowLeadIn = false, AllowLeadIn = false,
AllowResults = false, AllowResults = false,

View File

@ -6,7 +6,6 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using OpenTK; using OpenTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -29,14 +28,11 @@ namespace osu.Game.Tests.Visual
private RulesetStore rulesets; private RulesetStore rulesets;
private TestBeatmapInfoWedge infoWedge; private TestBeatmapInfoWedge infoWedge;
private readonly List<IBeatmap> beatmaps = new List<IBeatmap>(); private readonly List<IBeatmap> beatmaps = new List<IBeatmap>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, RulesetStore rulesets) private void load(RulesetStore rulesets)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
beatmap.BindTo(game.Beatmap);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -53,11 +49,11 @@ namespace osu.Game.Tests.Visual
AddStep("show", () => AddStep("show", () =>
{ {
infoWedge.State = Visibility.Visible; infoWedge.State = Visibility.Visible;
infoWedge.Beatmap = beatmap; infoWedge.Beatmap = Beatmap;
}); });
// select part is redundant, but wait for load isn't // select part is redundant, but wait for load isn't
selectBeatmap(beatmap.Value.Beatmap); selectBeatmap(Beatmap.Value.Beatmap);
AddWaitStep(3); AddWaitStep(3);
@ -120,8 +116,8 @@ namespace osu.Game.Tests.Visual
{ {
selectNullBeatmap(); selectNullBeatmap();
AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text)); AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text));
AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Title); AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Title);
AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Artist); AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Artist);
AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any()); AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any());
AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any());
} }
@ -133,7 +129,7 @@ namespace osu.Game.Tests.Visual
AddStep($"select {b.Metadata.Title} beatmap", () => AddStep($"select {b.Metadata.Title} beatmap", () =>
{ {
infoBefore = infoWedge.Info; infoBefore = infoWedge.Info;
infoWedge.Beatmap = beatmap.Value = new TestWorkingBeatmap(b); infoWedge.Beatmap = Beatmap.Value = new TestWorkingBeatmap(b);
}); });
AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load");
@ -143,8 +139,8 @@ namespace osu.Game.Tests.Visual
{ {
AddStep("select null beatmap", () => AddStep("select null beatmap", () =>
{ {
beatmap.Value = beatmap.Default; Beatmap.Value = Beatmap.Default;
infoWedge.Beatmap = beatmap; infoWedge.Beatmap = Beatmap;
}); });
} }

View File

@ -35,9 +35,6 @@ namespace osu.Game.Tests.Visual
typeof(MessageFormatter) typeof(MessageFormatter)
}; };
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
public TestCaseChatLink() public TestCaseChatLink()
{ {
Add(textContainer = new TestChatLineContainer Add(textContainer = new TestChatLineContainer
@ -53,7 +50,7 @@ namespace osu.Game.Tests.Visual
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
linkColour = colours.Blue; linkColour = colours.Blue;
dependencies.Cache(new ChatOverlay Dependencies.Cache(new ChatOverlay
{ {
AvailableChannels = AvailableChannels =
{ {

View File

@ -17,14 +17,10 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Compose) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Compose) };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
Child = new Compose();
var compose = new Compose();
compose.Beatmap.BindTo(osuGame.Beatmap);
Child = compose;
} }
} }
} }

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using OpenTK; using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Overlays; using osu.Game.Overlays;
@ -18,8 +17,6 @@ namespace osu.Game.Tests.Visual
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(ScrollingTimelineContainer), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(ScrollingTimelineContainer), typeof(BeatmapWaveformGraph), typeof(TimelineButton) };
private readonly ScrollableTimeline timeline;
public TestCaseEditorComposeTimeline() public TestCaseEditorComposeTimeline()
{ {
Children = new Drawable[] Children = new Drawable[]
@ -30,7 +27,7 @@ namespace osu.Game.Tests.Visual
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
State = Visibility.Visible State = Visibility.Visible
}, },
timeline = new ScrollableTimeline new ScrollableTimeline
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -38,11 +35,5 @@ namespace osu.Game.Tests.Visual
} }
}; };
} }
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGame)
{
timeline.Beatmap.BindTo(osuGame.Beatmap);
}
} }
} }

View File

@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
var testBeatmap = new Beatmap var testBeatmap = new Beatmap
{ {
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual
} }
}; };
osuGame.Beatmap.Value = new TestWorkingBeatmap(testBeatmap); Beatmap.Value = new TestWorkingBeatmap(testBeatmap);
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock }; Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };

View File

@ -19,19 +19,16 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
SummaryTimeline summaryTimeline; Add(new SummaryTimeline
Add(summaryTimeline = new SummaryTimeline
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(500, 50) Size = new Vector2(500, 50)
}); });
summaryTimeline.Beatmap.BindTo(osuGame.Beatmap);
} }
} }
} }

View File

@ -32,15 +32,10 @@ namespace osu.Game.Tests.Visual
typeof(NotNullAttribute) typeof(NotNullAttribute)
}; };
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent);
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(new Beatmap Beatmap.Value = new TestWorkingBeatmap(new Beatmap
{ {
HitObjects = new List<HitObject> HitObjects = new List<HitObject>
{ {
@ -63,8 +58,8 @@ namespace osu.Game.Tests.Visual
}); });
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
dependencies.CacheAs<IAdjustableClock>(clock); Dependencies.CacheAs<IAdjustableClock>(clock);
dependencies.CacheAs<IFrameBasedClock>(clock); Dependencies.CacheAs<IFrameBasedClock>(clock);
Child = new OsuHitObjectComposer(new OsuRuleset()); Child = new OsuHitObjectComposer(new OsuRuleset());
} }

View File

@ -2,12 +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 NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; 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.Beatmaps;
using osu.Game.Overlays; using osu.Game.Overlays;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
@ -15,8 +12,6 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseMusicController : OsuTestCase public class TestCaseMusicController : OsuTestCase
{ {
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
public TestCaseMusicController() public TestCaseMusicController()
{ {
Clock = new FramedClock(); Clock = new FramedClock();
@ -30,13 +25,7 @@ namespace osu.Game.Tests.Visual
AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden); AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
AddStep(@"show", () => mc.State = Visibility.Visible); AddStep(@"show", () => mc.State = Visibility.Visible);
AddToggleStep(@"toggle beatmap lock", state => beatmapBacking.Disabled = state); AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
beatmapBacking.BindTo(game.Beatmap);
} }
} }
} }

View File

@ -27,7 +27,6 @@ namespace osu.Game.Tests.Visual
private RulesetStore rulesets; private RulesetStore rulesets;
private DependencyContainer dependencies;
private WorkingBeatmap defaultBeatmap; private WorkingBeatmap defaultBeatmap;
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
@ -48,8 +47,6 @@ namespace osu.Game.Tests.Visual
typeof(DrawableCarouselBeatmapSet), typeof(DrawableCarouselBeatmapSet),
}; };
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
private class TestSongSelect : PlaySongSelect private class TestSongSelect : PlaySongSelect
{ {
public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
@ -58,7 +55,7 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load()
{ {
TestSongSelect songSelect = null; TestSongSelect songSelect = null;
@ -67,10 +64,10 @@ namespace osu.Game.Tests.Visual
// this is by no means clean. should be replacing inside of OsuGameBase somehow. // this is by no means clean. should be replacing inside of OsuGameBase somehow.
IDatabaseContextFactory factory = new SingletonContextFactory(new OsuDbContext()); IDatabaseContextFactory factory = new SingletonContextFactory(new OsuDbContext());
dependencies.Cache(rulesets = new RulesetStore(factory)); Dependencies.Cache(rulesets = new RulesetStore(factory));
dependencies.Cache(manager = new BeatmapManager(storage, factory, rulesets, null, null) Dependencies.Cache(manager = new BeatmapManager(storage, factory, rulesets, null, null)
{ {
DefaultBeatmap = defaultBeatmap = game.Beatmap.Default DefaultBeatmap = defaultBeatmap = Beatmap.Default
}); });
void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () => void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () =>
@ -78,7 +75,7 @@ namespace osu.Game.Tests.Visual
if (deleteMaps) if (deleteMaps)
{ {
manager.Delete(manager.GetAllUsableBeatmapSets()); manager.Delete(manager.GetAllUsableBeatmapSets());
game.Beatmap.SetDefault(); Beatmap.SetDefault();
} }
if (songSelect != null) if (songSelect != null)

View File

@ -15,17 +15,12 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCasePlaybackControl : OsuTestCase public class TestCasePlaybackControl : OsuTestCase
{ {
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent);
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
dependencies.CacheAs<IAdjustableClock>(clock); Dependencies.CacheAs<IAdjustableClock>(clock);
dependencies.CacheAs<IFrameBasedClock>(clock); Dependencies.CacheAs<IFrameBasedClock>(clock);
var playback = new PlaybackControl var playback = new PlaybackControl
{ {
@ -34,7 +29,7 @@ namespace osu.Game.Tests.Visual
Size = new Vector2(200,100) Size = new Vector2(200,100)
}; };
playback.Beatmap.Value = new TestWorkingBeatmap(new Beatmap()); Beatmap.Value = new TestWorkingBeatmap(new Beatmap());
Child = playback; Child = playback;
} }

View File

@ -12,9 +12,10 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load(OsuGameBase game)
{ {
Beatmap.Value = new DummyWorkingBeatmap(game);
AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player
{ {
InitialBeatmap = new DummyWorkingBeatmap(game),
AllowPause = false, AllowPause = false,
AllowLeadIn = false, AllowLeadIn = false,
AllowResults = false, AllowResults = false,

View File

@ -3,7 +3,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -13,23 +12,20 @@ namespace osu.Game.Tests.Visual
[Description("Player instantiated with a replay.")] [Description("Player instantiated with a replay.")]
public class TestCaseReplay : TestCasePlayer public class TestCaseReplay : TestCasePlayer
{ {
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
// We create a dummy RulesetContainer just to get the replay - we don't want to use mods here // We create a dummy RulesetContainer just to get the replay - we don't want to use mods here
// to simulate setting a replay rather than having the replay already set for us // to simulate setting a replay rather than having the replay already set for us
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(beatmap); var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(Beatmap.Value);
// We have the replay // We have the replay
var replay = dummyRulesetContainer.Replay; var replay = dummyRulesetContainer.Replay;
// Reset the mods // Reset the mods
beatmap.Mods.Value = beatmap.Mods.Value.Where(m => !(m is ModAutoplay)); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Where(m => !(m is ModAutoplay));
return new ReplayPlayer(replay) return new ReplayPlayer(replay);
{
InitialBeatmap = beatmap
};
} }
} }
} }

View File

@ -32,18 +32,13 @@ namespace osu.Game.Tests.Visual
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
} }
private WorkingBeatmap beatmap;
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
if (beatmap == null) var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
{ if (beatmapInfo != null)
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
if (beatmapInfo != null)
beatmap = beatmaps.GetWorkingBeatmap(beatmapInfo);
}
Add(new Results(new Score Add(new Results(new Score
{ {
@ -63,10 +58,7 @@ namespace osu.Game.Tests.Visual
{ {
Username = "peppy", Username = "peppy",
} }
}) }));
{
InitialBeatmap = beatmap
});
} }
} }
} }

View File

@ -14,10 +14,6 @@ namespace osu.Game.Tests.Visual
private readonly SettingsOverlay settings; private readonly SettingsOverlay settings;
private readonly DialogOverlay dialogOverlay; private readonly DialogOverlay dialogOverlay;
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
public TestCaseSettings() public TestCaseSettings()
{ {
settings = new MainSettings settings = new MainSettings
@ -33,7 +29,7 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
dependencies.Cache(dialogOverlay); Dependencies.Cache(dialogOverlay);
Add(settings); Add(settings);
} }

View File

@ -3,7 +3,6 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
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;
@ -18,8 +17,6 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseStoryboard : OsuTestCase public class TestCaseStoryboard : OsuTestCase
{ {
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
private readonly Container<DrawableStoryboard> storyboardContainer; private readonly Container<DrawableStoryboard> storyboardContainer;
private DrawableStoryboard storyboard; private DrawableStoryboard storyboard;
@ -43,6 +40,7 @@ namespace osu.Game.Tests.Visual
}, },
}, },
}); });
Add(new MusicController Add(new MusicController
{ {
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
@ -55,10 +53,9 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load()
{ {
beatmapBacking.BindTo(game.Beatmap); Beatmap.ValueChanged += beatmapChanged;
beatmapBacking.ValueChanged += beatmapChanged;
} }
private void beatmapChanged(WorkingBeatmap working) private void beatmapChanged(WorkingBeatmap working)
@ -66,10 +63,10 @@ namespace osu.Game.Tests.Visual
private void restart() private void restart()
{ {
var track = beatmapBacking.Value.Track; var track = Beatmap.Value.Track;
track.Reset(); track.Reset();
loadStoryboard(beatmapBacking.Value); loadStoryboard(Beatmap);
track.Start(); track.Start();
} }
@ -81,7 +78,7 @@ namespace osu.Game.Tests.Visual
var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true };
storyboardContainer.Clock = decoupledClock; storyboardContainer.Clock = decoupledClock;
storyboard = working.Storyboard.CreateDrawable(beatmapBacking); storyboard = working.Storyboard.CreateDrawable(Beatmap);
storyboard.Passing = false; storyboard.Passing = false;
storyboardContainer.Add(storyboard); storyboardContainer.Add(storyboard);

View File

@ -5,11 +5,9 @@ using NUnit.Framework;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
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.Game.Beatmaps;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Screens.Edit.Screens.Compose.Timeline; using osu.Game.Screens.Edit.Screens.Compose.Timeline;
@ -19,9 +17,8 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseWaveform : OsuTestCase public class TestCaseWaveform : OsuTestCase
{ {
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>(); [BackgroundDependencyLoader]
private void load()
public TestCaseWaveform()
{ {
FillFlowContainer flow; FillFlowContainer flow;
Child = flow = new FillFlowContainer Child = flow = new FillFlowContainer
@ -46,10 +43,11 @@ namespace osu.Game.Tests.Visual
var newDisplay = new BeatmapWaveformGraph var newDisplay = new BeatmapWaveformGraph
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Resolution = 1f / i Resolution = 1f / i,
Beatmap = Beatmap
}; };
newDisplay.Beatmap.BindTo(beatmapBacking); Beatmap.ValueChanged += b => newDisplay.Beatmap = b;
flow.Add(new Container flow.Add(new Container
{ {
@ -83,8 +81,5 @@ namespace osu.Game.Tests.Visual
}); });
} }
} }
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) => beatmapBacking.BindTo(osuGame.Beatmap);
} }
} }

View File

@ -0,0 +1,75 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Diagnostics;
using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
namespace osu.Game.Beatmaps
{
/// <summary>
/// A <see cref="Bindable{WorkingBeatmap}"/> for the <see cref="OsuGame"/> beatmap.
/// This should be used sparingly in-favour of <see cref="IBindableBeatmap"/>.
/// </summary>
public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap>, IBindableBeatmap
{
private AudioManager audioManager;
private WorkingBeatmap lastBeatmap;
protected BindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue)
{
}
/// <summary>
/// Registers an <see cref="AudioManager"/> for <see cref="Track"/>s to be added to.
/// </summary>
/// <param name="audioManager">The <see cref="AudioManager"/> to register.</param>
protected void RegisterAudioManager([NotNull] AudioManager audioManager)
{
if (this.audioManager != null) throw new InvalidOperationException($"Cannot register multiple {nameof(AudioManager)}s.");
this.audioManager = audioManager;
ValueChanged += registerAudioTrack;
// If the track has changed prior to this being called, let's register it
if (Value != Default)
registerAudioTrack(Value);
}
private void registerAudioTrack(WorkingBeatmap beatmap)
{
var trackLoaded = lastBeatmap?.TrackLoaded ?? false;
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
if (!trackLoaded || lastBeatmap?.Track != beatmap.Track)
{
if (trackLoaded)
{
Debug.Assert(lastBeatmap != null);
Debug.Assert(lastBeatmap.Track != null);
lastBeatmap.RecycleTrack();
}
audioManager.Track.AddItem(beatmap.Track);
}
lastBeatmap = beatmap;
}
[NotNull]
IBindableBeatmap IBindableBeatmap.GetBoundCopy() => GetBoundCopy();
/// <summary>
/// Retrieve a new <see cref="BindableBeatmap"/> instance weakly bound to this <see cref="BindableBeatmap"/>.
/// If you are further binding to events of the retrieved <see cref="BindableBeatmap"/>, ensure a local reference is held.
/// </summary>
[NotNull]
public abstract BindableBeatmap GetBoundCopy();
}
}

View File

@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
{ {
private readonly OsuGameBase game; private readonly OsuGameBase game;
public DummyWorkingBeatmap(OsuGameBase game) public DummyWorkingBeatmap(OsuGameBase game = null)
: base(new BeatmapInfo : base(new BeatmapInfo
{ {
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
@ -43,7 +43,7 @@ namespace osu.Game.Beatmaps
protected override IBeatmap GetBeatmap() => new Beatmap(); protected override IBeatmap GetBeatmap() => new Beatmap();
protected override Texture GetBackground() => game.Textures.Get(@"Backgrounds/bg4"); protected override Texture GetBackground() => game?.Textures.Get(@"Backgrounds/bg4");
protected override Track GetTrack() => new TrackVirtual(); protected override Track GetTrack() => new TrackVirtual();

View File

@ -8,7 +8,6 @@ using System.Linq;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Framework;
namespace osu.Game.Beatmaps.Formats namespace osu.Game.Beatmaps.Formats
{ {
@ -28,23 +27,17 @@ namespace osu.Game.Beatmaps.Formats
AddDecoder<Beatmap>(@"osu file format v", m => new LegacyBeatmapDecoder(int.Parse(m.Split('v').Last()))); AddDecoder<Beatmap>(@"osu file format v", m => new LegacyBeatmapDecoder(int.Parse(m.Split('v').Last())));
} }
/// <summary>
/// lazer's audio timings in general doesn't match stable. this is the result of user testing, albeit limited.
/// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck.
/// </summary>
public static int UniversalOffset => RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? -22 : 0;
/// <summary> /// <summary>
/// Whether or not beatmap or runtime offsets should be applied. Defaults on; only disable for testing purposes. /// Whether or not beatmap or runtime offsets should be applied. Defaults on; only disable for testing purposes.
/// </summary> /// </summary>
public bool ApplyOffsets = true; public bool ApplyOffsets = true;
private readonly int offset = UniversalOffset; private readonly int offset;
public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version) public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version)
{ {
// BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off) // BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off)
offset += FormatVersion < 5 ? 24 : 0; offset = FormatVersion < 5 ? 24 : 0;
} }
protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap) protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap)

View File

@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
namespace osu.Game.Beatmaps
{
/// <summary>
/// Read-only interface for the <see cref="OsuGame"/> beatmap.
/// </summary>
public interface IBindableBeatmap : IBindable<WorkingBeatmap>
{
/// <summary>
/// Retrieve a new <see cref="IBindableBeatmap"/> instance weakly bound to this <see cref="IBindableBeatmap"/>.
/// If you are further binding to events of the retrieved <see cref="IBindableBeatmap"/>, ensure a local reference is held.
/// </summary>
IBindableBeatmap GetBoundCopy();
}
}

View File

@ -12,7 +12,7 @@ namespace osu.Game.Graphics.Containers
{ {
public class BeatSyncedContainer : Container public class BeatSyncedContainer : Container
{ {
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private int lastBeat; private int lastBeat;
private TimingControlPoint lastTimingPoint; private TimingControlPoint lastTimingPoint;
@ -74,9 +74,9 @@ namespace osu.Game.Graphics.Containers
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load(IBindableBeatmap beatmap)
{ {
Beatmap.BindTo(game.Beatmap); Beatmap.BindTo(beatmap);
} }
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -63,7 +62,8 @@ namespace osu.Game
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
public Bindable<WorkingBeatmap> Beatmap { get; private set; } private OsuBindableBeatmap beatmap;
protected BindableBeatmap Beatmap => beatmap;
private Bindable<bool> fpsDisplayVisible; private Bindable<bool> fpsDisplayVisible;
@ -157,33 +157,15 @@ namespace osu.Game
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light")); Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light"));
var defaultBeatmap = new DummyWorkingBeatmap(this); var defaultBeatmap = new DummyWorkingBeatmap(this);
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap); beatmap = new OsuBindableBeatmap(defaultBeatmap, Audio);
BeatmapManager.DefaultBeatmap = defaultBeatmap; BeatmapManager.DefaultBeatmap = defaultBeatmap;
// tracks play so loud our samples can't keep up. // tracks play so loud our samples can't keep up.
// this adds a global reduction of track volume for the time being. // this adds a global reduction of track volume for the time being.
Audio.Track.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8)); Audio.Track.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8));
Beatmap.ValueChanged += b => dependencies.CacheAs<BindableBeatmap>(beatmap);
{ dependencies.CacheAs<IBindableBeatmap>(beatmap);
var trackLoaded = lastBeatmap?.TrackLoaded ?? false;
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
if (!trackLoaded || lastBeatmap?.Track != b.Track)
{
if (trackLoaded)
{
Debug.Assert(lastBeatmap != null);
Debug.Assert(lastBeatmap.Track != null);
lastBeatmap.RecycleTrack();
}
Audio.Track.AddItem(b.Track);
}
lastBeatmap = b;
};
FileStore.Cleanup(); FileStore.Cleanup();
@ -204,6 +186,17 @@ namespace osu.Game
dependencies.Cache(globalBinding); dependencies.Cache(globalBinding);
} }
protected override void LoadComplete()
{
base.LoadComplete();
// TODO: This is temporary until we reimplement the local FPS display.
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);
fpsDisplayVisible.ValueChanged += val => { FrameStatisticsMode = val ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; };
fpsDisplayVisible.TriggerChange();
}
private void runMigrations() private void runMigrations()
{ {
try try
@ -227,19 +220,6 @@ namespace osu.Game
} }
} }
private WorkingBeatmap lastBeatmap;
protected override void LoadComplete()
{
base.LoadComplete();
// TODO: This is temporary until we reimplement the local FPS display.
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);
fpsDisplayVisible.ValueChanged += val => { FrameStatisticsMode = val ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; };
fpsDisplayVisible.TriggerChange();
}
public override void SetHost(GameHost host) public override void SetHost(GameHost host)
{ {
if (LocalConfig == null) if (LocalConfig == null)
@ -258,5 +238,26 @@ namespace osu.Game
} }
public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray(); public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray();
private class OsuBindableBeatmap : BindableBeatmap
{
public OsuBindableBeatmap(WorkingBeatmap defaultValue, AudioManager audioManager)
: this(defaultValue)
{
RegisterAudioManager(audioManager);
}
private OsuBindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue)
{
}
public override BindableBeatmap GetBoundCopy()
{
var copy = new OsuBindableBeatmap(Default);
copy.BindTo(this);
return copy;
}
}
} }
} }

View File

@ -73,13 +73,13 @@ namespace osu.Game.Overlays.Music
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps, OsuGameBase osuGame) private void load(BeatmapManager beatmaps, IBindableBeatmap beatmap)
{ {
beatmaps.GetAllUsableBeatmapSets().ForEach(addBeatmapSet); beatmaps.GetAllUsableBeatmapSets().ForEach(addBeatmapSet);
beatmaps.ItemAdded += addBeatmapSet; beatmaps.ItemAdded += addBeatmapSet;
beatmaps.ItemRemoved += removeBeatmapSet; beatmaps.ItemRemoved += removeBeatmapSet;
beatmapBacking.BindTo(osuGame.Beatmap); beatmapBacking.BindTo(beatmap);
beatmapBacking.ValueChanged += _ => updateSelectedSet(); beatmapBacking.ValueChanged += _ => updateSelectedSet();
} }

View File

@ -21,17 +21,22 @@ namespace osu.Game.Overlays.Music
private const float transition_duration = 600; private const float transition_duration = 600;
private const float playlist_height = 510; private const float playlist_height = 510;
/// <summary>
/// Invoked when the order of an item in the list has changed.
/// The second parameter indicates the new index of the item.
/// </summary>
public Action<BeatmapSetInfo, int> OrderChanged; public Action<BeatmapSetInfo, int> OrderChanged;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private BeatmapManager beatmaps; private BeatmapManager beatmaps;
private FilterControl filter; private FilterControl filter;
private PlaylistList list; private PlaylistList list;
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours) private void load(OsuColour colours, BindableBeatmap beatmap, BeatmapManager beatmaps)
{ {
this.beatmap.BindTo(beatmap);
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
Children = new Drawable[] Children = new Drawable[]
@ -73,15 +78,13 @@ namespace osu.Game.Overlays.Music
}, },
}; };
beatmapBacking.BindTo(game.Beatmap);
filter.Search.OnCommit = (sender, newText) => filter.Search.OnCommit = (sender, newText) =>
{ {
BeatmapInfo beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault(); BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
if (beatmap != null) if (toSelect != null)
{ {
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(beatmap); beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect);
beatmapBacking.Value.Track.Restart(); beatmap.Value.Track.Restart();
} }
}; };
} }
@ -105,14 +108,14 @@ namespace osu.Game.Overlays.Music
private void itemSelected(BeatmapSetInfo set) private void itemSelected(BeatmapSetInfo set)
{ {
if (set.ID == (beatmapBacking.Value?.BeatmapSetInfo?.ID ?? -1)) if (set.ID == (beatmap.Value?.BeatmapSetInfo?.ID ?? -1))
{ {
beatmapBacking.Value?.Track?.Seek(0); beatmap.Value?.Track?.Seek(0);
return; return;
} }
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First()); beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First());
beatmapBacking.Value.Track.Restart(); beatmap.Value.Track.Restart();
} }
} }

View File

@ -30,11 +30,8 @@ namespace osu.Game.Overlays
public class MusicController : OsuFocusedOverlayContainer public class MusicController : OsuFocusedOverlayContainer
{ {
private const float player_height = 130; private const float player_height = 130;
private const float transition_length = 800; private const float transition_length = 800;
private const float progress_height = 10; private const float progress_height = 10;
private const float bottom_black_area_height = 55; private const float bottom_black_area_height = 55;
private Drawable background; private Drawable background;
@ -49,16 +46,17 @@ namespace osu.Game.Overlays
private PlaylistOverlay playlist; private PlaylistOverlay playlist;
private BeatmapManager beatmaps;
private LocalisationEngine localisation; private LocalisationEngine localisation;
private BeatmapManager beatmaps;
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
private List<BeatmapSetInfo> beatmapSets; private List<BeatmapSetInfo> beatmapSets;
private BeatmapSetInfo currentSet; private BeatmapSetInfo currentSet;
private Container dragContainer; private Container dragContainer;
private Container playerContainer; private Container playerContainer;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
public MusicController() public MusicController()
{ {
Width = 400; Width = 400;
@ -97,8 +95,9 @@ namespace osu.Game.Overlays
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation) private void load(BindableBeatmap beatmap, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation)
{ {
this.beatmap.BindTo(beatmap);
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
this.localisation = localisation; this.localisation = localisation;
@ -224,8 +223,6 @@ namespace osu.Game.Overlays
beatmaps.ItemAdded += handleBeatmapAdded; beatmaps.ItemAdded += handleBeatmapAdded;
beatmaps.ItemRemoved += handleBeatmapRemoved; beatmaps.ItemRemoved += handleBeatmapRemoved;
beatmapBacking.BindTo(game.Beatmap);
playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint); playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
} }
@ -240,10 +237,8 @@ namespace osu.Game.Overlays
protected override void LoadComplete() protected override void LoadComplete()
{ {
beatmapBacking.ValueChanged += beatmapChanged; beatmap.BindValueChanged(beatmapChanged, true);
beatmapBacking.DisabledChanged += beatmapDisabledChanged; beatmap.BindDisabledChanged(beatmapDisabledChanged, true);
beatmapBacking.TriggerChange();
base.LoadComplete(); base.LoadComplete();
} }
@ -276,7 +271,7 @@ namespace osu.Game.Overlays
playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o;
if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled && beatmapSets.Any()) if (track.HasCompleted && !track.Looping && !beatmap.Disabled && beatmapSets.Any())
next(); next();
} }
else else
@ -289,7 +284,7 @@ namespace osu.Game.Overlays
if (track == null) if (track == null)
{ {
if (!beatmapBacking.Disabled) if (!beatmap.Disabled)
next(true); next(true);
return; return;
} }
@ -307,8 +302,8 @@ namespace osu.Game.Overlays
var playable = beatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? beatmapSets.LastOrDefault(); var playable = beatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? beatmapSets.LastOrDefault();
if (playable != null) if (playable != null)
{ {
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmapBacking); beatmap.Value = beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmap.Value);
beatmapBacking.Value.Track.Restart(); beatmap.Value.Track.Restart();
} }
} }
@ -320,8 +315,8 @@ namespace osu.Game.Overlays
var playable = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? beatmapSets.FirstOrDefault(); var playable = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? beatmapSets.FirstOrDefault();
if (playable != null) if (playable != null)
{ {
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmapBacking); beatmap.Value = beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmap.Value);
beatmapBacking.Value.Track.Restart(); beatmap.Value.Track.Restart();
} }
} }

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Edit
private RulesetContainer rulesetContainer; private RulesetContainer rulesetContainer;
private readonly List<Container> layerContainers = new List<Container>(); private readonly List<Container> layerContainers = new List<Container>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
protected HitObjectComposer(Ruleset ruleset) protected HitObjectComposer(Ruleset ruleset)
{ {
@ -38,9 +38,9 @@ namespace osu.Game.Rulesets.Edit
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame, IFrameBasedClock framedClock) private void load(IBindableBeatmap beatmap, IFrameBasedClock framedClock)
{ {
beatmap.BindTo(osuGame.Beatmap); this.beatmap.BindTo(beatmap);
try try
{ {

View File

@ -17,7 +17,7 @@ namespace osu.Game.Screens.Edit.Components
private const float corner_radius = 5; private const float corner_radius = 5;
private const float contents_padding = 15; private const float contents_padding = 15;
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
protected Track Track => Beatmap.Value.Track; protected Track Track => Beatmap.Value.Track;
private readonly Drawable background; private readonly Drawable background;
@ -42,8 +42,9 @@ namespace osu.Game.Screens.Edit.Components
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(IBindableBeatmap beatmap, OsuColour colours)
{ {
Beatmap.BindTo(beatmap);
background.Colour = colours.Gray1; background.Colour = colours.Gray1;
} }
} }

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 osu.Framework.Allocation;
using OpenTK; using OpenTK;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -15,7 +16,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
/// </summary> /// </summary>
public abstract class TimelinePart : CompositeDrawable public abstract class TimelinePart : CompositeDrawable
{ {
public Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private readonly Container timeline; private readonly Container timeline;
@ -30,6 +31,12 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
}; };
} }
[BackgroundDependencyLoader]
private void load(IBindableBeatmap beatmap)
{
Beatmap.BindTo(beatmap);
}
private void updateRelativeChildSize() private void updateRelativeChildSize()
{ {
// the track may not be loaded completely (only has a length once it is). // the track may not be loaded completely (only has a length once it is).

View File

@ -20,19 +20,17 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, IAdjustableClock adjustableClock) private void load(OsuColour colours, IAdjustableClock adjustableClock)
{ {
TimelinePart markerPart, controlPointPart, bookmarkPart, breakPart;
Children = new Drawable[] Children = new Drawable[]
{ {
markerPart = new MarkerPart(adjustableClock) { RelativeSizeAxes = Axes.Both }, new MarkerPart(adjustableClock) { RelativeSizeAxes = Axes.Both },
controlPointPart = new ControlPointPart new ControlPointPart
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.35f Height = 0.35f
}, },
bookmarkPart = new BookmarkPart new BookmarkPart
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
@ -67,7 +65,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
}, },
} }
}, },
breakPart = new BreakPart new BreakPart
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -75,11 +73,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
Height = 0.25f Height = 0.25f
} }
}; };
markerPart.Beatmap.BindTo(Beatmap);
controlPointPart.Beatmap.BindTo(Beatmap);
bookmarkPart.Beatmap.BindTo(Beatmap);
breakPart.Beatmap.BindTo(Beatmap);
} }
} }
} }

View File

@ -41,14 +41,14 @@ namespace osu.Game.Screens.Edit
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent); => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
// TODO: should probably be done at a RulesetContainer level to share logic with Player. // TODO: should probably be done at a RulesetContainer level to share logic with Player.
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock(); var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock();
clock = new EditorClock(Beatmap, beatDivisor) { IsCoupled = false }; clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
clock.ChangeSource(sourceClock); clock.ChangeSource(sourceClock);
dependencies.CacheAs<IFrameBasedClock>(clock); dependencies.CacheAs<IFrameBasedClock>(clock);
@ -128,9 +128,9 @@ namespace osu.Game.Screens.Edit
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = 10 }, Padding = new MarginPadding { Right = 10 },
Child = timeInfo = new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, Child = new TimeInfoContainer { RelativeSizeAxes = Axes.Both },
}, },
timeline = new SummaryTimeline new SummaryTimeline
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
@ -138,7 +138,7 @@ namespace osu.Game.Screens.Edit
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 10 }, Padding = new MarginPadding { Left = 10 },
Child = playback = new PlaybackControl { RelativeSizeAxes = Axes.Both }, Child = new PlaybackControl { RelativeSizeAxes = Axes.Both },
} }
}, },
} }
@ -148,9 +148,6 @@ namespace osu.Game.Screens.Edit
}, },
}; };
timeInfo.Beatmap.BindTo(Beatmap);
timeline.Beatmap.BindTo(Beatmap);
playback.Beatmap.BindTo(Beatmap);
menuBar.Mode.ValueChanged += onModeChanged; menuBar.Mode.ValueChanged += onModeChanged;
bottomBackground.Colour = colours.Gray2; bottomBackground.Colour = colours.Gray2;
@ -178,7 +175,6 @@ namespace osu.Game.Screens.Edit
break; break;
} }
currentScreen.Beatmap.BindTo(Beatmap);
LoadComponentAsync(currentScreen, screenContainer.Add); LoadComponentAsync(currentScreen, screenContainer.Add);
} }

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -24,12 +23,12 @@ namespace osu.Game.Screens.Edit
private readonly BindableBeatDivisor beatDivisor; private readonly BindableBeatDivisor beatDivisor;
public EditorClock(Bindable<WorkingBeatmap> beatmap, BindableBeatDivisor beatDivisor) public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
{ {
this.beatDivisor = beatDivisor; this.beatDivisor = beatDivisor;
ControlPointInfo = beatmap.Value.Beatmap.ControlPointInfo; ControlPointInfo = beatmap.Beatmap.ControlPointInfo;
TrackLength = beatmap.Value.Track.Length; TrackLength = beatmap.Track.Length;
} }
public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor) public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor)

View File

@ -28,7 +28,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose
if (beatDivisor != null) if (beatDivisor != null)
this.beatDivisor.BindTo(beatDivisor); this.beatDivisor.BindTo(beatDivisor);
ScrollableTimeline timeline;
Children = new Drawable[] Children = new Drawable[]
{ {
new GridContainer new GridContainer
@ -65,7 +64,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = 5 }, Padding = new MarginPadding { Right = 5 },
Child = timeline = new ScrollableTimeline { RelativeSizeAxes = Axes.Both } Child = new ScrollableTimeline { RelativeSizeAxes = Axes.Both }
}, },
new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both }
}, },
@ -94,8 +93,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose
}, },
}; };
timeline.Beatmap.BindTo(Beatmap);
var ruleset = Beatmap.Value.BeatmapInfo.Ruleset?.CreateInstance(); var ruleset = Beatmap.Value.BeatmapInfo.Ruleset?.CreateInstance();
if (ruleset == null) if (ruleset == null)
{ {

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 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.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -11,14 +10,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
{ {
public class BeatmapWaveformGraph : CompositeDrawable public class BeatmapWaveformGraph : CompositeDrawable
{ {
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); public WorkingBeatmap Beatmap { set => graph.Waveform = value.Waveform; }
private readonly WaveformGraph graph; private readonly WaveformGraph graph;
public BeatmapWaveformGraph() public BeatmapWaveformGraph()
{ {
InternalChild = graph = new WaveformGraph { RelativeSizeAxes = Axes.Both }; InternalChild = graph = new WaveformGraph { RelativeSizeAxes = Axes.Both };
Beatmap.ValueChanged += b => graph.Waveform = b.Waveform;
} }
/// <summary> /// <summary>

View File

@ -2,11 +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 OpenTK; using OpenTK;
using osu.Framework.Configuration;
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.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
@ -14,8 +12,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
{ {
public class ScrollableTimeline : CompositeDrawable public class ScrollableTimeline : CompositeDrawable
{ {
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private readonly ScrollingTimelineContainer timelineContainer; private readonly ScrollingTimelineContainer timelineContainer;
public ScrollableTimeline() public ScrollableTimeline()
@ -117,7 +113,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
hitSoundsCheckbox.Current.Value = true; hitSoundsCheckbox.Current.Value = true;
waveformCheckbox.Current.Value = true; waveformCheckbox.Current.Value = true;
timelineContainer.Beatmap.BindTo(Beatmap);
timelineContainer.WaveformVisible.BindTo(waveformCheckbox.Current); timelineContainer.WaveformVisible.BindTo(waveformCheckbox.Current);
} }

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 osu.Framework.Allocation;
using OpenTK; using OpenTK;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -17,7 +18,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
public readonly Bindable<bool> HitObjectsVisible = new Bindable<bool>(); public readonly Bindable<bool> HitObjectsVisible = new Bindable<bool>();
public readonly Bindable<bool> HitSoundsVisible = new Bindable<bool>(); public readonly Bindable<bool> HitSoundsVisible = new Bindable<bool>();
public readonly Bindable<bool> WaveformVisible = new Bindable<bool>(); public readonly Bindable<bool> WaveformVisible = new Bindable<bool>();
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private readonly BeatmapWaveformGraph waveform; private readonly BeatmapWaveformGraph waveform;
@ -36,12 +38,20 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
Content.AutoSizeAxes = Axes.None; Content.AutoSizeAxes = Axes.None;
Content.RelativeSizeAxes = Axes.Both; Content.RelativeSizeAxes = Axes.Both;
waveform.Beatmap.BindTo(Beatmap);
WaveformVisible.ValueChanged += waveformVisibilityChanged; WaveformVisible.ValueChanged += waveformVisibilityChanged;
Zoom = 10; Zoom = 10;
} }
[BackgroundDependencyLoader]
private void load(IBindableBeatmap beatmap)
{
this.beatmap.BindTo(beatmap);
this.beatmap.BindValueChanged(beatmapChanged, true);
}
private void beatmapChanged(WorkingBeatmap beatmap) => waveform.Beatmap = beatmap;
private float minZoom = 1; private float minZoom = 1;
/// <summary> /// <summary>
/// The minimum zoom level allowed. /// The minimum zoom level allowed.

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 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.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -13,7 +14,7 @@ namespace osu.Game.Screens.Edit.Screens
/// </summary> /// </summary>
public class EditorScreen : Container public class EditorScreen : Container
{ {
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container content; private readonly Container content;
@ -27,6 +28,12 @@ namespace osu.Game.Screens.Edit.Screens
InternalChild = content = new Container { RelativeSizeAxes = Axes.Both }; InternalChild = content = new Container { RelativeSizeAxes = Axes.Both };
} }
[BackgroundDependencyLoader]
private void load(IBindableBeatmap beatmap)
{
Beatmap.BindTo(beatmap);
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();

View File

@ -326,7 +326,10 @@ namespace osu.Game.Screens.Menu
logoTracking = false; logoTracking = false;
if (game != null) if (game != null)
game.OverlayActivationMode.Value = state == MenuState.Exit ? OverlayActivation.Disabled : OverlayActivation.UserTriggered; {
game.OverlayActivationMode.Value = state == MenuState.Exit ? OverlayActivation.Disabled : OverlayActivation.All;
game.Toolbar.Hide();
}
logo.ClearTransforms(targetMember: nameof(Position)); logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.Both; logo.RelativePositionAxes = Axes.Both;

View File

@ -28,6 +28,8 @@ namespace osu.Game.Screens.Menu
/// </summary> /// </summary>
public bool DidLoadMenu; public bool DidLoadMenu;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private MainMenu mainMenu; private MainMenu mainMenu;
private SampleChannel welcome; private SampleChannel welcome;
private SampleChannel seeya; private SampleChannel seeya;
@ -42,11 +44,13 @@ namespace osu.Game.Screens.Menu
private Bindable<bool> menuVoice; private Bindable<bool> menuVoice;
private Bindable<bool> menuMusic; private Bindable<bool> menuMusic;
private Track track; private Track track;
private WorkingBeatmap beatmap; private WorkingBeatmap introBeatmap;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game, BindableBeatmap beatmap)
{ {
this.beatmap.BindTo(beatmap);
menuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice); menuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic); menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
@ -73,8 +77,8 @@ namespace osu.Game.Screens.Menu
} }
} }
beatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
track = beatmap.Track; track = introBeatmap.Track;
welcome = audio.Sample.Get(@"welcome"); welcome = audio.Sample.Get(@"welcome");
seeya = audio.Sample.Get(@"seeya"); seeya = audio.Sample.Get(@"seeya");
@ -91,7 +95,7 @@ namespace osu.Game.Screens.Menu
if (!resuming) if (!resuming)
{ {
Game.Beatmap.Value = beatmap; beatmap.Value = introBeatmap;
if (menuVoice) if (menuVoice)
welcome.Play(); welcome.Play();

View File

@ -21,7 +21,7 @@ namespace osu.Game.Screens.Menu
{ {
public class LogoVisualisation : Drawable, IHasAccentColour public class LogoVisualisation : Drawable, IHasAccentColour
{ {
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
/// <summary> /// <summary>
/// The number of bars to jump each update iteration. /// The number of bars to jump each update iteration.
@ -78,9 +78,9 @@ namespace osu.Game.Screens.Menu
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(ShaderManager shaders, OsuGameBase game) private void load(ShaderManager shaders, IBindableBeatmap beatmap)
{ {
beatmap.BindTo(game.Beatmap); this.beatmap.BindTo(beatmap);
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
} }

View File

@ -22,7 +22,7 @@ namespace osu.Game.Screens.Menu
public override bool HandleKeyboardInput => false; public override bool HandleKeyboardInput => false;
public override bool HandleMouseInput => false; public override bool HandleMouseInput => false;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private Box leftBox; private Box leftBox;
private Box rightBox; private Box rightBox;
@ -45,9 +45,9 @@ namespace osu.Game.Screens.Menu
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, OsuColour colours) private void load(IBindableBeatmap beatmap, OsuColour colours)
{ {
beatmap.BindTo(game.Beatmap); this.beatmap.BindTo(beatmap);
// linear colour looks better in this case, so let's use it for now. // linear colour looks better in this case, so let's use it for now.
Color4 gradientDark = colours.Blue.Opacity(0).ToLinear(); Color4 gradientDark = colours.Blue.Opacity(0).ToLinear();

View File

@ -77,30 +77,15 @@ namespace osu.Game.Screens
private ParallaxContainer backgroundParallaxContainer; private ParallaxContainer backgroundParallaxContainer;
public WorkingBeatmap InitialBeatmap
{
set
{
if (IsLoaded) throw new InvalidOperationException($"Cannot set {nameof(InitialBeatmap)} post-load.");
Beatmap.Value = value;
}
}
protected readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>(); protected readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private SampleChannel sampleExit; private SampleChannel sampleExit;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(true)]
private void load(OsuGameBase game, OsuGame osuGame, AudioManager audio) private void load(BindableBeatmap beatmap, OsuGame osuGame, AudioManager audio)
{ {
if (game != null) if (beatmap != null)
{ Beatmap.BindTo(beatmap);
//if we were given a beatmap at ctor time, we want to pass this on to the game-wide beatmap.
var localMap = Beatmap.Value;
Beatmap.BindTo(game.Beatmap);
if (localMap != null)
Beatmap.Value = localMap;
}
if (osuGame != null) if (osuGame != null)
{ {

View File

@ -44,13 +44,18 @@ namespace osu.Game.Screens.Play
public Action OnResume; public Action OnResume;
public Action OnPause; public Action OnPause;
private readonly IAdjustableClock adjustableClock;
private readonly FramedClock framedClock; private readonly FramedClock framedClock;
private readonly DecoupleableInterpolatingFramedClock decoupledClock;
public PauseContainer(FramedClock framedClock, IAdjustableClock adjustableClock) /// <summary>
/// Creates a new <see cref="PauseContainer"/>.
/// </summary>
/// <param name="framedClock">The gameplay clock. This is the clock that will process frames.</param>
/// <param name="decoupledClock">The seekable clock. This is the clock that will be paused and resumed.</param>
public PauseContainer(FramedClock framedClock, DecoupleableInterpolatingFramedClock decoupledClock)
{ {
this.framedClock = framedClock; this.framedClock = framedClock;
this.adjustableClock = adjustableClock; this.decoupledClock = decoupledClock;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -80,7 +85,7 @@ namespace osu.Game.Screens.Play
if (IsPaused) return; if (IsPaused) return;
// stop the seekable clock (stops the audio eventually) // stop the seekable clock (stops the audio eventually)
adjustableClock.Stop(); decoupledClock.Stop();
IsPaused = true; IsPaused = true;
OnPause?.Invoke(); OnPause?.Invoke();
@ -97,10 +102,10 @@ namespace osu.Game.Screens.Play
IsResuming = false; IsResuming = false;
lastPauseActionTime = Time.Current; lastPauseActionTime = Time.Current;
// seek back to the time of the framed clock. // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time
// this accounts for the audio clock potentially taking time to enter a completely stopped state. // This accounts for the audio clock source potentially taking time to enter a completely stopped state
adjustableClock.Seek(framedClock.CurrentTime); decoupledClock.Seek(decoupledClock.CurrentTime);
adjustableClock.Start(); decoupledClock.Start();
OnResume?.Invoke(); OnResume?.Invoke();
pauseOverlay.Hide(); pauseOverlay.Hide();

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
@ -120,7 +121,7 @@ namespace osu.Game.Screens.Play
// let's try again forcing the beatmap's ruleset. // let's try again forcing the beatmap's ruleset.
ruleset = beatmap.BeatmapInfo.Ruleset; ruleset = beatmap.BeatmapInfo.Ruleset;
rulesetInstance = ruleset.CreateInstance(); rulesetInstance = ruleset.CreateInstance();
RulesetContainer = rulesetInstance.CreateRulesetContainerWith(Beatmap); RulesetContainer = rulesetInstance.CreateRulesetContainerWith(Beatmap.Value);
} }
if (!RulesetContainer.Objects.Any()) if (!RulesetContainer.Objects.Any())
@ -146,8 +147,12 @@ namespace osu.Game.Screens.Play
adjustableClock.ProcessFrame(); adjustableClock.ProcessFrame();
// Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited.
// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck.
var platformOffsetClock = new FramedOffsetClock(adjustableClock) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 22 : 0 };
// the final usable gameplay clock with user-set offsets applied. // the final usable gameplay clock with user-set offsets applied.
var offsetClock = new FramedOffsetClock(adjustableClock); var offsetClock = new FramedOffsetClock(platformOffsetClock);
userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
userAudioOffset.TriggerChange(); userAudioOffset.TriggerChange();

View File

@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Add(info = new BeatmapMetadataDisplay(Beatmap) Add(info = new BeatmapMetadataDisplay(Beatmap.Value)
{ {
Alpha = 0, Alpha = 0,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,

View File

@ -13,7 +13,7 @@ namespace osu.Game.Screens.Play
{ {
public abstract class ScreenWithBeatmapBackground : OsuScreen public abstract class ScreenWithBeatmapBackground : OsuScreen
{ {
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
public override bool AllowBeatmapRulesetChange => false; public override bool AllowBeatmapRulesetChange => false;

View File

@ -38,7 +38,7 @@ namespace osu.Game.Screens.Ranking
private static readonly Vector2 background_blur = new Vector2(20); private static readonly Vector2 background_blur = new Vector2(20);
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
private const float overscan = 1.3f; private const float overscan = 1.3f;
@ -274,10 +274,10 @@ namespace osu.Game.Screens.Ranking
switch (mode) switch (mode)
{ {
case ResultMode.Summary: case ResultMode.Summary:
currentPage = new ResultsPageScore(score, Beatmap); currentPage = new ResultsPageScore(score, Beatmap.Value);
break; break;
case ResultMode.Ranking: case ResultMode.Ranking:
currentPage = new ResultsPageRanking(score, Beatmap); currentPage = new ResultsPageRanking(score, Beatmap.Value);
break; break;
} }

View File

@ -63,7 +63,8 @@ namespace osu.Game.Screens.Select
private SampleChannel sampleChangeBeatmap; private SampleChannel sampleChangeBeatmap;
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent); protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
protected SongSelect() protected SongSelect()
{ {
@ -175,7 +176,7 @@ namespace osu.Game.Screens.Select
} }
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(true)]
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours) private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours)
{ {
dependencies.CacheAs(this); dependencies.CacheAs(this);
@ -206,15 +207,13 @@ namespace osu.Game.Screens.Select
Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable(); Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable();
Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.BindDisabledChanged(disabled => Carousel.AllowSelection = !disabled, true);
Beatmap.TriggerChange(); Beatmap.BindValueChanged(workingBeatmapChanged);
Beatmap.ValueChanged += workingBeatmapChanged;
} }
public void Edit(BeatmapInfo beatmap) public void Edit(BeatmapInfo beatmap)
{ {
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
Push(new Editor()); Push(new Editor());
} }
@ -280,7 +279,7 @@ namespace osu.Game.Screens.Select
{ {
bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID; bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID;
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
ensurePlayingSelected(preview); ensurePlayingSelected(preview);
} }
@ -367,7 +366,7 @@ namespace osu.Game.Screens.Select
{ {
if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending)
{ {
UpdateBeatmap(Beatmap); UpdateBeatmap(Beatmap.Value);
ensurePlayingSelected(); ensurePlayingSelected();
} }

View File

@ -7,6 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables namespace osu.Game.Storyboards.Drawables
{ {
@ -63,14 +64,14 @@ namespace osu.Game.Storyboards.Drawables
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, TextureStore textureStore) private void load(IBindableBeatmap beatmap, TextureStore textureStore)
{ {
var basePath = Animation.Path.ToLowerInvariant(); var basePath = Animation.Path.ToLowerInvariant();
for (var frame = 0; frame < Animation.FrameCount; frame++) for (var frame = 0; frame < Animation.FrameCount; frame++)
{ {
var framePath = basePath.Replace(".", frame + "."); var framePath = basePath.Replace(".", frame + ".");
var path = game.Beatmap.Value.BeatmapSetInfo.Files.FirstOrDefault(f => f.Filename.ToLowerInvariant() == framePath)?.FileInfo.StoragePath; var path = beatmap.Value.BeatmapSetInfo.Files.FirstOrDefault(f => f.Filename.ToLowerInvariant() == framePath)?.FileInfo.StoragePath;
if (path == null) if (path == null)
continue; continue;

View File

@ -7,6 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables namespace osu.Game.Storyboards.Drawables
{ {
@ -62,10 +63,10 @@ namespace osu.Game.Storyboards.Drawables
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, TextureStore textureStore) private void load(IBindableBeatmap beatmap, TextureStore textureStore)
{ {
var spritePath = Sprite.Path.ToLowerInvariant(); var spritePath = Sprite.Path.ToLowerInvariant();
var path = game.Beatmap.Value.BeatmapSetInfo.Files.FirstOrDefault(f => f.Filename.ToLowerInvariant() == spritePath)?.FileInfo.StoragePath; var path = beatmap.Value.BeatmapSetInfo.Files.FirstOrDefault(f => f.Filename.ToLowerInvariant() == spritePath)?.FileInfo.StoragePath;
if (path == null) if (path == null)
return; return;

View File

@ -20,29 +20,19 @@ namespace osu.Game.Tests.Visual
protected readonly BindableBeatDivisor BeatDivisor = new BindableBeatDivisor(); protected readonly BindableBeatDivisor BeatDivisor = new BindableBeatDivisor();
protected readonly EditorClock Clock; protected readonly EditorClock Clock;
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent);
private OsuGameBase osuGame;
protected EditorClockTestCase() protected EditorClockTestCase()
{ {
Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false }; Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false };
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
this.osuGame = osuGame; Dependencies.Cache(BeatDivisor);
Dependencies.CacheAs<IFrameBasedClock>(Clock);
Dependencies.CacheAs<IAdjustableClock>(Clock);
dependencies.Cache(BeatDivisor); Beatmap.BindValueChanged(beatmapChanged, true);
dependencies.CacheAs<IFrameBasedClock>(Clock);
dependencies.CacheAs<IAdjustableClock>(Clock);
osuGame.Beatmap.ValueChanged += beatmapChanged;
beatmapChanged(osuGame.Beatmap.Value);
} }
private void beatmapChanged(WorkingBeatmap working) private void beatmapChanged(WorkingBeatmap working)
@ -68,12 +58,5 @@ namespace osu.Game.Tests.Visual
return true; return true;
} }
protected override void Dispose(bool isDisposing)
{
osuGame.Beatmap.ValueChanged -= beatmapChanged;
base.Dispose(isDisposing);
}
} }
} }

View File

@ -23,9 +23,9 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(ruleset.RulesetInfo); Beatmap.Value = new TestWorkingBeatmap(ruleset.RulesetInfo);
LoadComponentAsync(new Editor(), LoadScreen); LoadComponentAsync(new Editor(), LoadScreen);
} }

View File

@ -1,12 +1,47 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 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.Allocation;
using osu.Framework.Audio;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
public abstract class OsuTestCase : TestCase public abstract class OsuTestCase : TestCase
{ {
private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap());
protected BindableBeatmap Beatmap => beatmap;
protected DependencyContainer Dependencies { get; private set; }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
Dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
Dependencies.CacheAs<BindableBeatmap>(beatmap);
Dependencies.CacheAs<IBindableBeatmap>(beatmap);
return Dependencies;
}
[BackgroundDependencyLoader]
private void load(AudioManager audioManager)
{
beatmap.SetAudioManager(audioManager);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmap != null)
{
beatmap.Disabled = true;
beatmap.Value.Track.Stop();
}
}
protected override ITestCaseTestRunner CreateRunner() => new OsuTestCaseTestRunner(); protected override ITestCaseTestRunner CreateRunner() => new OsuTestCaseTestRunner();
public class OsuTestCaseTestRunner : OsuGameBase, ITestCaseTestRunner public class OsuTestCaseTestRunner : OsuGameBase, ITestCaseTestRunner
@ -23,5 +58,22 @@ namespace osu.Game.Tests.Visual
public void RunTestBlocking(TestCase test) => runner.RunTestBlocking(test); public void RunTestBlocking(TestCase test) => runner.RunTestBlocking(test);
} }
private class OsuTestBeatmap : BindableBeatmap
{
public OsuTestBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue)
{
}
public void SetAudioManager(AudioManager audioManager) => RegisterAudioManager(audioManager);
public override BindableBeatmap GetBoundCopy()
{
var copy = new OsuTestBeatmap(Default);
copy.BindTo(this);
return copy;
}
}
} }
} }

View File

@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual
new ScrollContainer new ScrollContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = new BeatmapList(ruleset) Child = new BeatmapList(ruleset, Beatmap)
} }
} }
}, },
@ -108,10 +108,12 @@ namespace osu.Game.Tests.Visual
{ {
private readonly Container<BeatmapDisplay> beatmapDisplays; private readonly Container<BeatmapDisplay> beatmapDisplays;
private readonly Ruleset ruleset; private readonly Ruleset ruleset;
private readonly BindableBeatmap beatmapBindable;
public BeatmapList(Ruleset ruleset) public BeatmapList(Ruleset ruleset, BindableBeatmap beatmapBindable)
{ {
this.ruleset = ruleset; this.ruleset = ruleset;
this.beatmapBindable = beatmapBindable;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
@ -130,7 +132,7 @@ namespace osu.Game.Tests.Visual
var sets = beatmaps.GetAllUsableBeatmapSets(); var sets = beatmaps.GetAllUsableBeatmapSets();
var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID); var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID);
allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b, beatmapBindable)));
} }
private class BeatmapDisplay : CompositeDrawable, IHasTooltip private class BeatmapDisplay : CompositeDrawable, IHasTooltip
@ -138,27 +140,47 @@ namespace osu.Game.Tests.Visual
private readonly OsuSpriteText text; private readonly OsuSpriteText text;
private readonly BeatmapInfo beatmap; private readonly BeatmapInfo beatmap;
private readonly BindableBeatmap beatmapBindable;
private BeatmapManager beatmaps; private BeatmapManager beatmaps;
private OsuGameBase osuGame;
private bool isSelected; private bool isSelected;
public string TooltipText => text.Text; public string TooltipText => text.Text;
public BeatmapDisplay(BeatmapInfo beatmap) public BeatmapDisplay(BeatmapInfo beatmap, BindableBeatmap beatmapBindable)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
this.beatmapBindable = beatmapBindable;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
InternalChild = text = new OsuSpriteText(); InternalChild = text = new OsuSpriteText();
this.beatmapBindable.ValueChanged += beatmapChanged;
}
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps)
{
this.beatmaps = beatmaps;
var working = beatmaps.GetWorkingBeatmap(beatmap);
text.Text = $"{working.Metadata.Artist} - {working.Metadata.Title} ({working.Metadata.AuthorString}) [{working.BeatmapInfo.Version}]";
}
private void beatmapChanged(WorkingBeatmap newBeatmap)
{
if (isSelected)
this.FadeColour(Color4.White, 100);
isSelected = false;
} }
protected override bool OnClick(InputState state) protected override bool OnClick(InputState state)
{ {
if (osuGame.Beatmap.Value.BeatmapInfo.ID == beatmap.ID) if (beatmapBindable.Value.BeatmapInfo.ID == beatmap.ID)
return false; return false;
osuGame.Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); beatmapBindable.Value = beatmaps.GetWorkingBeatmap(beatmap);
isSelected = true; isSelected = true;
return true; return true;
} }
@ -177,25 +199,6 @@ namespace osu.Game.Tests.Visual
return; return;
this.FadeColour(Color4.White, 100); this.FadeColour(Color4.White, 100);
} }
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGame, BeatmapManager beatmaps)
{
this.osuGame = osuGame;
this.beatmaps = beatmaps;
var working = beatmaps.GetWorkingBeatmap(beatmap);
text.Text = $"{working.Metadata.Artist} - {working.Metadata.Title} ({working.Metadata.AuthorString}) [{working.BeatmapInfo.Version}]";
osuGame.Beatmap.ValueChanged += beatmapChanged;
}
private void beatmapChanged(WorkingBeatmap newBeatmap)
{
if (isSelected)
this.FadeColour(Color4.White, 100);
isSelected = false;
}
} }
} }
@ -204,7 +207,7 @@ namespace osu.Game.Tests.Visual
private readonly FillFlowContainer<PerformanceDisplay> scores; private readonly FillFlowContainer<PerformanceDisplay> scores;
private APIAccess api; private APIAccess api;
private readonly Bindable<WorkingBeatmap> currentBeatmap = new Bindable<WorkingBeatmap>(); private readonly IBindable<WorkingBeatmap> currentBeatmap = new Bindable<WorkingBeatmap>();
public PerformanceList() public PerformanceList()
{ {
@ -220,7 +223,7 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame, APIAccess api) private void load(IBindableBeatmap beatmap, APIAccess api)
{ {
this.api = api; this.api = api;
@ -235,7 +238,7 @@ namespace osu.Game.Tests.Visual
} }
currentBeatmap.ValueChanged += beatmapChanged; currentBeatmap.ValueChanged += beatmapChanged;
currentBeatmap.BindTo(osuGame.Beatmap); currentBeatmap.BindTo(beatmap);
} }
private GetScoresRequest lastRequest; private GetScoresRequest lastRequest;
@ -333,9 +336,9 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load(IBindableBeatmap beatmap)
{ {
osuGame.Beatmap.ValueChanged += beatmapChanged; beatmap.ValueChanged += beatmapChanged;
} }
private Cached informationCache = new Cached(); private Cached informationCache = new Cached();

View File

@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual
protected Player Player; protected Player Player;
private TestWorkingBeatmap working;
protected TestCasePlayer(Ruleset ruleset) protected TestCasePlayer(Ruleset ruleset)
{ {
this.ruleset = ruleset; this.ruleset = ruleset;
@ -67,13 +65,13 @@ namespace osu.Game.Tests.Visual
{ {
var beatmap = CreateBeatmap(r); var beatmap = CreateBeatmap(r);
working = new TestWorkingBeatmap(beatmap); Beatmap.Value = new TestWorkingBeatmap(beatmap);
working.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; Beatmap.Value.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) };
if (Player != null) if (Player != null)
Remove(Player); Remove(Player);
var player = CreatePlayer(working, r); var player = CreatePlayer(r);
LoadComponentAsync(player, LoadScreen); LoadComponentAsync(player, LoadScreen);
@ -84,14 +82,12 @@ namespace osu.Game.Tests.Visual
{ {
base.Update(); base.Update();
if (working != null) // note that this will override any mod rate application
// note that this will override any mod rate application Beatmap.Value.Track.Rate = Clock.Rate;
working.Track.Rate = Clock.Rate;
} }
protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) => new Player protected virtual Player CreatePlayer(Ruleset ruleset) => new Player
{ {
InitialBeatmap = beatmap,
AllowPause = false, AllowPause = false,
AllowLeadIn = false, AllowLeadIn = false,
AllowResults = false, AllowResults = false,

View File

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2018.606.0" /> <PackageReference Include="ppy.osu.Framework" Version="2018.607.0" />
<PackageReference Include="SharpCompress" Version="0.18.1" /> <PackageReference Include="SharpCompress" Version="0.18.1" />
<PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" />