Merge branch 'master' into keyboard_shortcuts

This commit is contained in:
Dean Herbert 2021-06-03 14:47:40 +09:00 committed by GitHub
commit 4a5d8215f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
189 changed files with 2690 additions and 1318 deletions

View File

@ -10,14 +10,6 @@ trim_trailing_whitespace = true
#Roslyn naming styles #Roslyn naming styles
#PascalCase for public and protected members
dotnet_naming_style.pascalcase.capitalization = pascal_case
dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event
dotnet_naming_rule.public_members_pascalcase.severity = error
dotnet_naming_rule.public_members_pascalcase.symbols = public_members
dotnet_naming_rule.public_members_pascalcase.style = pascalcase
#camelCase for private members #camelCase for private members
dotnet_naming_style.camelcase.capitalization = camel_case dotnet_naming_style.camelcase.capitalization = camel_case

View File

@ -1,7 +0,0 @@
---
name: Feature Request
about: Propose a feature you would like to see in the game!
---
**Describe the new feature:**
**Proposal designs of the feature:**

View File

@ -1,5 +1,12 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Suggestions or feature request
url: https://github.com/ppy/osu/discussions/categories/ideas
about: Got something you think should change or be added? Search for or start a new discussion!
- name: Help
url: https://github.com/ppy/osu/discussions/categories/q-a
about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section!
- name: osu!stable issues - name: osu!stable issues
url: https://github.com/ppy/osu-stable-issues url: https://github.com/ppy/osu-stable-issues
about: For issues regarding osu!stable (not osu!lazer), open them here. about: For osu!stable bugs (not osu!lazer), check out the dedicated repository. Note that we only accept serious bug reports.

View File

@ -97,7 +97,7 @@ Before committing your code, please run a code formatter. This can be achieved b
We have adopted some cross-platform, compiler integrated analyzers. They can provide warnings when you are editing, building inside IDE or from command line, as-if they are provided by the compiler itself. We have adopted some cross-platform, compiler integrated analyzers. They can provide warnings when you are editing, building inside IDE or from command line, as-if they are provided by the compiler itself.
JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it from PowerShell with `.\InspectCode.ps1`, which is [only supported on Windows](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice. JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it from PowerShell with `.\InspectCode.ps1`. Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice.
## Contributing ## Contributing

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -51,7 +51,7 @@
<Reference Include="Java.Interop" /> <Reference Include="Java.Interop" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.524.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2021.601.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -57,7 +57,7 @@ namespace osu.Desktop
private string getStableInstallPath() private string getStableInstallPath()
{ {
static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")); static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")) || File.Exists(Path.Combine(p, "osu!.cfg"));
string stableInstallPath; string stableInstallPath;

View File

@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" /> <PackageReference Include="BenchmarkDotNet" Version="0.13.0" />
<PackageReference Include="nunit" Version="3.13.2" /> <PackageReference Include="nunit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
</ItemGroup> </ItemGroup>

View File

@ -1,8 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
@ -10,5 +18,22 @@ namespace osu.Game.Rulesets.Catch.Tests
public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene
{ {
protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); protected override Ruleset CreatePlayerRuleset() => new CatchRuleset();
[Test]
public void TestLegacyHUDComboCounterHidden([Values] bool withModifiedSkin)
{
if (withModifiedSkin)
{
AddStep("change component scale", () => Player.ChildrenOfType<LegacyScoreCounter>().First().Scale = new Vector2(2f));
AddStep("update target", () => Player.ChildrenOfType<SkinnableTargetContainer>().ForEach(LegacySkin.UpdateDrawableTarget));
AddStep("exit player", () => Player.Exit());
CreateTest(null);
}
AddAssert("legacy HUD combo counter hidden", () =>
{
return Player.ChildrenOfType<LegacyComboCounter>().All(c => c.ChildrenOfType<Container>().Single().Alpha == 0f);
});
}
} }
} }

View File

@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Catch.Tests
CircleSize = circleSize CircleSize = circleSize
}; };
SetContents(() => SetContents(_ =>
{ {
var droppedObjectContainer = new Container<CaughtObject> var droppedObjectContainer = new Container<CaughtObject>
{ {

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
scoreProcessor = new ScoreProcessor(); scoreProcessor = new ScoreProcessor();
SetContents(() => new CatchComboDisplay SetContents(_ => new CatchComboDisplay
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -19,22 +19,22 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
base.LoadComplete(); base.LoadComplete();
AddStep("show pear", () => SetContents(() => createDrawableFruit(0))); AddStep("show pear", () => SetContents(_ => createDrawableFruit(0)));
AddStep("show grape", () => SetContents(() => createDrawableFruit(1))); AddStep("show grape", () => SetContents(_ => createDrawableFruit(1)));
AddStep("show pineapple / apple", () => SetContents(() => createDrawableFruit(2))); AddStep("show pineapple / apple", () => SetContents(_ => createDrawableFruit(2)));
AddStep("show raspberry / orange", () => SetContents(() => createDrawableFruit(3))); AddStep("show raspberry / orange", () => SetContents(_ => createDrawableFruit(3)));
AddStep("show banana", () => SetContents(createDrawableBanana)); AddStep("show banana", () => SetContents(_ => createDrawableBanana()));
AddStep("show droplet", () => SetContents(() => createDrawableDroplet())); AddStep("show droplet", () => SetContents(_ => createDrawableDroplet()));
AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet)); AddStep("show tiny droplet", () => SetContents(_ => createDrawableTinyDroplet()));
AddStep("show hyperdash pear", () => SetContents(() => createDrawableFruit(0, true))); AddStep("show hyperdash pear", () => SetContents(_ => createDrawableFruit(0, true)));
AddStep("show hyperdash grape", () => SetContents(() => createDrawableFruit(1, true))); AddStep("show hyperdash grape", () => SetContents(_ => createDrawableFruit(1, true)));
AddStep("show hyperdash pineapple / apple", () => SetContents(() => createDrawableFruit(2, true))); AddStep("show hyperdash pineapple / apple", () => SetContents(_ => createDrawableFruit(2, true)));
AddStep("show hyperdash raspberry / orange", () => SetContents(() => createDrawableFruit(3, true))); AddStep("show hyperdash raspberry / orange", () => SetContents(_ => createDrawableFruit(3, true)));
AddStep("show hyperdash droplet", () => SetContents(() => createDrawableDroplet(true))); AddStep("show hyperdash droplet", () => SetContents(_ => createDrawableDroplet(true)));
} }
private Drawable createDrawableFruit(int indexInBeatmap, bool hyperdash = false) => private Drawable createDrawableFruit(int indexInBeatmap, bool hyperdash = false) =>

View File

@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Catch.Tests
protected override void LoadComplete() protected override void LoadComplete()
{ {
AddStep("fruit changes visual and hyper", () => SetContents(() => new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit AddStep("fruit changes visual and hyper", () => SetContents(_ => new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit
{ {
IndexInBeatmapBindable = { BindTarget = indexInBeatmap }, IndexInBeatmapBindable = { BindTarget = indexInBeatmap },
HyperDashBindable = { BindTarget = hyperDash }, HyperDashBindable = { BindTarget = hyperDash },
})))); }))));
AddStep("droplet changes hyper", () => SetContents(() => new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet AddStep("droplet changes hyper", () => SetContents(_ => new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet
{ {
HyperDashBindable = { BindTarget = hyperDash }, HyperDashBindable = { BindTarget = hyperDash },
})))); }))));

View File

@ -32,28 +32,28 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase(true, false)] [TestCase(true, false)]
[TestCase(false, true)] [TestCase(false, true)]
[TestCase(false, false)] [TestCase(false, false)]
public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) public void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true));
base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin); ConfigureTest(useBeatmapSkin, true, userHasCustomColours);
AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
} }
[TestCase(true)] [TestCase(true)]
[TestCase(false)] [TestCase(false)]
public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin) public void TestBeatmapComboColoursOverride(bool useBeatmapSkin)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true));
base.TestBeatmapComboColoursOverride(useBeatmapSkin); ConfigureTest(useBeatmapSkin, false, true);
AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
} }
[TestCase(true)] [TestCase(true)]
[TestCase(false)] [TestCase(false)]
public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) public void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true));
base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin); ConfigureTest(useBeatmapSkin, false, false);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
} }
@ -61,10 +61,10 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase(false, true)] [TestCase(false, true)]
[TestCase(true, false)] [TestCase(true, false)]
[TestCase(false, false)] [TestCase(false, false)]
public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) public void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, false));
base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour); ConfigureTest(useBeatmapSkin, useBeatmapColour, false);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
} }
@ -72,10 +72,10 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase(false, true)] [TestCase(false, true)]
[TestCase(true, false)] [TestCase(true, false)]
[TestCase(false, false)] [TestCase(false, false)]
public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) public void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, false));
base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour); ConfigureTest(useBeatmapSkin, useBeatmapColour, true);
AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
} }
@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase(false)] [TestCase(false)]
public void TestBeatmapHyperDashColours(bool useBeatmapSkin) public void TestBeatmapHyperDashColours(bool useBeatmapSkin)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true));
ConfigureTest(useBeatmapSkin, true, true); ConfigureTest(useBeatmapSkin, true, true);
AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestBeatmapSkin.HYPER_DASH_COLOUR); AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestBeatmapSkin.HYPER_DASH_COLOUR);
AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestBeatmapSkin.HYPER_DASH_AFTER_IMAGE_COLOUR); AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestBeatmapSkin.HYPER_DASH_AFTER_IMAGE_COLOUR);
@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase(false)] [TestCase(false)]
public void TestBeatmapHyperDashColoursOverride(bool useBeatmapSkin) public void TestBeatmapHyperDashColoursOverride(bool useBeatmapSkin)
{ {
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true));
ConfigureTest(useBeatmapSkin, false, true); ConfigureTest(useBeatmapSkin, false, true);
AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestSkin.HYPER_DASH_COLOUR); AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestSkin.HYPER_DASH_COLOUR);
AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestSkin.HYPER_DASH_AFTER_IMAGE_COLOUR); AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestSkin.HYPER_DASH_AFTER_IMAGE_COLOUR);

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -161,13 +161,13 @@ namespace osu.Game.Rulesets.Catch
switch (result) switch (result)
{ {
case HitResult.LargeTickHit: case HitResult.LargeTickHit:
return "large droplet"; return "Large droplet";
case HitResult.SmallTickHit: case HitResult.SmallTickHit:
return "small droplet"; return "Small droplet";
case HitResult.LargeBonus: case HitResult.LargeBonus:
return "banana"; return "Banana";
} }
return base.GetDisplayNameForHitResult(result); return base.GetDisplayNameForHitResult(result);

View File

@ -1,8 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK.Graphics; using osuTK.Graphics;
@ -22,59 +24,68 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
public override Drawable GetDrawableComponent(ISkinComponent component) public override Drawable GetDrawableComponent(ISkinComponent component)
{ {
if (component is HUDSkinComponent hudComponent) if (component is SkinnableTargetComponent targetComponent)
{ {
switch (hudComponent.Component) switch (targetComponent.Target)
{ {
case HUDSkinComponents.ComboCounter: case SkinnableTarget.MainHUDComponents:
// catch may provide its own combo counter; hide the default. var components = Source.GetDrawableComponent(component) as SkinnableTargetComponentsContainer;
return providesComboCounter ? Drawable.Empty() : null;
if (providesComboCounter && components != null)
{
// catch may provide its own combo counter; hide the default.
// todo: this should be done in an elegant way per ruleset, defining which HUD skin components should be displayed.
foreach (var legacyComboCounter in components.OfType<LegacyComboCounter>())
legacyComboCounter.HiddenByRulesetImplementation = false;
}
return components;
} }
} }
if (!(component is CatchSkinComponent catchSkinComponent)) if (component is CatchSkinComponent catchSkinComponent)
return null;
switch (catchSkinComponent.Component)
{ {
case CatchSkinComponents.Fruit: switch (catchSkinComponent.Component)
if (GetTexture("fruit-pear") != null) {
return new LegacyFruitPiece(); case CatchSkinComponents.Fruit:
if (GetTexture("fruit-pear") != null)
return new LegacyFruitPiece();
break; return null;
case CatchSkinComponents.Banana: case CatchSkinComponents.Banana:
if (GetTexture("fruit-bananas") != null) if (GetTexture("fruit-bananas") != null)
return new LegacyBananaPiece(); return new LegacyBananaPiece();
break; return null;
case CatchSkinComponents.Droplet: case CatchSkinComponents.Droplet:
if (GetTexture("fruit-drop") != null) if (GetTexture("fruit-drop") != null)
return new LegacyDropletPiece(); return new LegacyDropletPiece();
break; return null;
case CatchSkinComponents.CatcherIdle: case CatchSkinComponents.CatcherIdle:
return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? return this.GetAnimation("fruit-catcher-idle", true, true, true) ??
this.GetAnimation("fruit-ryuuta", true, true, true); this.GetAnimation("fruit-ryuuta", true, true, true);
case CatchSkinComponents.CatcherFail: case CatchSkinComponents.CatcherFail:
return this.GetAnimation("fruit-catcher-fail", true, true, true) ?? return this.GetAnimation("fruit-catcher-fail", true, true, true) ??
this.GetAnimation("fruit-ryuuta", true, true, true); this.GetAnimation("fruit-ryuuta", true, true, true);
case CatchSkinComponents.CatcherKiai: case CatchSkinComponents.CatcherKiai:
return this.GetAnimation("fruit-catcher-kiai", true, true, true) ?? return this.GetAnimation("fruit-catcher-kiai", true, true, true) ??
this.GetAnimation("fruit-ryuuta", true, true, true); this.GetAnimation("fruit-ryuuta", true, true, true);
case CatchSkinComponents.CatchComboCounter: case CatchSkinComponents.CatchComboCounter:
if (providesComboCounter) if (providesComboCounter)
return new LegacyCatchComboCounter(Source); return new LegacyCatchComboCounter(Source);
break; return null;
}
} }
return null; return Source.GetDrawableComponent(component);
} }
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[SetUp] [SetUp]
public void SetUp() => Schedule(() => public void SetUp() => Schedule(() =>
{ {
SetContents(() => new FillFlowContainer SetContents(_ => new FillFlowContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new FillFlowContainer SetContents(_ => new FillFlowContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new FillFlowContainer SetContents(_ => new FillFlowContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{ {
if (hitWindows.IsHitResultAllowed(result)) if (hitWindows.IsHitResultAllowed(result))
{ {
AddStep("Show " + result.GetDescription(), () => SetContents(() => AddStep("Show " + result.GetDescription(), () => SetContents(_ =>
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement()) new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
{ {
Type = result Type = result

View File

@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => SetContents(_ =>
{ {
var pool = new DrawablePool<PoolableHitExplosion>(5); var pool = new DrawablePool<PoolableHitExplosion>(5);
hitExplosionPools.Add(pool); hitExplosionPools.Add(pool);

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new FillFlowContainer SetContents(_ => new FillFlowContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
new StageDefinition { Columns = 2 } new StageDefinition { Columns = 2 }
}; };
SetContents(() => new ManiaPlayfield(stageDefinitions)); SetContents(_ => new ManiaPlayfield(stageDefinitions));
}); });
} }
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
new StageDefinition { Columns = 2 } new StageDefinition { Columns = 2 }
}; };
SetContents(() => new ManiaPlayfield(stageDefinitions)); SetContents(_ => new ManiaPlayfield(stageDefinitions));
}); });
} }

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => SetContents(_ =>
{ {
ManiaAction normalAction = ManiaAction.Key1; ManiaAction normalAction = ManiaAction.Key1;
ManiaAction specialAction = ManiaAction.Special1; ManiaAction specialAction = ManiaAction.Special1;

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: new StageDefinition { Columns = 4 }), SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: new StageDefinition { Columns = 4 }),
_ => new DefaultStageBackground()) _ => new DefaultStageBackground())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,

View File

@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: new StageDefinition { Columns = 4 }), _ => null) SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: new StageDefinition { Columns = 4 }), _ => null)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Tests
public class TestSceneManiaHitObjectSamples : HitObjectSampleTest public class TestSceneManiaHitObjectSamples : HitObjectSampleTest
{ {
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
protected override IResourceStore<byte[]> Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples))); protected override IResourceStore<byte[]> RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples)));
/// <summary> /// <summary>
/// Tests that when a normal sample bank is used, the normal hitsound will be looked up. /// Tests that when a normal sample bank is used, the normal hitsound will be looked up.

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
break; break;
} }
return null; return Source.GetDrawableComponent(component);
} }
private Drawable getResult(HitResult result) private Drawable getResult(HitResult result)

View File

@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
int poolIndex = 0; int poolIndex = 0;
SetContents(() => SetContents(_ =>
{ {
DrawablePool<TestDrawableOsuJudgement> pool; DrawablePool<TestDrawableOsuJudgement> pool;

View File

@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void loadContent(bool automated = true, Func<SkinProvidingContainer> skinProvider = null) private void loadContent(bool automated = true, Func<SkinProvidingContainer> skinProvider = null)
{ {
SetContents(() => SetContents(_ =>
{ {
var inputManager = automated ? (InputManager)new MovingCursorInputManager() : new OsuInputManager(new OsuRuleset().RulesetInfo); var inputManager = automated ? (InputManager)new MovingCursorInputManager() : new OsuInputManager(new OsuRuleset().RulesetInfo);
var skinContainer = skinProvider?.Invoke() ?? new SkinProvidingContainer(null); var skinContainer = skinProvider?.Invoke() ?? new SkinProvidingContainer(null);

View File

@ -23,18 +23,18 @@ namespace osu.Game.Rulesets.Osu.Tests
[Test] [Test]
public void TestVariousHitCircles() public void TestVariousHitCircles()
{ {
AddStep("Miss Big Single", () => SetContents(() => testSingle(2))); AddStep("Miss Big Single", () => SetContents(_ => testSingle(2)));
AddStep("Miss Medium Single", () => SetContents(() => testSingle(5))); AddStep("Miss Medium Single", () => SetContents(_ => testSingle(5)));
AddStep("Miss Small Single", () => SetContents(() => testSingle(7))); AddStep("Miss Small Single", () => SetContents(_ => testSingle(7)));
AddStep("Hit Big Single", () => SetContents(() => testSingle(2, true))); AddStep("Hit Big Single", () => SetContents(_ => testSingle(2, true)));
AddStep("Hit Medium Single", () => SetContents(() => testSingle(5, true))); AddStep("Hit Medium Single", () => SetContents(_ => testSingle(5, true)));
AddStep("Hit Small Single", () => SetContents(() => testSingle(7, true))); AddStep("Hit Small Single", () => SetContents(_ => testSingle(7, true)));
AddStep("Miss Big Stream", () => SetContents(() => testStream(2))); AddStep("Miss Big Stream", () => SetContents(_ => testStream(2)));
AddStep("Miss Medium Stream", () => SetContents(() => testStream(5))); AddStep("Miss Medium Stream", () => SetContents(_ => testStream(5)));
AddStep("Miss Small Stream", () => SetContents(() => testStream(7))); AddStep("Miss Small Stream", () => SetContents(_ => testStream(7)));
AddStep("Hit Big Stream", () => SetContents(() => testStream(2, true))); AddStep("Hit Big Stream", () => SetContents(_ => testStream(2, true)));
AddStep("Hit Medium Stream", () => SetContents(() => testStream(5, true))); AddStep("Hit Medium Stream", () => SetContents(_ => testStream(5, true)));
AddStep("Hit Small Stream", () => SetContents(() => testStream(7, true))); AddStep("Hit Small Stream", () => SetContents(_ => testStream(7, true)));
} }
private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null) private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null)

View File

@ -30,28 +30,28 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(true, false)] [TestCase(true, false)]
[TestCase(false, true)] [TestCase(false, true)]
[TestCase(false, false)] [TestCase(false, false)]
public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) public void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin)
{ {
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true));
base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin); ConfigureTest(useBeatmapSkin, true, userHasCustomColours);
AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
} }
[TestCase(true)] [TestCase(true)]
[TestCase(false)] [TestCase(false)]
public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin) public void TestBeatmapComboColoursOverride(bool useBeatmapSkin)
{ {
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true));
base.TestBeatmapComboColoursOverride(useBeatmapSkin); ConfigureTest(useBeatmapSkin, false, true);
AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
} }
[TestCase(true)] [TestCase(true)]
[TestCase(false)] [TestCase(false)]
public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) public void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin)
{ {
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true); PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true));
base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin); ConfigureTest(useBeatmapSkin, false, false);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
} }
@ -59,10 +59,10 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(false, true)] [TestCase(false, true)]
[TestCase(true, false)] [TestCase(true, false)]
[TestCase(false, false)] [TestCase(false, false)]
public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) public void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour)
{ {
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false); PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, false));
base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour); ConfigureTest(useBeatmapSkin, useBeatmapColour, false);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
} }
@ -70,10 +70,10 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(false, true)] [TestCase(false, true)]
[TestCase(true, false)] [TestCase(true, false)]
[TestCase(false, false)] [TestCase(false, false)]
public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) public void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour)
{ {
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false); PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, false));
base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour); ConfigureTest(useBeatmapSkin, useBeatmapColour, true);
AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
} }

View File

@ -30,54 +30,54 @@ namespace osu.Game.Rulesets.Osu.Tests
[Test] [Test]
public void TestVariousSliders() public void TestVariousSliders()
{ {
AddStep("Big Single", () => SetContents(() => testSimpleBig())); AddStep("Big Single", () => SetContents(_ => testSimpleBig()));
AddStep("Medium Single", () => SetContents(() => testSimpleMedium())); AddStep("Medium Single", () => SetContents(_ => testSimpleMedium()));
AddStep("Small Single", () => SetContents(() => testSimpleSmall())); AddStep("Small Single", () => SetContents(_ => testSimpleSmall()));
AddStep("Big 1 Repeat", () => SetContents(() => testSimpleBig(1))); AddStep("Big 1 Repeat", () => SetContents(_ => testSimpleBig(1)));
AddStep("Medium 1 Repeat", () => SetContents(() => testSimpleMedium(1))); AddStep("Medium 1 Repeat", () => SetContents(_ => testSimpleMedium(1)));
AddStep("Small 1 Repeat", () => SetContents(() => testSimpleSmall(1))); AddStep("Small 1 Repeat", () => SetContents(_ => testSimpleSmall(1)));
AddStep("Big 2 Repeats", () => SetContents(() => testSimpleBig(2))); AddStep("Big 2 Repeats", () => SetContents(_ => testSimpleBig(2)));
AddStep("Medium 2 Repeats", () => SetContents(() => testSimpleMedium(2))); AddStep("Medium 2 Repeats", () => SetContents(_ => testSimpleMedium(2)));
AddStep("Small 2 Repeats", () => SetContents(() => testSimpleSmall(2))); AddStep("Small 2 Repeats", () => SetContents(_ => testSimpleSmall(2)));
AddStep("Slow Slider", () => SetContents(testSlowSpeed)); // slow long sliders take ages already so no repeat steps AddStep("Slow Slider", () => SetContents(_ => testSlowSpeed())); // slow long sliders take ages already so no repeat steps
AddStep("Slow Short Slider", () => SetContents(() => testShortSlowSpeed())); AddStep("Slow Short Slider", () => SetContents(_ => testShortSlowSpeed()));
AddStep("Slow Short Slider 1 Repeats", () => SetContents(() => testShortSlowSpeed(1))); AddStep("Slow Short Slider 1 Repeats", () => SetContents(_ => testShortSlowSpeed(1)));
AddStep("Slow Short Slider 2 Repeats", () => SetContents(() => testShortSlowSpeed(2))); AddStep("Slow Short Slider 2 Repeats", () => SetContents(_ => testShortSlowSpeed(2)));
AddStep("Fast Slider", () => SetContents(() => testHighSpeed())); AddStep("Fast Slider", () => SetContents(_ => testHighSpeed()));
AddStep("Fast Slider 1 Repeat", () => SetContents(() => testHighSpeed(1))); AddStep("Fast Slider 1 Repeat", () => SetContents(_ => testHighSpeed(1)));
AddStep("Fast Slider 2 Repeats", () => SetContents(() => testHighSpeed(2))); AddStep("Fast Slider 2 Repeats", () => SetContents(_ => testHighSpeed(2)));
AddStep("Fast Short Slider", () => SetContents(() => testShortHighSpeed())); AddStep("Fast Short Slider", () => SetContents(_ => testShortHighSpeed()));
AddStep("Fast Short Slider 1 Repeat", () => SetContents(() => testShortHighSpeed(1))); AddStep("Fast Short Slider 1 Repeat", () => SetContents(_ => testShortHighSpeed(1)));
AddStep("Fast Short Slider 2 Repeats", () => SetContents(() => testShortHighSpeed(2))); AddStep("Fast Short Slider 2 Repeats", () => SetContents(_ => testShortHighSpeed(2)));
AddStep("Fast Short Slider 6 Repeats", () => SetContents(() => testShortHighSpeed(6))); AddStep("Fast Short Slider 6 Repeats", () => SetContents(_ => testShortHighSpeed(6)));
AddStep("Perfect Curve", () => SetContents(() => testPerfect())); AddStep("Perfect Curve", () => SetContents(_ => testPerfect()));
AddStep("Perfect Curve 1 Repeat", () => SetContents(() => testPerfect(1))); AddStep("Perfect Curve 1 Repeat", () => SetContents(_ => testPerfect(1)));
AddStep("Perfect Curve 2 Repeats", () => SetContents(() => testPerfect(2))); AddStep("Perfect Curve 2 Repeats", () => SetContents(_ => testPerfect(2)));
AddStep("Linear Slider", () => SetContents(() => testLinear())); AddStep("Linear Slider", () => SetContents(_ => testLinear()));
AddStep("Linear Slider 1 Repeat", () => SetContents(() => testLinear(1))); AddStep("Linear Slider 1 Repeat", () => SetContents(_ => testLinear(1)));
AddStep("Linear Slider 2 Repeats", () => SetContents(() => testLinear(2))); AddStep("Linear Slider 2 Repeats", () => SetContents(_ => testLinear(2)));
AddStep("Bezier Slider", () => SetContents(() => testBezier())); AddStep("Bezier Slider", () => SetContents(_ => testBezier()));
AddStep("Bezier Slider 1 Repeat", () => SetContents(() => testBezier(1))); AddStep("Bezier Slider 1 Repeat", () => SetContents(_ => testBezier(1)));
AddStep("Bezier Slider 2 Repeats", () => SetContents(() => testBezier(2))); AddStep("Bezier Slider 2 Repeats", () => SetContents(_ => testBezier(2)));
AddStep("Linear Overlapping", () => SetContents(() => testLinearOverlapping())); AddStep("Linear Overlapping", () => SetContents(_ => testLinearOverlapping()));
AddStep("Linear Overlapping 1 Repeat", () => SetContents(() => testLinearOverlapping(1))); AddStep("Linear Overlapping 1 Repeat", () => SetContents(_ => testLinearOverlapping(1)));
AddStep("Linear Overlapping 2 Repeats", () => SetContents(() => testLinearOverlapping(2))); AddStep("Linear Overlapping 2 Repeats", () => SetContents(_ => testLinearOverlapping(2)));
AddStep("Catmull Slider", () => SetContents(() => testCatmull())); AddStep("Catmull Slider", () => SetContents(_ => testCatmull()));
AddStep("Catmull Slider 1 Repeat", () => SetContents(() => testCatmull(1))); AddStep("Catmull Slider 1 Repeat", () => SetContents(_ => testCatmull(1)));
AddStep("Catmull Slider 2 Repeats", () => SetContents(() => testCatmull(2))); AddStep("Catmull Slider 2 Repeats", () => SetContents(_ => testCatmull(2)));
AddStep("Big Single, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset())); AddStep("Big Single, Large StackOffset", () => SetContents(_ => testSimpleBigLargeStackOffset()));
AddStep("Big 1 Repeat, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset(1))); AddStep("Big 1 Repeat, Large StackOffset", () => SetContents(_ => testSimpleBigLargeStackOffset(1)));
AddStep("Distance Overflow", () => SetContents(() => testDistanceOverflow())); AddStep("Distance Overflow", () => SetContents(_ => testDistanceOverflow()));
AddStep("Distance Overflow 1 Repeat", () => SetContents(() => testDistanceOverflow(1))); AddStep("Distance Overflow 1 Repeat", () => SetContents(_ => testDistanceOverflow(1)));
} }
[Test] [Test]

View File

@ -29,15 +29,15 @@ namespace osu.Game.Rulesets.Osu.Tests
public void TestVariousSpinners(bool autoplay) public void TestVariousSpinners(bool autoplay)
{ {
string term = autoplay ? "Hit" : "Miss"; string term = autoplay ? "Hit" : "Miss";
AddStep($"{term} Big", () => SetContents(() => testSingle(2, autoplay))); AddStep($"{term} Big", () => SetContents(_ => testSingle(2, autoplay)));
AddStep($"{term} Medium", () => SetContents(() => testSingle(5, autoplay))); AddStep($"{term} Medium", () => SetContents(_ => testSingle(5, autoplay)));
AddStep($"{term} Small", () => SetContents(() => testSingle(7, autoplay))); AddStep($"{term} Small", () => SetContents(_ => testSingle(7, autoplay)));
} }
[Test] [Test]
public void TestSpinningSamplePitchShift() public void TestSpinningSamplePitchShift()
{ {
AddStep("Add spinner", () => SetContents(() => testSingle(5, true, 4000))); AddStep("Add spinner", () => SetContents(_ => testSingle(5, true, 4000)));
AddUntilStep("Pitch starts low", () => getSpinningSample().Frequency.Value < 0.8); AddUntilStep("Pitch starts low", () => getSpinningSample().Frequency.Value < 0.8);
AddUntilStep("Pitch increases", () => getSpinningSample().Frequency.Value > 0.8); AddUntilStep("Pitch increases", () => getSpinningSample().Frequency.Value > 0.8);
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(true)] [TestCase(true)]
public void TestLongSpinner(bool autoplay) public void TestLongSpinner(bool autoplay)
{ {
AddStep("Very long spinner", () => SetContents(() => testSingle(5, autoplay, 4000))); AddStep("Very long spinner", () => SetContents(_ => testSingle(5, autoplay, 4000)));
AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult); AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult);
AddUntilStep("Check correct progress", () => drawableSpinner.Progress == (autoplay ? 1 : 0)); AddUntilStep("Check correct progress", () => drawableSpinner.Progress == (autoplay ? 1 : 0));
} }
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(true)] [TestCase(true)]
public void TestSuperShortSpinner(bool autoplay) public void TestSuperShortSpinner(bool autoplay)
{ {
AddStep("Very short spinner", () => SetContents(() => testSingle(5, autoplay, 200))); AddStep("Very short spinner", () => SetContents(_ => testSingle(5, autoplay, 200)));
AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult); AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult);
AddUntilStep("Short spinner implicitly completes", () => drawableSpinner.Progress == 1); AddUntilStep("Short spinner implicitly completes", () => drawableSpinner.Progress == 1);
} }

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -182,8 +182,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
// todo: temporary / arbitrary, used for lifetime optimisation. // todo: temporary / arbitrary, used for lifetime optimisation.
this.Delay(800).FadeOut(); this.Delay(800).FadeOut();
(CirclePiece.Drawable as IMainCirclePiece)?.Animate(state);
switch (state) switch (state)
{ {
case ArmedState.Idle: case ArmedState.Idle:

View File

@ -97,8 +97,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
base.UpdateHitStateTransforms(state); base.UpdateHitStateTransforms(state);
(CirclePiece.Drawable as IMainCirclePiece)?.Animate(state);
switch (state) switch (state)
{ {
case ArmedState.Idle: case ArmedState.Idle:

View File

@ -7,13 +7,14 @@ 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.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, ITrackSnaking, IHasMainCirclePiece public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, IHasMainCirclePiece
{ {
public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject; public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject;
@ -86,8 +87,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Debug.Assert(HitObject.HitWindows != null); Debug.Assert(HitObject.HitWindows != null);
(CirclePiece.Drawable as IMainCirclePiece)?.Animate(state);
switch (state) switch (state)
{ {
case ArmedState.Idle: case ArmedState.Idle:
@ -111,7 +110,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult); ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
} }
public void UpdateSnakingPosition(Vector2 start, Vector2 end) => protected override void OnApply()
Position = HitObject.RepeatIndex % 2 == 0 ? end : start; {
base.OnApply();
if (Slider != null)
Position = Slider.CurvePositionAt(HitObject.RepeatIndex % 2 == 0 ? 1 : 0);
}
} }
} }

View File

@ -1,17 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Skinning.Default
{
public interface IMainCirclePiece
{
/// <summary>
/// Begins animating this <see cref="IMainCirclePiece"/>.
/// </summary>
/// <param name="state">The <see cref="ArmedState"/> of the related <see cref="DrawableHitCircle"/>.</param>
void Animate(ArmedState state);
}
}

View File

@ -13,7 +13,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Skinning.Default namespace osu.Game.Rulesets.Osu.Skinning.Default
{ {
public class MainCirclePiece : CompositeDrawable, IMainCirclePiece public class MainCirclePiece : CompositeDrawable
{ {
private readonly CirclePiece circle; private readonly CirclePiece circle;
private readonly RingPiece ring; private readonly RingPiece ring;
@ -42,6 +42,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
private readonly IBindable<Color4> accentColour = new Bindable<Color4>(); private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>(); private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
private readonly IBindable<ArmedState> armedState = new Bindable<ArmedState>();
[Resolved] [Resolved]
private DrawableHitObject drawableObject { get; set; } private DrawableHitObject drawableObject { get; set; }
@ -53,6 +54,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
accentColour.BindTo(drawableObject.AccentColour); accentColour.BindTo(drawableObject.AccentColour);
indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable);
armedState.BindTo(drawableObject.State);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -67,16 +69,20 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
}, true); }, true);
indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true);
armedState.BindValueChanged(animate, true);
} }
public void Animate(ArmedState state) private void animate(ValueChangedEvent<ArmedState> state)
{ {
ClearTransforms(true);
using (BeginAbsoluteSequence(drawableObject.StateUpdateTime)) using (BeginAbsoluteSequence(drawableObject.StateUpdateTime))
glow.FadeOut(400); glow.FadeOut(400);
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
{ {
switch (state) switch (state.NewValue)
{ {
case ArmedState.Hit: case ArmedState.Hit:
const double flash_in = 40; const double flash_in = 40;
@ -89,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
explode.FadeIn(flash_in); explode.FadeIn(flash_in);
this.ScaleTo(1.5f, 400, Easing.OutQuad); this.ScaleTo(1.5f, 400, Easing.OutQuad);
using (BeginDelayedSequence(flash_in, true)) using (BeginDelayedSequence(flash_in))
{ {
// after the flash, we can hide some elements that were behind it // after the flash, we can hide some elements that were behind it
ring.FadeOut(); ring.FadeOut();

View File

@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -20,7 +19,7 @@ using static osu.Game.Skinning.LegacySkinConfiguration;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{ {
public class LegacyMainCirclePiece : CompositeDrawable, IMainCirclePiece public class LegacyMainCirclePiece : CompositeDrawable
{ {
private readonly string priorityLookup; private readonly string priorityLookup;
private readonly bool hasNumber; private readonly bool hasNumber;
@ -41,6 +40,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
private readonly Bindable<Color4> accentColour = new Bindable<Color4>(); private readonly Bindable<Color4> accentColour = new Bindable<Color4>();
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>(); private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
private readonly IBindable<ArmedState> armedState = new Bindable<ArmedState>();
[Resolved] [Resolved]
private DrawableHitObject drawableObject { get; set; } private DrawableHitObject drawableObject { get; set; }
@ -115,6 +115,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
accentColour.BindTo(drawableObject.AccentColour); accentColour.BindTo(drawableObject.AccentColour);
indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable);
armedState.BindTo(drawableObject.State);
Texture getTextureWithFallback(string name) Texture getTextureWithFallback(string name)
{ {
@ -139,15 +140,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
if (hasNumber) if (hasNumber)
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
armedState.BindValueChanged(animate, true);
} }
public void Animate(ArmedState state) private void animate(ValueChangedEvent<ArmedState> state)
{ {
const double legacy_fade_duration = 240; const double legacy_fade_duration = 240;
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime, true)) ClearTransforms(true);
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
{ {
switch (state) switch (state.NewValue)
{ {
case ArmedState.Hit: case ArmedState.Hit:
circleSprites.FadeOut(legacy_fade_duration, Easing.Out); circleSprites.FadeOut(legacy_fade_duration, Easing.Out);

View File

@ -34,90 +34,90 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
public override Drawable GetDrawableComponent(ISkinComponent component) public override Drawable GetDrawableComponent(ISkinComponent component)
{ {
if (!(component is OsuSkinComponent osuComponent)) if (component is OsuSkinComponent osuComponent)
return null;
switch (osuComponent.Component)
{ {
case OsuSkinComponents.FollowPoint: switch (osuComponent.Component)
return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false); {
case OsuSkinComponents.FollowPoint:
return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false);
case OsuSkinComponents.SliderFollowCircle: case OsuSkinComponents.SliderFollowCircle:
var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true); var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true);
if (followCircle != null) if (followCircle != null)
// follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x // follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x
followCircle.Scale *= 0.5f; followCircle.Scale *= 0.5f;
return followCircle; return followCircle;
case OsuSkinComponents.SliderBall: case OsuSkinComponents.SliderBall:
var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: ""); var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: "");
// todo: slider ball has a custom frame delay based on velocity // todo: slider ball has a custom frame delay based on velocity
// Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME); // Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
if (sliderBallContent != null) if (sliderBallContent != null)
return new LegacySliderBall(sliderBallContent); return new LegacySliderBall(sliderBallContent);
return null;
case OsuSkinComponents.SliderBody:
if (hasHitCircle.Value)
return new LegacySliderBody();
return null;
case OsuSkinComponents.SliderTailHitCircle:
if (hasHitCircle.Value)
return new LegacyMainCirclePiece("sliderendcircle", false);
return null;
case OsuSkinComponents.SliderHeadHitCircle:
if (hasHitCircle.Value)
return new LegacyMainCirclePiece("sliderstartcircle");
return null;
case OsuSkinComponents.HitCircle:
if (hasHitCircle.Value)
return new LegacyMainCirclePiece();
return null;
case OsuSkinComponents.Cursor:
if (Source.GetTexture("cursor") != null)
return new LegacyCursor();
return null;
case OsuSkinComponents.CursorTrail:
if (Source.GetTexture("cursortrail") != null)
return new LegacyCursorTrail();
return null;
case OsuSkinComponents.HitCircleText:
if (!this.HasFont(LegacyFont.HitCircle))
return null; return null;
return new LegacySpriteText(LegacyFont.HitCircle) case OsuSkinComponents.SliderBody:
{ if (hasHitCircle.Value)
// stable applies a blanket 0.8x scale to hitcircle fonts return new LegacySliderBody();
Scale = new Vector2(0.8f),
};
case OsuSkinComponents.SpinnerBody: return null;
bool hasBackground = Source.GetTexture("spinner-background") != null;
if (Source.GetTexture("spinner-top") != null && !hasBackground) case OsuSkinComponents.SliderTailHitCircle:
return new LegacyNewStyleSpinner(); if (hasHitCircle.Value)
else if (hasBackground) return new LegacyMainCirclePiece("sliderendcircle", false);
return new LegacyOldStyleSpinner();
return null; return null;
case OsuSkinComponents.SliderHeadHitCircle:
if (hasHitCircle.Value)
return new LegacyMainCirclePiece("sliderstartcircle");
return null;
case OsuSkinComponents.HitCircle:
if (hasHitCircle.Value)
return new LegacyMainCirclePiece();
return null;
case OsuSkinComponents.Cursor:
if (Source.GetTexture("cursor") != null)
return new LegacyCursor();
return null;
case OsuSkinComponents.CursorTrail:
if (Source.GetTexture("cursortrail") != null)
return new LegacyCursorTrail();
return null;
case OsuSkinComponents.HitCircleText:
if (!this.HasFont(LegacyFont.HitCircle))
return null;
return new LegacySpriteText(LegacyFont.HitCircle)
{
// stable applies a blanket 0.8x scale to hitcircle fonts
Scale = new Vector2(0.8f),
};
case OsuSkinComponents.SpinnerBody:
bool hasBackground = Source.GetTexture("spinner-background") != null;
if (Source.GetTexture("spinner-top") != null && !hasBackground)
return new LegacyNewStyleSpinner();
else if (hasBackground)
return new LegacyOldStyleSpinner();
return null;
}
} }
return null; return Source.GetDrawableComponent(component);
} }
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
AddStep("Bar line", () => SetContents(() => AddStep("Bar line", () => SetContents(_ =>
{ {
ScrollingHitObjectContainer hoc; ScrollingHitObjectContainer hoc;
@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
return cont; return cont;
})); }));
AddStep("Bar line (major)", () => SetContents(() => AddStep("Bar line (major)", () => SetContents(_ =>
{ {
ScrollingHitObjectContainer hoc; ScrollingHitObjectContainer hoc;

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
AddStep("Drum roll", () => SetContents(() => AddStep("Drum roll", () => SetContents(_ =>
{ {
var hoc = new ScrollingHitObjectContainer(); var hoc = new ScrollingHitObjectContainer();
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
return hoc; return hoc;
})); }));
AddStep("Drum roll (strong)", () => SetContents(() => AddStep("Drum roll (strong)", () => SetContents(_ =>
{ {
var hoc = new ScrollingHitObjectContainer(); var hoc = new ScrollingHitObjectContainer();

View File

@ -17,25 +17,25 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
AddStep("Centre hit", () => SetContents(() => new DrawableHit(createHitAtCurrentTime()) AddStep("Centre hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
})); }));
AddStep("Centre hit (strong)", () => SetContents(() => new DrawableHit(createHitAtCurrentTime(true)) AddStep("Centre hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true))
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
})); }));
AddStep("Rim hit", () => SetContents(() => new DrawableHit(createHitAtCurrentTime()) AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
})); }));
AddStep("Rim hit (strong)", () => SetContents(() => new DrawableHit(createHitAtCurrentTime(true)) AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true))
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -54,16 +54,16 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
{ {
AddStep("set beatmap", () => setBeatmap()); AddStep("set beatmap", () => setBeatmap());
AddStep("clear state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Clear))); AddStep("clear state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Clear)));
AddStep("idle state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Idle))); AddStep("idle state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Idle)));
AddStep("kiai state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Kiai))); AddStep("kiai state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Kiai)));
AddStep("fail state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Fail))); AddStep("fail state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Fail)));
} }
[Test] [Test]
public void TestInitialState() public void TestInitialState()
{ {
AddStep("create mascot", () => SetContents(() => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); AddStep("create mascot", () => SetContents(_ => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both }));
AddAssert("mascot initially idle", () => allMascotsIn(TaikoMascotAnimationState.Idle)); AddAssert("mascot initially idle", () => allMascotsIn(TaikoMascotAnimationState.Idle));
} }
@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
{ {
AddStep("set beatmap", () => setBeatmap()); AddStep("set beatmap", () => setBeatmap());
AddStep("create mascot", () => SetContents(() => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); AddStep("create mascot", () => SetContents(_ => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both }));
AddStep("set clear state", () => mascots.ForEach(mascot => mascot.State.Value = TaikoMascotAnimationState.Clear)); AddStep("set clear state", () => mascots.ForEach(mascot => mascot.State.Value = TaikoMascotAnimationState.Clear));
AddStep("miss", () => mascots.ForEach(mascot => mascot.LastResult.Value = new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss })); AddStep("miss", () => mascots.ForEach(mascot => mascot.LastResult.Value = new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }));
@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
{ {
Beatmap.Value.Track.Start(); Beatmap.Value.Track.Start();
SetContents(() => SetContents(_ =>
{ {
var ruleset = new TaikoRuleset(); var ruleset = new TaikoRuleset();
return new DrawableTaikoRuleset(ruleset, Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo)); return new DrawableTaikoRuleset(ruleset, Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo));

View File

@ -22,16 +22,16 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[Test] [Test]
public void TestNormalHit() public void TestNormalHit()
{ {
AddStep("Great", () => SetContents(() => getContentFor(createHit(HitResult.Great)))); AddStep("Great", () => SetContents(_ => getContentFor(createHit(HitResult.Great))));
AddStep("Ok", () => SetContents(() => getContentFor(createHit(HitResult.Ok)))); AddStep("Ok", () => SetContents(_ => getContentFor(createHit(HitResult.Ok))));
AddStep("Miss", () => SetContents(() => getContentFor(createHit(HitResult.Miss)))); AddStep("Miss", () => SetContents(_ => getContentFor(createHit(HitResult.Miss))));
} }
[TestCase(HitResult.Great)] [TestCase(HitResult.Great)]
[TestCase(HitResult.Ok)] [TestCase(HitResult.Ok)]
public void TestStrongHit(HitResult type) public void TestStrongHit(HitResult type)
{ {
AddStep("create hit", () => SetContents(() => getContentFor(createStrongHit(type)))); AddStep("create hit", () => SetContents(_ => getContentFor(createStrongHit(type))));
AddStep("visualise second hit", AddStep("visualise second hit",
() => this.ChildrenOfType<HitExplosion>() () => this.ChildrenOfType<HitExplosion>()
.ForEach(e => e.VisualiseSecondHit(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())))); .ForEach(e => e.VisualiseSecondHit(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement()))));

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new TaikoInputManager(new TaikoRuleset().RulesetInfo) SetContents(_ => new TaikoInputManager(new TaikoRuleset().RulesetInfo)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = new Container Child = new Container

View File

@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[Test] [Test]
public void TestKiaiHits() public void TestKiaiHits()
{ {
AddStep("rim hit", () => SetContents(() => getContentFor(createHit(HitType.Rim)))); AddStep("rim hit", () => SetContents(_ => getContentFor(createHit(HitType.Rim))));
AddStep("centre hit", () => SetContents(() => getContentFor(createHit(HitType.Centre)))); AddStep("centre hit", () => SetContents(_ => getContentFor(createHit(HitType.Centre))));
} }
private Drawable getContentFor(DrawableTestHit hit) private Drawable getContentFor(DrawableTestHit hit)

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
Beatmap.Value.Track.Start(); Beatmap.Value.Track.Start();
}); });
AddStep("Load playfield", () => SetContents(() => new TaikoPlayfield(new ControlPointInfo()) AddStep("Load playfield", () => SetContents(_ => new TaikoPlayfield(new ControlPointInfo())
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
public TestSceneTaikoScroller() public TestSceneTaikoScroller()
{ {
AddStep("Load scroller", () => SetContents(() => AddStep("Load scroller", () => SetContents(_ =>
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty()) new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty())
{ {
Clock = new FramedClock(clock), Clock = new FramedClock(clock),

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
{ {
protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset();
protected override IResourceStore<byte[]> Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples))); protected override IResourceStore<byte[]> RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples)));
[TestCase("taiko-normal-hitnormal")] [TestCase("taiko-normal-hitnormal")]
[TestCase("normal-hitnormal")] [TestCase("normal-hitnormal")]

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -79,8 +79,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
// Old osu! used hit sounding to determine various hit type information // Old osu! used hit sounding to determine various hit type information
IList<HitSampleInfo> samples = obj.Samples; IList<HitSampleInfo> samples = obj.Samples;
bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
switch (obj) switch (obj)
{ {
case IHasDistance distanceData: case IHasDistance distanceData:
@ -94,15 +92,11 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
{ {
IList<HitSampleInfo> currentSamples = allSamples[i]; IList<HitSampleInfo> currentSamples = allSamples[i];
bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
yield return new Hit yield return new Hit
{ {
StartTime = j, StartTime = j,
Type = isRim ? HitType.Rim : HitType.Centre,
Samples = currentSamples, Samples = currentSamples,
IsStrong = strong
}; };
i = (i + 1) % allSamples.Count; i = (i + 1) % allSamples.Count;
@ -117,7 +111,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Samples = obj.Samples, Samples = obj.Samples,
IsStrong = strong,
Duration = taikoDuration, Duration = taikoDuration,
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4 TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4
}; };
@ -143,16 +136,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
default: default:
{ {
bool isRimDefinition(HitSampleInfo s) => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE;
bool isRim = samples.Any(isRimDefinition);
yield return new Hit yield return new Hit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Type = isRim ? HitType.Rim : HitType.Centre,
Samples = samples, Samples = samples,
IsStrong = strong
}; };
break; break;

View File

@ -69,7 +69,11 @@ namespace osu.Game.Rulesets.Taiko.Edit
{ {
EditorBeatmap.PerformOnSelection(h => EditorBeatmap.PerformOnSelection(h =>
{ {
if (h is Hit taikoHit) taikoHit.Type = state ? HitType.Rim : HitType.Centre; if (h is Hit taikoHit)
{
taikoHit.Type = state ? HitType.Rim : HitType.Centre;
EditorBeatmap.Update(h);
}
}); });
} }

View File

@ -17,13 +17,25 @@ namespace osu.Game.Rulesets.Taiko.Objects
public HitType Type public HitType Type
{ {
get => TypeBindable.Value; get => TypeBindable.Value;
set set => TypeBindable.Value = value;
{
TypeBindable.Value = value;
updateSamplesFromType();
}
} }
public Hit()
{
TypeBindable.BindValueChanged(_ => updateSamplesFromType());
SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples());
}
private void updateTypeFromSamples()
{
Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre;
}
/// <summary>
/// Returns an array of any samples which would cause this object to be a "rim" type hit.
/// </summary>
private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray();
private void updateSamplesFromType() private void updateSamplesFromType()
{ {
var rimSamples = getRimSamples(); var rimSamples = getRimSamples();
@ -42,11 +54,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
} }
} }
/// <summary>
/// Returns an array of any samples which would cause this object to be a "rim" type hit.
/// </summary>
private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray();
protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime }; protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime };
public class StrongNestedHit : StrongNestedHitObject public class StrongNestedHit : StrongNestedHitObject

View File

@ -33,14 +33,21 @@ namespace osu.Game.Rulesets.Taiko.Objects
public bool IsStrong public bool IsStrong
{ {
get => IsStrongBindable.Value; get => IsStrongBindable.Value;
set set => IsStrongBindable.Value = value;
{
IsStrongBindable.Value = value;
updateSamplesFromStrong();
}
} }
private void updateSamplesFromStrong() protected TaikoStrongableHitObject()
{
IsStrongBindable.BindValueChanged(_ => updateSamplesFromType());
SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples());
}
private void updateTypeFromSamples()
{
IsStrong = getStrongSamples().Any();
}
private void updateSamplesFromType()
{ {
var strongSamples = getStrongSamples(); var strongSamples = getStrongSamples();

View File

@ -38,98 +38,98 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
return Drawable.Empty().With(d => d.Expire()); return Drawable.Empty().With(d => d.Expire());
} }
if (!(component is TaikoSkinComponent taikoComponent)) if (component is TaikoSkinComponent taikoComponent)
return null;
switch (taikoComponent.Component)
{ {
case TaikoSkinComponents.DrumRollBody: switch (taikoComponent.Component)
if (GetTexture("taiko-roll-middle") != null) {
return new LegacyDrumRoll(); case TaikoSkinComponents.DrumRollBody:
if (GetTexture("taiko-roll-middle") != null)
return new LegacyDrumRoll();
return null; return null;
case TaikoSkinComponents.InputDrum: case TaikoSkinComponents.InputDrum:
if (GetTexture("taiko-bar-left") != null) if (GetTexture("taiko-bar-left") != null)
return new LegacyInputDrum(); return new LegacyInputDrum();
return null; return null;
case TaikoSkinComponents.CentreHit: case TaikoSkinComponents.CentreHit:
case TaikoSkinComponents.RimHit: case TaikoSkinComponents.RimHit:
if (GetTexture("taikohitcircle") != null) if (GetTexture("taikohitcircle") != null)
return new LegacyHit(taikoComponent.Component); return new LegacyHit(taikoComponent.Component);
return null; return null;
case TaikoSkinComponents.DrumRollTick: case TaikoSkinComponents.DrumRollTick:
return this.GetAnimation("sliderscorepoint", false, false); return this.GetAnimation("sliderscorepoint", false, false);
case TaikoSkinComponents.HitTarget: case TaikoSkinComponents.HitTarget:
if (GetTexture("taikobigcircle") != null) if (GetTexture("taikobigcircle") != null)
return new TaikoLegacyHitTarget(); return new TaikoLegacyHitTarget();
return null; return null;
case TaikoSkinComponents.PlayfieldBackgroundRight: case TaikoSkinComponents.PlayfieldBackgroundRight:
if (GetTexture("taiko-bar-right") != null) if (GetTexture("taiko-bar-right") != null)
return new TaikoLegacyPlayfieldBackgroundRight(); return new TaikoLegacyPlayfieldBackgroundRight();
return null; return null;
case TaikoSkinComponents.PlayfieldBackgroundLeft: case TaikoSkinComponents.PlayfieldBackgroundLeft:
// This is displayed inside LegacyInputDrum. It is required to be there for layout purposes (can be seen on legacy skins). // This is displayed inside LegacyInputDrum. It is required to be there for layout purposes (can be seen on legacy skins).
if (GetTexture("taiko-bar-right") != null) if (GetTexture("taiko-bar-right") != null)
return Drawable.Empty(); return Drawable.Empty();
return null; return null;
case TaikoSkinComponents.BarLine: case TaikoSkinComponents.BarLine:
if (GetTexture("taiko-barline") != null) if (GetTexture("taiko-barline") != null)
return new LegacyBarLine(); return new LegacyBarLine();
return null; return null;
case TaikoSkinComponents.TaikoExplosionMiss: case TaikoSkinComponents.TaikoExplosionMiss:
var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false);
if (missSprite != null) if (missSprite != null)
return new LegacyHitExplosion(missSprite); return new LegacyHitExplosion(missSprite);
return null; return null;
case TaikoSkinComponents.TaikoExplosionOk: case TaikoSkinComponents.TaikoExplosionOk:
case TaikoSkinComponents.TaikoExplosionGreat: case TaikoSkinComponents.TaikoExplosionGreat:
var hitName = getHitName(taikoComponent.Component); var hitName = getHitName(taikoComponent.Component);
var hitSprite = this.GetAnimation(hitName, true, false); var hitSprite = this.GetAnimation(hitName, true, false);
if (hitSprite != null) if (hitSprite != null)
{ {
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false); var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
return new LegacyHitExplosion(hitSprite, strongHitSprite); return new LegacyHitExplosion(hitSprite, strongHitSprite);
} }
return null; return null;
case TaikoSkinComponents.TaikoExplosionKiai: case TaikoSkinComponents.TaikoExplosionKiai:
// suppress the default kiai explosion if the skin brings its own sprites. // suppress the default kiai explosion if the skin brings its own sprites.
// the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield. // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield.
if (hasExplosion.Value) if (hasExplosion.Value)
return Drawable.Empty().With(d => d.Expire()); return Drawable.Empty().With(d => d.Expire());
return null; return null;
case TaikoSkinComponents.Scroller: case TaikoSkinComponents.Scroller:
if (GetTexture("taiko-slider") != null) if (GetTexture("taiko-slider") != null)
return new LegacyTaikoScroller(); return new LegacyTaikoScroller();
return null; return null;
case TaikoSkinComponents.Mascot: case TaikoSkinComponents.Mascot:
return new DrawableTaikoMascot(); return new DrawableTaikoMascot();
}
} }
return Source.GetDrawableComponent(component); return Source.GetDrawableComponent(component);

View File

@ -169,6 +169,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
protected override Track GetBeatmapTrack() => throw new NotImplementedException(); protected override Track GetBeatmapTrack() => throw new NotImplementedException();
protected override ISkin GetSkin() => throw new NotImplementedException();
public override Stream GetStream(string storagePath) => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException();
} }
} }

View File

@ -24,10 +24,10 @@ namespace osu.Game.Tests.Chat
[TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456?whatever")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456?whatever")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123/456")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123/456")]
[TestCase(LinkAction.External, null, "https://dev.ppy.sh/beatmapsets/abc/def")] [TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc/def", "https://dev.ppy.sh/beatmapsets/abc/def")]
[TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123")] [TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123")]
[TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123/whatever")] [TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123/whatever")]
[TestCase(LinkAction.External, null, "https://dev.ppy.sh/beatmapsets/abc")] [TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc", "https://dev.ppy.sh/beatmapsets/abc")]
public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link) public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link)
{ {
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh"; MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
@ -489,5 +489,23 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(result.Links[2].Url, "\uD83D\uDE00"); Assert.AreEqual(result.Links[2].Url, "\uD83D\uDE00");
Assert.AreEqual(result.Links[3].Url, "\uD83D\uDE20"); Assert.AreEqual(result.Links[3].Url, "\uD83D\uDE20");
} }
[Test]
public void TestAbsoluteExternalLinks()
{
LinkDetails result = MessageFormatter.GetLinkDetails("https://google.com");
Assert.AreEqual(LinkAction.External, result.Action);
Assert.AreEqual("https://google.com", result.Argument);
}
[Test]
public void TestRelativeExternalLinks()
{
LinkDetails result = MessageFormatter.GetLinkDetails("/relative");
Assert.AreEqual(LinkAction.External, result.Action);
Assert.AreEqual("/relative", result.Argument);
}
} }
} }

View File

@ -23,7 +23,7 @@ namespace osu.Game.Tests.Collections.IO
{ {
var osu = LoadOsuIntoHost(host); var osu = LoadOsuIntoHost(host);
await osu.CollectionManager.Import(new MemoryStream()); await importCollectionsFromStream(osu, new MemoryStream());
Assert.That(osu.CollectionManager.Collections.Count, Is.Zero); Assert.That(osu.CollectionManager.Collections.Count, Is.Zero);
} }
@ -43,7 +43,7 @@ namespace osu.Game.Tests.Collections.IO
{ {
var osu = LoadOsuIntoHost(host); var osu = LoadOsuIntoHost(host);
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2)); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
@ -69,7 +69,7 @@ namespace osu.Game.Tests.Collections.IO
{ {
var osu = LoadOsuIntoHost(host, true); var osu = LoadOsuIntoHost(host, true);
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2)); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
@ -110,7 +110,7 @@ namespace osu.Game.Tests.Collections.IO
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
await osu.CollectionManager.Import(ms); await importCollectionsFromStream(osu, ms);
} }
Assert.That(host.UpdateThread.Running, Is.True); Assert.That(host.UpdateThread.Running, Is.True);
@ -134,7 +134,7 @@ namespace osu.Game.Tests.Collections.IO
{ {
var osu = LoadOsuIntoHost(host, true); var osu = LoadOsuIntoHost(host, true);
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
// Move first beatmap from second collection into the first. // Move first beatmap from second collection into the first.
osu.CollectionManager.Collections[0].Beatmaps.Add(osu.CollectionManager.Collections[1].Beatmaps[0]); osu.CollectionManager.Collections[0].Beatmaps.Add(osu.CollectionManager.Collections[1].Beatmaps[0]);
@ -169,5 +169,12 @@ namespace osu.Game.Tests.Collections.IO
} }
} }
} }
private static async Task importCollectionsFromStream(TestOsuGameBase osu, Stream stream)
{
// intentionally spin this up on a separate task to avoid disposal deadlocks.
// see https://github.com/EventStore/EventStore/issues/1179
await Task.Run(() => osu.CollectionManager.Import(stream).Wait());
}
} }
} }

View File

@ -3,6 +3,8 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
@ -70,15 +72,81 @@ namespace osu.Game.Tests.Gameplay
AddAssert("Lifetime is changed", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == 1000); AddAssert("Lifetime is changed", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == 1000);
} }
[Test]
public void TestLifetimeUpdatedOnDefaultApplied()
{
TestLifetimeEntry entry = null;
AddStep("Create entry", () => entry = new TestLifetimeEntry(new HitObject()) { LifetimeStart = 1 });
AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()));
AddAssert("Lifetime is updated", () => entry.LifetimeStart == -TestLifetimeEntry.INITIAL_LIFETIME_OFFSET);
TestDrawableHitObject dho = null;
AddStep("Create DHO", () =>
{
dho = new TestDrawableHitObject(null);
dho.Apply(entry);
Child = dho;
dho.SetLifetimeStartOnApply = true;
});
AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()));
AddAssert("Lifetime is correct", () => dho.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY && entry.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY);
}
[Test]
public void TestDrawableLifetimeUpdateOnEntryLifetimeChange()
{
TestDrawableHitObject dho = null;
TestLifetimeEntry entry = null;
AddStep("Create DHO", () =>
{
dho = new TestDrawableHitObject(null);
dho.Apply(entry = new TestLifetimeEntry(new HitObject()));
Child = dho;
});
AddStep("Set entry lifetime", () =>
{
entry.LifetimeStart = 777;
entry.LifetimeEnd = 888;
});
AddAssert("Drawable lifetime is updated", () => dho.LifetimeStart == 777 && dho.LifetimeEnd == 888);
AddStep("KeepAlive = true", () => entry.KeepAlive = true);
AddAssert("Drawable lifetime is updated", () => dho.LifetimeStart == double.MinValue && dho.LifetimeEnd == double.MaxValue);
AddStep("Modify start time", () => entry.HitObject.StartTime = 100);
AddAssert("Drawable lifetime is correct", () => dho.LifetimeStart == double.MinValue);
AddStep("Set LifetimeStart", () => dho.LifetimeStart = 666);
AddAssert("Lifetime change is blocked", () => dho.LifetimeStart == double.MinValue);
AddStep("Set LifetimeEnd", () => dho.LifetimeEnd = 999);
AddAssert("Lifetime change is blocked", () => dho.LifetimeEnd == double.MaxValue);
AddStep("KeepAlive = false", () => entry.KeepAlive = false);
AddAssert("Drawable lifetime is restored", () => dho.LifetimeStart == 666 && dho.LifetimeEnd == 999);
}
private class TestDrawableHitObject : DrawableHitObject private class TestDrawableHitObject : DrawableHitObject
{ {
public const double INITIAL_LIFETIME_OFFSET = 100; public const double INITIAL_LIFETIME_OFFSET = 100;
public const double LIFETIME_ON_APPLY = 222;
protected override double InitialLifetimeOffset => INITIAL_LIFETIME_OFFSET; protected override double InitialLifetimeOffset => INITIAL_LIFETIME_OFFSET;
public bool SetLifetimeStartOnApply;
public TestDrawableHitObject(HitObject hitObject) public TestDrawableHitObject(HitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
} }
protected override void OnApply()
{
base.OnApply();
if (SetLifetimeStartOnApply)
LifetimeStart = LIFETIME_ON_APPLY;
}
} }
private class TestLifetimeEntry : HitObjectLifetimeEntry private class TestLifetimeEntry : HitObjectLifetimeEntry

View File

@ -14,7 +14,7 @@ namespace osu.Game.Tests.Gameplay
public class TestSceneHitObjectSamples : HitObjectSampleTest public class TestSceneHitObjectSamples : HitObjectSampleTest
{ {
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
protected override IResourceStore<byte[]> Resources => TestResources.GetStore(); protected override IResourceStore<byte[]> RulesetResources => TestResources.GetStore();
/// <summary> /// <summary>
/// Tests that a hitobject which provides no custom sample set retrieves samples from the user skin. /// Tests that a hitobject which provides no custom sample set retrieves samples from the user skin.

View File

@ -219,6 +219,7 @@ namespace osu.Game.Tests.Gameplay
public AudioManager AudioManager => Audio; public AudioManager AudioManager => Audio;
public IResourceStore<byte[]> Files => null; public IResourceStore<byte[]> Files => null;
public new IResourceStore<byte[]> Resources => base.Resources;
public IResourceStore<TextureUpload> CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore) => null; public IResourceStore<TextureUpload> CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore) => null;
#endregion #endregion

View File

@ -12,6 +12,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.IO.Stores;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -44,7 +45,7 @@ namespace osu.Game.Tests.Online
private void load(AudioManager audio, GameHost host) private void load(AudioManager audio, GameHost host)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.CacheAs<BeatmapManager>(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, host, Beatmap.Default)); Dependencies.CacheAs<BeatmapManager>(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
} }
[SetUp] [SetUp]
@ -160,8 +161,8 @@ namespace osu.Game.Tests.Online
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize)
=> new TestDownloadRequest(set); => new TestDownloadRequest(set);
public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false) public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore<byte[]> resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false)
: base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, performOnlineLookups) : base(storage, contextFactory, rulesets, api, audioManager, resources, host, defaultBeatmap, performOnlineLookups)
{ {
} }

View File

@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Background
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage)); Dependencies.Cache(new OsuConfigManager(LocalStorage));
manager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); manager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();

View File

@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Collections
private void load(GameHost host) private void load(GameHost host)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();

View File

@ -24,13 +24,13 @@ namespace osu.Game.Tests.Visual.Editing
protected override bool EditorComponentsReady => Editor.ChildrenOfType<SetupScreen>().SingleOrDefault()?.IsLoaded == true; protected override bool EditorComponentsReady => Editor.ChildrenOfType<SetupScreen>().SingleOrDefault()?.IsLoaded == true;
protected override bool IsolateSavingFromDatabase => false;
[Resolved] [Resolved]
private BeatmapManager beatmapManager { get; set; } private BeatmapManager beatmapManager { get; set; }
public override void SetUpSteps() public override void SetUpSteps()
{ {
AddStep("set dummy", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null));
base.SetUpSteps(); base.SetUpSteps();
// if we save a beatmap with a hash collision, things fall over. // if we save a beatmap with a hash collision, things fall over.
@ -38,6 +38,12 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("make new beatmap unique", () => EditorBeatmap.Metadata.Title = Guid.NewGuid().ToString()); AddStep("make new beatmap unique", () => EditorBeatmap.Metadata.Title = Guid.NewGuid().ToString());
} }
protected override void LoadEditor()
{
Beatmap.Value = new DummyWorkingBeatmap(Audio, null);
base.LoadEditor();
}
[Test] [Test]
public void TestCreateNewBeatmap() public void TestCreateNewBeatmap()
{ {

View File

@ -0,0 +1,33 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
namespace osu.Game.Tests.Visual.Gameplay
{
public abstract class SkinnableHUDComponentTestScene : SkinnableTestScene
{
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[SetUp]
public void SetUp() => Schedule(() =>
{
SetContents(skin =>
{
var implementation = skin != null
? CreateLegacyImplementation()
: CreateDefaultImplementation();
implementation.Anchor = Anchor.Centre;
implementation.Origin = Anchor.Centre;
return implementation;
});
});
protected abstract Drawable CreateDefaultImplementation();
protected abstract Drawable CreateLegacyImplementation();
}
}

View File

@ -0,0 +1,130 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics.Containers;
using osu.Framework.Lists;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Skinning.Legacy;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
using osu.Game.Storyboards;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneBeatmapSkinFallbacks : OsuPlayerTestScene
{
private ISkin currentBeatmapSkin;
[Resolved]
private SkinManager skinManager { get; set; }
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[Cached(typeof(HealthProcessor))]
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
protected override bool HasCustomSteps => true;
[Test]
public void TestEmptyLegacyBeatmapSkinFallsBack()
{
CreateSkinTest(SkinInfo.Default, () => new LegacyBeatmapSkin(new BeatmapInfo(), null, null));
AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value));
}
protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func<ISkin> getBeatmapSkin)
{
CreateTest(() =>
{
AddStep("setup skins", () =>
{
skinManager.CurrentSkinInfo.Value = gameCurrentSkin;
currentBeatmapSkin = getBeatmapSkin();
});
});
}
protected bool AssertComponentsFromExpectedSource(SkinnableTarget target, ISkin expectedSource)
{
var actualComponentsContainer = Player.ChildrenOfType<SkinnableTargetContainer>().First(s => s.Target == target)
.ChildrenOfType<SkinnableTargetComponentsContainer>().SingleOrDefault();
if (actualComponentsContainer == null)
return false;
var actualInfo = actualComponentsContainer.CreateSkinnableInfo();
var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new SkinnableTargetComponent(target));
if (expectedComponentsContainer == null)
return false;
var expectedComponentsAdjustmentContainer = new Container
{
Position = actualComponentsContainer.Parent.ToSpaceOfOtherDrawable(actualComponentsContainer.DrawPosition, Content),
Size = actualComponentsContainer.DrawSize,
Child = expectedComponentsContainer,
};
Add(expectedComponentsAdjustmentContainer);
expectedComponentsAdjustmentContainer.UpdateSubTree();
var expectedInfo = expectedComponentsContainer.CreateSkinnableInfo();
Remove(expectedComponentsAdjustmentContainer);
return almostEqual(actualInfo, expectedInfo);
static bool almostEqual(SkinnableInfo info, SkinnableInfo other) =>
other != null
&& info.Type == other.Type
&& info.Anchor == other.Anchor
&& info.Origin == other.Origin
&& Precision.AlmostEquals(info.Position, other.Position)
&& Precision.AlmostEquals(info.Scale, other.Scale)
&& Precision.AlmostEquals(info.Rotation, other.Rotation)
&& info.Children.SequenceEqual(other.Children, new FuncEqualityComparer<SkinnableInfo>(almostEqual));
}
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
=> new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, Audio, currentBeatmapSkin);
protected override Ruleset CreatePlayerRuleset() => new TestOsuRuleset();
private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
{
private readonly ISkin beatmapSkin;
public CustomSkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio, ISkin beatmapSkin)
: base(beatmap, storyboard, referenceClock, audio)
{
this.beatmapSkin = beatmapSkin;
}
protected override ISkin GetSkin() => beatmapSkin;
}
private class TestOsuRuleset : OsuRuleset
{
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new TestOsuLegacySkinTransformer(source);
private class TestOsuLegacySkinTransformer : OsuLegacySkinTransformer
{
public TestOsuLegacySkinTransformer(ISkinSource source)
: base(source)
{
}
}
}
}
}

View File

@ -90,6 +90,20 @@ namespace osu.Game.Tests.Visual.Gameplay
assertChildPosition(5); assertChildPosition(5);
} }
[TestCase("pooled")]
[TestCase("non-pooled")]
public void TestLifetimeRecomputedWhenTimeRangeChanges(string pooled)
{
var beatmap = createBeatmap(_ => pooled == "pooled" ? new TestPooledHitObject() : new TestHitObject());
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
createTest(beatmap);
assertDead(3);
AddStep("increase time range", () => drawableRuleset.TimeRange.Value = 3 * time_range);
assertPosition(3, 1);
}
[Test] [Test]
public void TestRelativeBeatLengthScaleSingleTimingPoint() public void TestRelativeBeatLengthScaleSingleTimingPoint()
{ {

View File

@ -29,8 +29,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = false); AddStep("allow skin lookup", () => storyboard.UseSkinSprites = false);
AddStep("create sprites", () => SetContents( AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
() => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
assertSpritesFromSkin(false); assertSpritesFromSkin(false);
} }
@ -42,8 +41,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
AddStep("create sprites", () => SetContents( AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.Centre, Vector2.Zero)));
() => createSprite(lookup_name, Anchor.Centre, Vector2.Zero)));
assertSpritesFromSkin(true); assertSpritesFromSkin(true);
} }

View File

@ -88,13 +88,18 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
beforeLoadAction?.Invoke(); beforeLoadAction?.Invoke();
prepareBeatmap();
LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive)));
}
private void prepareBeatmap()
{
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning; Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>()) foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
mod.ApplyToTrack(Beatmap.Value.Track); mod.ApplyToTrack(Beatmap.Value.Track);
LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive)));
} }
[Test] [Test]
@ -178,10 +183,13 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("load slow dummy beatmap", () => AddStep("load slow dummy beatmap", () =>
{ {
LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); prepareBeatmap();
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); slowPlayer = new SlowLoadPlayer(false, false);
LoadScreen(loader = new TestPlayerLoader(() => slowPlayer));
}); });
AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000));
AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen()); AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen());
} }

View File

@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestToggleEditor() public void TestToggleEditor()
{ {
AddStep("show available components", () => SetContents(() => new SkinComponentToolbox(300) AddStep("show available components", () => SetContents(_ => new SkinComponentToolbox(300)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,

View File

@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddStep("create editor overlay", () => AddStep("create editor overlay", () =>
{ {
SetContents(() => SetContents(_ =>
{ {
var ruleset = new OsuRuleset(); var ruleset = new OsuRuleset();
var mods = new[] { ruleset.GetAutoplayMod() }; var mods = new[] { ruleset.GetAutoplayMod() };

View File

@ -3,26 +3,26 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene public class TestSceneSkinnableAccuracyCounter : SkinnableHUDComponentTestScene
{ {
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached] [Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor(); private ScoreProcessor scoreProcessor = new ScoreProcessor();
protected override Drawable CreateDefaultImplementation() => new DefaultAccuracyCounter();
protected override Drawable CreateLegacyImplementation() => new LegacyAccuracyCounter();
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1); AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1);
AddStep("Create accuracy counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter))));
} }
[Test] [Test]

View File

@ -3,26 +3,19 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Testing; using osu.Framework.Graphics;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Screens.Play.HUD;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneComboCounter : SkinnableTestScene public class TestSceneSkinnableComboCounter : SkinnableHUDComponentTestScene
{ {
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached] [Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor(); private ScoreProcessor scoreProcessor = new ScoreProcessor();
[SetUpSteps] protected override Drawable CreateDefaultImplementation() => new DefaultComboCounter();
public void SetUpSteps() protected override Drawable CreateLegacyImplementation() => new LegacyComboCounter();
{
AddStep("Create combo counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ComboCounter))));
}
[Test] [Test]
public void TestComboCounterIncrementing() public void TestComboCounterIncrementing()

View File

@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddStep("create overlay", () => AddStep("create overlay", () =>
{ {
SetContents(() => SetContents(_ =>
{ {
hudOverlay = new HUDOverlay(null, Array.Empty<Mod>()); hudOverlay = new HUDOverlay(null, Array.Empty<Mod>());

View File

@ -3,28 +3,28 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneSkinnableHealthDisplay : SkinnableTestScene public class TestSceneSkinnableHealthDisplay : SkinnableHUDComponentTestScene
{ {
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached(typeof(HealthProcessor))] [Cached(typeof(HealthProcessor))]
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
protected override Drawable CreateDefaultImplementation() => new DefaultHealthDisplay();
protected override Drawable CreateLegacyImplementation() => new LegacyHealthDisplay();
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
AddStep("Create health displays", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.HealthDisplay))));
AddStep(@"Reset all", delegate AddStep(@"Reset all", delegate
{ {
healthProcessor.Health.Value = 1; healthProcessor.Health.Value = 1;

View File

@ -3,26 +3,20 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Testing; using osu.Framework.Graphics;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneSkinnableScoreCounter : SkinnableTestScene public class TestSceneSkinnableScoreCounter : SkinnableHUDComponentTestScene
{ {
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached] [Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor(); private ScoreProcessor scoreProcessor = new ScoreProcessor();
[SetUpSteps] protected override Drawable CreateDefaultImplementation() => new DefaultScoreCounter();
public void SetUpSteps() protected override Drawable CreateLegacyImplementation() => new LegacyScoreCounter();
{
AddStep("Create score counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ScoreCounter))));
}
[Test] [Test]
public void TestScoreCounterIncrementing() public void TestScoreCounterIncrementing()

View File

@ -53,7 +53,8 @@ namespace osu.Game.Tests.Visual.Gameplay
CreateTest(null); CreateTest(null);
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space)); AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space));
AddAssert("score shown", () => Player.IsScoreShown); AddUntilStep("wait for score shown", () => Player.IsScoreShown);
AddUntilStep("time less than storyboard duration", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < currentStoryboardDuration);
} }
[Test] [Test]

View File

@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait(); manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();
} }

View File

@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
} }
[SetUp] [SetUp]

View File

@ -73,8 +73,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
for (int i = 0; i < users; i++) for (int i = 0; i < users; i++)
spectatorClient.StartPlay(i, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); spectatorClient.StartPlay(i, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
Client.CurrentMatchPlayingUserIds.Clear(); spectatorClient.Schedule(() =>
Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers); {
Client.CurrentMatchPlayingUserIds.Clear();
Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers);
});
Children = new Drawable[] Children = new Drawable[]
{ {
@ -91,6 +94,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}); });
AddUntilStep("wait for load", () => leaderboard.IsLoaded); AddUntilStep("wait for load", () => leaderboard.IsLoaded);
AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0);
} }
[Test] [Test]

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
beatmaps = new List<BeatmapInfo>(); beatmaps = new List<BeatmapInfo>();

View File

@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();

View File

@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
Add(beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker Add(beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker

View File

@ -141,14 +141,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
private Room createRoom(Action<Room> initFunc = null) private Room createRoom(Action<Room> initFunc = null)
{ {
var room = new Room(); var room = new Room
room.Name.Value = "test room";
room.Playlist.Add(new PlaylistItem
{ {
Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, Name =
Ruleset = { Value = Ruleset.Value } {
}); Value = "test room"
},
Playlist =
{
new PlaylistItem
{
Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo },
Ruleset = { Value = Ruleset.Value }
}
}
};
initFunc?.Invoke(room); initFunc?.Invoke(room);
return room; return room;

View File

@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
var beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = selectedItem } }; var beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = selectedItem } };
base.Content.Add(beatmapTracker); base.Content.Add(beatmapTracker);

View File

@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
var beatmaps = new List<BeatmapInfo>(); var beatmaps = new List<BeatmapInfo>();

View File

@ -0,0 +1,102 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.Wiki;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneWikiHeader : OsuTestScene
{
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange);
[Cached]
private readonly Bindable<APIWikiPage> wikiPageData = new Bindable<APIWikiPage>(new APIWikiPage
{
Title = "Main Page",
Path = "Main_Page",
});
private TestHeader header;
[SetUp]
public void SetUp() => Schedule(() =>
{
Child = header = new TestHeader
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
ShowIndexPage = dummyShowIndexPage,
ShowParentPage = dummyShowParentPage,
};
wikiPageData.BindTo(header.WikiPageData);
});
[Test]
public void TestWikiHeader()
{
AddAssert("Current is index", () => checkCurrent("index"));
AddStep("Change wiki page data", () => wikiPageData.Value = new APIWikiPage
{
Title = "Welcome",
Path = "Welcome"
});
AddAssert("Current is welcome", () => checkCurrent("Welcome"));
AddAssert("Check breadcrumb", checkBreadcrumb);
AddStep("Change current to index", () => header.Current.Value = "index");
AddAssert("Current is index", () => checkCurrent("index"));
AddStep("Change wiki page data", () => wikiPageData.Value = new APIWikiPage
{
Title = "Developers",
Path = "People/The_Team/Developers",
Subtitle = "The Team",
});
AddAssert("Current is 'Developers'", () => checkCurrent("Developers"));
AddAssert("Check breadcrumb", checkBreadcrumb);
AddStep("Change current to 'The Team'", () => header.Current.Value = "The Team");
AddAssert("Current is 'The Team'", () => checkCurrent("The Team"));
AddAssert("Check breadcrumb", checkBreadcrumb);
}
private bool checkCurrent(string expectedCurrent) => header.Current.Value == expectedCurrent;
private bool checkBreadcrumb()
{
var result = header.TabControlItems.Contains(wikiPageData.Value.Title);
if (wikiPageData.Value.Subtitle != null)
result = header.TabControlItems.Contains(wikiPageData.Value.Subtitle) && result;
return result;
}
private void dummyShowIndexPage() => wikiPageData.SetDefault();
private void dummyShowParentPage()
{
wikiPageData.Value = new APIWikiPage
{
Path = "People/The_Team",
Title = "The Team",
Subtitle = "People"
};
}
private class TestHeader : WikiHeader
{
public IReadOnlyList<string> TabControlItems => TabControl.Items;
}
}
}

View File

@ -0,0 +1,43 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Overlays;
using osu.Game.Overlays.Wiki;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneWikiMainPage : OsuTestScene
{
[Cached]
private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange);
public TestSceneWikiMainPage()
{
Children = new Drawable[]
{
new Box
{
Colour = overlayColour.Background5,
RelativeSizeAxes = Axes.Both,
},
new BasicScrollContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
Child = new WikiMainPage
{
Markdown = main_page_markdown
}
}
};
}
// From https://osu.ppy.sh/api/v2/wiki/en/Main_Page
private const string main_page_markdown =
"---\nlayout: main_page\n---\n\n<!-- Do not add any empty lines inside this div. -->\n\n<div class=\"wiki-main-page__blurb\">\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n</div>\n\n<div class=\"wiki-main-page__panels\">\n<div class=\"wiki-main-page-panel wiki-main-page-panel--full\">\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n</div>\n</div>\n";
}
}

View File

@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Online
[Test] [Test]
public void TestLink() public void TestLink()
{ {
AddStep("set current path", () => markdownContainer.CurrentPath = "Article_styling_criteria/"); AddStep("set current path", () => markdownContainer.CurrentPath = $"{API.WebsiteRootUrl}/wiki/Article_styling_criteria/");
AddStep("set '/wiki/Main_Page''", () => markdownContainer.Text = "[wiki main page](/wiki/Main_Page)"); AddStep("set '/wiki/Main_Page''", () => markdownContainer.Text = "[wiki main page](/wiki/Main_Page)");
AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/Main_Page"); AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/Main_Page");
@ -113,7 +113,7 @@ needs_cleanup: true
AddStep("Add relative image", () => AddStep("Add relative image", () =>
{ {
markdownContainer.DocumentUrl = "https://dev.ppy.sh"; markdownContainer.DocumentUrl = "https://dev.ppy.sh";
markdownContainer.CurrentPath = "Interface/"; markdownContainer.CurrentPath = $"{API.WebsiteRootUrl}/wiki/Interface/";
markdownContainer.Text = "![intro](img/intro-screen.jpg)"; markdownContainer.Text = "![intro](img/intro-screen.jpg)";
}); });
} }
@ -124,7 +124,7 @@ needs_cleanup: true
AddStep("Add paragraph with block image", () => AddStep("Add paragraph with block image", () =>
{ {
markdownContainer.DocumentUrl = "https://dev.ppy.sh"; markdownContainer.DocumentUrl = "https://dev.ppy.sh";
markdownContainer.CurrentPath = "Interface/"; markdownContainer.CurrentPath = $"{API.WebsiteRootUrl}/wiki/Interface/";
markdownContainer.Text = @"Line before image markdownContainer.Text = @"Line before image
![play menu](img/play-menu.jpg ""Main Menu in osu!"") ![play menu](img/play-menu.jpg ""Main Menu in osu!"")

File diff suppressed because one or more lines are too long

View File

@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Playlists
private void load(GameHost host, AudioManager audio) private void load(GameHost host, AudioManager audio)
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait(); manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();

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