mirror of
https://github.com/ppy/osu.git
synced 2025-03-03 22:43:04 +08:00
Merge branch 'master' into score-recalc
This commit is contained in:
commit
117c7ec6b2
@ -5,6 +5,6 @@
|
|||||||
"version": "3.1.100"
|
"version": "3.1.100"
|
||||||
},
|
},
|
||||||
"msbuild-sdks": {
|
"msbuild-sdks": {
|
||||||
"Microsoft.Build.Traversal": "2.0.52"
|
"Microsoft.Build.Traversal": "2.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.812.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.819.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.907.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||||
|
@ -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.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<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" />
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
|
||||||
@ -23,19 +22,19 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
{
|
{
|
||||||
Name = @"Fruit Count",
|
Name = @"Fruit Count",
|
||||||
Content = fruits.ToString(),
|
Content = fruits.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Juice Stream Count",
|
Name = @"Juice Stream Count",
|
||||||
Content = juiceStreams.ToString(),
|
Content = juiceStreams.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Banana Shower Count",
|
Name = @"Banana Shower Count",
|
||||||
Content = bananaShowers.ToString(),
|
Content = bananaShowers.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,11 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class CatchRuleset : Ruleset, ILegacyRuleset
|
public class CatchRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Skinning
|
namespace osu.Game.Rulesets.Catch.Skinning
|
||||||
{
|
{
|
||||||
@ -61,7 +62,12 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
|||||||
switch (lookup)
|
switch (lookup)
|
||||||
{
|
{
|
||||||
case CatchSkinColour colour:
|
case CatchSkinColour colour:
|
||||||
return Source.GetConfig<SkinCustomColourLookup, TValue>(new SkinCustomColourLookup(colour));
|
var result = (Bindable<Color4>)Source.GetConfig<SkinCustomColourLookup, TValue>(new SkinCustomColourLookup(colour));
|
||||||
|
if (result == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
result.Value = LegacyColourCompatibility.DisallowZeroAlpha(result.Value);
|
||||||
|
return (IBindable<TValue>)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Source.GetConfig<TLookup, TValue>(lookup);
|
return Source.GetConfig<TLookup, TValue>(lookup);
|
||||||
|
@ -40,7 +40,6 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
|||||||
colouredSprite = new Sprite
|
colouredSprite = new Sprite
|
||||||
{
|
{
|
||||||
Texture = skin.GetTexture(lookupName),
|
Texture = skin.GetTexture(lookupName),
|
||||||
Colour = drawableObject.AccentColour.Value,
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
@ -76,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
accentColour.BindValueChanged(colour => colouredSprite.Colour = colour.NewValue, true);
|
accentColour.BindValueChanged(colour => colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,13 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
[TestCase("basic")]
|
[TestCase("basic")]
|
||||||
|
[TestCase("zero-length-slider")]
|
||||||
public void Test(string name) => base.Test(name);
|
public void Test(string name) => base.Test(name);
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
|
@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(ManiaModPerfect) })]
|
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(ManiaModPerfect) })]
|
||||||
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath | LegacyMods.DoubleTime, new[] { typeof(ManiaModDoubleTime), typeof(ManiaModPerfect) })]
|
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath | LegacyMods.DoubleTime, new[] { typeof(ManiaModDoubleTime), typeof(ManiaModPerfect) })]
|
||||||
[TestCase(LegacyMods.Random | LegacyMods.SuddenDeath, new[] { typeof(ManiaModRandom), typeof(ManiaModSuddenDeath) })]
|
[TestCase(LegacyMods.Random | LegacyMods.SuddenDeath, new[] { typeof(ManiaModRandom), typeof(ManiaModSuddenDeath) })]
|
||||||
|
[TestCase(LegacyMods.Flashlight | LegacyMods.Mirror, new[] { typeof(ManiaModFlashlight), typeof(ManiaModMirror) })]
|
||||||
public new void Test(LegacyMods legacyMods, Type[] expectedMods) => base.Test(legacyMods, expectedMods);
|
public new void Test(LegacyMods legacyMods, Type[] expectedMods) => base.Test(legacyMods, expectedMods);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||||
|
@ -22,18 +22,22 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
[Cached]
|
[Cached]
|
||||||
private readonly Column column;
|
private readonly Column column;
|
||||||
|
|
||||||
public ColumnTestContainer(int column, ManiaAction action)
|
public ColumnTestContainer(int column, ManiaAction action, bool showColumn = false)
|
||||||
{
|
{
|
||||||
this.column = new Column(column)
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
Action = { Value = action },
|
this.column = new Column(column)
|
||||||
AccentColour = Color4.Orange,
|
{
|
||||||
ColumnType = column % 2 == 0 ? ColumnType.Even : ColumnType.Odd
|
Action = { Value = action },
|
||||||
};
|
AccentColour = Color4.Orange,
|
||||||
|
ColumnType = column % 2 == 0 ? ColumnType.Even : ColumnType.Odd,
|
||||||
InternalChild = content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
|
Alpha = showColumn ? 1 : 0
|
||||||
{
|
},
|
||||||
RelativeSizeAxes = Axes.Both
|
content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
this.column.TopLevelContainer.CreateProxy()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new ColumnTestContainer(0, ManiaAction.Key1)
|
new ColumnTestContainer(0, ManiaAction.Key1, true)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
new ColumnTestContainer(1, ManiaAction.Key2)
|
new ColumnTestContainer(1, ManiaAction.Key2, true)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
117
osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs
Normal file
117
osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// 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.Extensions.TypeExtensions;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Replays;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneOutOfOrderHits : RateAdjustedBeatmapTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestPreviousHitWindowDoesNotExtendPastNextObject()
|
||||||
|
{
|
||||||
|
var objects = new List<ManiaHitObject>();
|
||||||
|
var frames = new List<ReplayFrame>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
double time = 1000 + i * 100;
|
||||||
|
|
||||||
|
objects.Add(new Note { StartTime = time });
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
frames.Add(new ManiaReplayFrame(time + 10, ManiaAction.Key1));
|
||||||
|
frames.Add(new ManiaReplayFrame(time + 11));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performTest(objects, frames);
|
||||||
|
|
||||||
|
addJudgementAssert(objects[0], HitResult.Miss);
|
||||||
|
|
||||||
|
for (int i = 1; i < 7; i++)
|
||||||
|
{
|
||||||
|
addJudgementAssert(objects[i], HitResult.Perfect);
|
||||||
|
addJudgementOffsetAssert(objects[i], 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addJudgementAssert(ManiaHitObject hitObject, HitResult result)
|
||||||
|
{
|
||||||
|
AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judgement is {result}",
|
||||||
|
() => judgementResults.Single(r => r.HitObject == hitObject).Type == result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addJudgementOffsetAssert(ManiaHitObject hitObject, double offset)
|
||||||
|
{
|
||||||
|
AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judged at {offset}",
|
||||||
|
() => Precision.AlmostEquals(judgementResults.Single(r => r.HitObject == hitObject).TimeOffset, offset, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScoreAccessibleReplayPlayer currentPlayer;
|
||||||
|
private List<JudgementResult> judgementResults;
|
||||||
|
|
||||||
|
private void performTest(List<ManiaHitObject> hitObjects, List<ReplayFrame> frames)
|
||||||
|
{
|
||||||
|
AddStep("load player", () =>
|
||||||
|
{
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })
|
||||||
|
{
|
||||||
|
HitObjects = hitObjects,
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new ManiaRuleset().RulesetInfo
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Beatmap.Value.Beatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 0.1f });
|
||||||
|
|
||||||
|
var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });
|
||||||
|
|
||||||
|
p.OnLoadComplete += _ =>
|
||||||
|
{
|
||||||
|
p.ScoreProcessor.NewJudgement += result =>
|
||||||
|
{
|
||||||
|
if (currentPlayer == p) judgementResults.Add(result);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadScreen(currentPlayer = p);
|
||||||
|
judgementResults = new List<JudgementResult>();
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
|
||||||
|
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
|
||||||
|
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ScoreAccessibleReplayPlayer : ReplayPlayer
|
||||||
|
{
|
||||||
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
|
|
||||||
|
protected override bool PauseOnFocusLost => false;
|
||||||
|
|
||||||
|
public ScoreAccessibleReplayPlayer(Score score)
|
||||||
|
: base(score, false, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<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" />
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
@ -41,14 +40,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Note Count",
|
Name = @"Note Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
Content = notes.ToString(),
|
Content = notes.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Hold Note Count",
|
Name = @"Hold Note Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
Content = holdnotes.ToString(),
|
Content = holdnotes.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using osu.Game.Rulesets.Mania.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -167,8 +166,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
var positionData = original as IHasPosition;
|
var positionData = original as IHasPosition;
|
||||||
|
|
||||||
for (double time = original.StartTime; !Precision.DefinitelyBigger(time, generator.EndTime); time += generator.SegmentDuration)
|
for (int i = 0; i <= generator.SpanCount; i++)
|
||||||
{
|
{
|
||||||
|
double time = original.StartTime + generator.SegmentDuration * i;
|
||||||
|
|
||||||
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
||||||
computeDensity(time);
|
computeDensity(time);
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
public readonly double EndTime;
|
public readonly double EndTime;
|
||||||
public readonly double SegmentDuration;
|
public readonly double SegmentDuration;
|
||||||
|
public readonly int SpanCount;
|
||||||
private readonly int spanCount;
|
|
||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
|
|
||||||
@ -42,20 +41,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
var distanceData = hitObject as IHasDistance;
|
var distanceData = hitObject as IHasDistance;
|
||||||
var repeatsData = hitObject as IHasRepeats;
|
var repeatsData = hitObject as IHasRepeats;
|
||||||
|
|
||||||
spanCount = repeatsData?.SpanCount() ?? 1;
|
SpanCount = repeatsData?.SpanCount() ?? 1;
|
||||||
|
|
||||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
||||||
|
|
||||||
// The true distance, accounting for any repeats
|
// The true distance, accounting for any repeats
|
||||||
double distance = (distanceData?.Distance ?? 0) * spanCount;
|
double distance = (distanceData?.Distance ?? 0) * SpanCount;
|
||||||
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
||||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
EndTime = hitObject.StartTime + osuDuration;
|
EndTime = hitObject.StartTime + osuDuration;
|
||||||
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
|
SegmentDuration = (EndTime - HitObject.StartTime) / SpanCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Pattern> Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
@ -96,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spanCount > 1)
|
if (SpanCount > 1)
|
||||||
{
|
{
|
||||||
if (SegmentDuration <= 90)
|
if (SegmentDuration <= 90)
|
||||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||||
@ -104,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (SegmentDuration <= 120)
|
if (SegmentDuration <= 120)
|
||||||
{
|
{
|
||||||
convertType |= PatternType.ForceNotStack;
|
convertType |= PatternType.ForceNotStack;
|
||||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
return generateRandomNotes(HitObject.StartTime, SpanCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SegmentDuration <= 160)
|
if (SegmentDuration <= 160)
|
||||||
@ -117,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (duration >= 4000)
|
if (duration >= 4000)
|
||||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
||||||
|
|
||||||
if (SegmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
if (SegmentDuration > 400 && SpanCount < TotalColumns - 1 - RandomStart)
|
||||||
return generateTiledHoldNotes(HitObject.StartTime);
|
return generateTiledHoldNotes(HitObject.StartTime);
|
||||||
|
|
||||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||||
@ -251,7 +250,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
bool increasing = Random.NextDouble() > 0.5;
|
bool increasing = Random.NextDouble() > 0.5;
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, column, startTime, startTime);
|
addToPattern(pattern, column, startTime, startTime);
|
||||||
startTime += SegmentDuration;
|
startTime += SegmentDuration;
|
||||||
@ -302,7 +301,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
|
||||||
@ -393,7 +392,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
int columnRepeat = Math.Min(SpanCount, TotalColumns);
|
||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
@ -447,7 +446,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var rowPattern = new Pattern();
|
var rowPattern = new Pattern();
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
if (!(ignoreHead && startTime == HitObject.StartTime))
|
if (!(ignoreHead && startTime == HitObject.StartTime))
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
@ -35,7 +34,6 @@ using osu.Game.Screens.Ranking.Statistics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class ManiaRuleset : Ruleset, ILegacyRuleset
|
public class ManiaRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -126,6 +124,9 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Random))
|
if (mods.HasFlag(LegacyMods.Random))
|
||||||
yield return new ManiaModRandom();
|
yield return new ManiaModRandom();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Mirror))
|
||||||
|
yield return new ManiaModMirror();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override LegacyMods ConvertToLegacyMods(Mod[] mods)
|
public override LegacyMods ConvertToLegacyMods(Mod[] mods)
|
||||||
@ -175,6 +176,10 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
case ManiaModFadeIn _:
|
case ManiaModFadeIn _:
|
||||||
value |= LegacyMods.FadeIn;
|
value |= LegacyMods.FadeIn;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ManiaModMirror _:
|
||||||
|
value |= LegacyMods.Mirror;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,6 +331,16 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
Height = 250
|
Height = 250
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
new StatisticRow
|
||||||
|
{
|
||||||
|
Columns = new[]
|
||||||
|
{
|
||||||
|
new StatisticItem(string.Empty, new SimpleStatisticTable(3, new SimpleStatisticItem[]
|
||||||
|
{
|
||||||
|
new UnstableRate(score.HitEvents)
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (Tail.AllJudged)
|
if (Tail.AllJudged)
|
||||||
|
{
|
||||||
ApplyResult(r => r.Type = HitResult.Perfect);
|
ApplyResult(r => r.Type = HitResult.Perfect);
|
||||||
|
endHold();
|
||||||
|
}
|
||||||
|
|
||||||
if (Tail.Result.Type == HitResult.Miss)
|
if (Tail.Result.Type == HitResult.Miss)
|
||||||
HasBroken = true;
|
HasBroken = true;
|
||||||
@ -252,6 +255,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (action != Action.Value)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (CheckHittable?.Invoke(this, Time.Current) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
// The tail has a lenience applied to it which is factored into the miss window (i.e. the miss judgement will be delayed).
|
// The tail has a lenience applied to it which is factored into the miss window (i.e. the miss judgement will be delayed).
|
||||||
// But the hold cannot ever be started within the late-lenience window, so we should skip trying to begin the hold during that time.
|
// But the hold cannot ever be started within the late-lenience window, so we should skip trying to begin the hold during that time.
|
||||||
// Note: Unlike below, we use the tail's start time to determine the time offset.
|
// Note: Unlike below, we use the tail's start time to determine the time offset.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// 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;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -8,6 +9,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -34,6 +36,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this <see cref="DrawableManiaHitObject"/> can be hit, given a time value.
|
||||||
|
/// If non-null, judgements will be ignored whilst the function returns false.
|
||||||
|
/// </summary>
|
||||||
|
public Func<DrawableHitObject, double, bool> CheckHittable;
|
||||||
|
|
||||||
protected DrawableManiaHitObject(ManiaHitObject hitObject)
|
protected DrawableManiaHitObject(ManiaHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
@ -124,6 +132,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Causes this <see cref="DrawableManiaHitObject"/> to get missed, disregarding all conditions in implementations of <see cref="DrawableHitObject.CheckForResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
public void MissForcefully() => ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
|
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
|
||||||
|
@ -64,6 +64,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (action != Action.Value)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (CheckHittable?.Invoke(this, Time.Current) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
return UpdateResult(true);
|
return UpdateResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"RandomW": 3083084786,
|
||||||
|
"RandomX": 273326509,
|
||||||
|
"RandomY": 273553282,
|
||||||
|
"RandomZ": 2659838971,
|
||||||
|
"StartTime": 4836,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 4836,
|
||||||
|
"EndTime": 4836,
|
||||||
|
"Column": 0
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StackLeniency: 0.7
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
HPDrainRate:1
|
||||||
|
CircleSize:4
|
||||||
|
OverallDifficulty:1
|
||||||
|
ApproachRate:9
|
||||||
|
SliderMultiplier:2.5
|
||||||
|
SliderTickRate:0.5
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
34,431.654676258993,4,1,0,50,1,0
|
||||||
|
4782,-66.6666666666667,4,1,0,20,0,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
15,199,4836,22,0,L,1,46.8750017881394
|
46
osu.Game.Rulesets.Mania/Skinning/HitTargetInsetContainer.cs
Normal file
46
osu.Game.Rulesets.Mania/Skinning/HitTargetInsetContainer.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class HitTargetInsetContainer : Container
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
|
private float hitPosition;
|
||||||
|
|
||||||
|
public HitTargetInsetContainer()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChild = content = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
hitPosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? Stage.HIT_TARGET_POSITION;
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
content.Padding = direction.NewValue == ScrollingDirection.Up
|
||||||
|
? new MarginPadding { Top = hitPosition }
|
||||||
|
: new MarginPadding { Bottom = hitPosition };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
// 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;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -19,7 +21,14 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
private readonly IBindable<bool> isHitting = new Bindable<bool>();
|
private readonly IBindable<bool> isHitting = new Bindable<bool>();
|
||||||
|
|
||||||
private Drawable sprite;
|
[CanBeNull]
|
||||||
|
private Drawable bodySprite;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
private Drawable lightContainer;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
private Drawable light;
|
||||||
|
|
||||||
public LegacyBodyPiece()
|
public LegacyBodyPiece()
|
||||||
{
|
{
|
||||||
@ -32,7 +41,39 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
string imageName = GetColumnSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage)?.Value
|
string imageName = GetColumnSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage)?.Value
|
||||||
?? $"mania-note{FallbackColumnIndex}L";
|
?? $"mania-note{FallbackColumnIndex}L";
|
||||||
|
|
||||||
sprite = skin.GetAnimation(imageName, WrapMode.ClampToEdge, WrapMode.ClampToEdge, true, true).With(d =>
|
string lightImage = GetColumnSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.HoldNoteLightImage)?.Value
|
||||||
|
?? "lightingL";
|
||||||
|
|
||||||
|
float lightScale = GetColumnSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.HoldNoteLightScale)?.Value
|
||||||
|
?? 1;
|
||||||
|
|
||||||
|
// Create a temporary animation to retrieve the number of frames, in an effort to calculate the intended frame length.
|
||||||
|
// This animation is discarded and re-queried with the appropriate frame length afterwards.
|
||||||
|
var tmp = skin.GetAnimation(lightImage, true, false);
|
||||||
|
double frameLength = 0;
|
||||||
|
if (tmp is IFramedAnimation tmpAnimation && tmpAnimation.FrameCount > 0)
|
||||||
|
frameLength = Math.Max(1000 / 60.0, 170.0 / tmpAnimation.FrameCount);
|
||||||
|
|
||||||
|
light = skin.GetAnimation(lightImage, true, true, frameLength: frameLength).With(d =>
|
||||||
|
{
|
||||||
|
if (d == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d.Origin = Anchor.Centre;
|
||||||
|
d.Blending = BlendingParameters.Additive;
|
||||||
|
d.Scale = new Vector2(lightScale);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (light != null)
|
||||||
|
{
|
||||||
|
lightContainer = new HitTargetInsetContainer
|
||||||
|
{
|
||||||
|
Alpha = 0,
|
||||||
|
Child = light
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bodySprite = skin.GetAnimation(imageName, WrapMode.ClampToEdge, WrapMode.ClampToEdge, true, true).With(d =>
|
||||||
{
|
{
|
||||||
if (d == null)
|
if (d == null)
|
||||||
return;
|
return;
|
||||||
@ -47,8 +88,8 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
// Todo: Wrap
|
// Todo: Wrap
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sprite != null)
|
if (bodySprite != null)
|
||||||
InternalChild = sprite;
|
InternalChild = bodySprite;
|
||||||
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
direction.BindValueChanged(onDirectionChanged, true);
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
@ -60,28 +101,68 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
|
|
||||||
private void onIsHittingChanged(ValueChangedEvent<bool> isHitting)
|
private void onIsHittingChanged(ValueChangedEvent<bool> isHitting)
|
||||||
{
|
{
|
||||||
if (!(sprite is TextureAnimation animation))
|
if (bodySprite is TextureAnimation bodyAnimation)
|
||||||
|
{
|
||||||
|
bodyAnimation.GotoFrame(0);
|
||||||
|
bodyAnimation.IsPlaying = isHitting.NewValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lightContainer == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
animation.GotoFrame(0);
|
if (isHitting.NewValue)
|
||||||
animation.IsPlaying = isHitting.NewValue;
|
{
|
||||||
|
// Clear the fade out and, more importantly, the removal.
|
||||||
|
lightContainer.ClearTransforms();
|
||||||
|
|
||||||
|
// Only add the container if the removal has taken place.
|
||||||
|
if (lightContainer.Parent == null)
|
||||||
|
Column.TopLevelContainer.Add(lightContainer);
|
||||||
|
|
||||||
|
// The light must be seeked only after being loaded, otherwise a nullref occurs (https://github.com/ppy/osu-framework/issues/3847).
|
||||||
|
if (light is TextureAnimation lightAnimation)
|
||||||
|
lightAnimation.GotoFrame(0);
|
||||||
|
|
||||||
|
lightContainer.FadeIn(80);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lightContainer.FadeOut(120)
|
||||||
|
.OnComplete(d => Column.TopLevelContainer.Remove(d));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
{
|
{
|
||||||
if (sprite == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (direction.NewValue == ScrollingDirection.Up)
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
{
|
{
|
||||||
sprite.Origin = Anchor.BottomCentre;
|
if (bodySprite != null)
|
||||||
sprite.Scale = new Vector2(1, -1);
|
{
|
||||||
|
bodySprite.Origin = Anchor.BottomCentre;
|
||||||
|
bodySprite.Scale = new Vector2(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (light != null)
|
||||||
|
light.Anchor = Anchor.TopCentre;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprite.Origin = Anchor.TopCentre;
|
if (bodySprite != null)
|
||||||
sprite.Scale = Vector2.One;
|
{
|
||||||
|
bodySprite.Origin = Anchor.TopCentre;
|
||||||
|
bodySprite.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (light != null)
|
||||||
|
light.Anchor = Anchor.BottomCentre;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
lightContainer?.Expire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Colour = lightColour,
|
Colour = LegacyColourCompatibility.DisallowZeroAlpha(lightColour),
|
||||||
Texture = skin.GetTexture(lightImage),
|
Texture = skin.GetTexture(lightImage),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Width = 1,
|
Width = 1,
|
||||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 1,
|
Height = 1,
|
||||||
Colour = lineColour,
|
Colour = LegacyColourCompatibility.DisallowZeroAlpha(lineColour),
|
||||||
Alpha = showJudgementLine ? 0.9f : 0
|
Alpha = showJudgementLine ? 0.9f : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,9 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
direction.BindValueChanged(onDirectionChanged, true);
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
|
||||||
|
if (GetColumnSkinConfig<bool>(skin, LegacyManiaSkinConfigurationLookups.KeysUnderNotes)?.Value ?? false)
|
||||||
|
Column.UnderlayElements.Add(CreateProxy());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
// 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 osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -108,75 +106,43 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
LegacyColourCompatibility.ApplyWithDoubledAlpha(new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both
|
||||||
Child = new Box
|
}, backgroundColour),
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = backgroundColour
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new HitTargetInsetContainer
|
new HitTargetInsetContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Box
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = leftLineWidth,
|
Width = leftLineWidth,
|
||||||
Scale = new Vector2(0.740f, 1),
|
Scale = new Vector2(0.740f, 1),
|
||||||
Colour = lineColour,
|
Alpha = hasLeftLine ? 1 : 0,
|
||||||
Alpha = hasLeftLine ? 1 : 0
|
Child = LegacyColourCompatibility.ApplyWithDoubledAlpha(new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}, lineColour)
|
||||||
},
|
},
|
||||||
new Box
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = rightLineWidth,
|
Width = rightLineWidth,
|
||||||
Scale = new Vector2(0.740f, 1),
|
Scale = new Vector2(0.740f, 1),
|
||||||
Colour = lineColour,
|
Alpha = hasRightLine ? 1 : 0,
|
||||||
Alpha = hasRightLine ? 1 : 0
|
Child = LegacyColourCompatibility.ApplyWithDoubledAlpha(new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}, lineColour)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HitTargetInsetContainer : Container
|
|
||||||
{
|
|
||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
|
||||||
private readonly Container content;
|
|
||||||
|
|
||||||
private float hitPosition;
|
|
||||||
|
|
||||||
public HitTargetInsetContainer()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
InternalChild = content = new Container { RelativeSizeAxes = Axes.Both };
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
|
||||||
{
|
|
||||||
hitPosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? Stage.HIT_TARGET_POSITION;
|
|
||||||
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
|
||||||
direction.BindValueChanged(onDirectionChanged, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
|
||||||
{
|
|
||||||
content.Padding = direction.NewValue == ScrollingDirection.Up
|
|
||||||
? new MarginPadding { Top = hitPosition }
|
|
||||||
: new MarginPadding { Bottom = hitPosition };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
@ -36,6 +37,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public readonly ColumnHitObjectArea HitObjectArea;
|
public readonly ColumnHitObjectArea HitObjectArea;
|
||||||
internal readonly Container TopLevelContainer;
|
internal readonly Container TopLevelContainer;
|
||||||
private readonly DrawablePool<PoolableHitExplosion> hitExplosionPool;
|
private readonly DrawablePool<PoolableHitExplosion> hitExplosionPool;
|
||||||
|
private readonly OrderedHitPolicy hitPolicy;
|
||||||
|
|
||||||
public Container UnderlayElements => HitObjectArea.UnderlayElements;
|
public Container UnderlayElements => HitObjectArea.UnderlayElements;
|
||||||
|
|
||||||
@ -65,6 +67,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
||||||
|
|
||||||
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
|
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +94,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
hitObject.AccentColour.Value = AccentColour;
|
hitObject.AccentColour.Value = AccentColour;
|
||||||
hitObject.OnNewResult += OnNewResult;
|
hitObject.OnNewResult += OnNewResult;
|
||||||
|
|
||||||
|
DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)hitObject;
|
||||||
|
maniaObject.CheckHittable = hitPolicy.IsHittable;
|
||||||
|
|
||||||
HitObjectContainer.Add(hitObject);
|
HitObjectContainer.Add(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +111,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
|
if (result.IsHit)
|
||||||
|
hitPolicy.HandleHit(judgedObject);
|
||||||
|
|
||||||
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
|
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
78
osu.Game.Rulesets.Mania/UI/OrderedHitPolicy.cs
Normal file
78
osu.Game.Rulesets.Mania/UI/OrderedHitPolicy.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that only the most recent <see cref="HitObject"/> is hittable, affectionately known as "note lock".
|
||||||
|
/// </summary>
|
||||||
|
public class OrderedHitPolicy
|
||||||
|
{
|
||||||
|
private readonly HitObjectContainer hitObjectContainer;
|
||||||
|
|
||||||
|
public OrderedHitPolicy(HitObjectContainer hitObjectContainer)
|
||||||
|
{
|
||||||
|
this.hitObjectContainer = hitObjectContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a <see cref="DrawableHitObject"/> can be hit at a point in time.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Only the most recent <see cref="DrawableHitObject"/> can be hit, a previous hitobject's window cannot extend past the next one.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to check.</param>
|
||||||
|
/// <param name="time">The time to check.</param>
|
||||||
|
/// <returns>Whether <paramref name="hitObject"/> can be hit at the given <paramref name="time"/>.</returns>
|
||||||
|
public bool IsHittable(DrawableHitObject hitObject, double time)
|
||||||
|
{
|
||||||
|
var nextObject = hitObjectContainer.AliveObjects.GetNext(hitObject);
|
||||||
|
return nextObject == null || time < nextObject.HitObject.StartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles a <see cref="HitObject"/> being hit to potentially miss all earlier <see cref="HitObject"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> that was hit.</param>
|
||||||
|
public void HandleHit(DrawableHitObject hitObject)
|
||||||
|
{
|
||||||
|
if (!IsHittable(hitObject, hitObject.HitObject.StartTime + hitObject.Result.TimeOffset))
|
||||||
|
throw new InvalidOperationException($"A {hitObject} was hit before it became hittable!");
|
||||||
|
|
||||||
|
foreach (var obj in enumerateHitObjectsUpTo(hitObject.HitObject.StartTime))
|
||||||
|
{
|
||||||
|
if (obj.Judged)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
((DrawableManiaHitObject)obj).MissForcefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<DrawableHitObject> enumerateHitObjectsUpTo(double targetTime)
|
||||||
|
{
|
||||||
|
foreach (var obj in hitObjectContainer.AliveObjects)
|
||||||
|
{
|
||||||
|
if (obj.HitObject.GetEndTime() >= targetTime)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
yield return obj;
|
||||||
|
|
||||||
|
foreach (var nestedObj in obj.NestedHitObjects)
|
||||||
|
{
|
||||||
|
if (nestedObj.HitObject.GetEndTime() >= targetTime)
|
||||||
|
break;
|
||||||
|
|
||||||
|
yield return nestedObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -22,7 +22,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|||||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Storyboards;
|
using osu.Game.Storyboards;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
@ -32,8 +31,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private AudioManager audioManager { get; set; }
|
private AudioManager audioManager { get; set; }
|
||||||
|
|
||||||
private TrackVirtualManual track;
|
|
||||||
|
|
||||||
protected override bool Autoplay => autoplay;
|
protected override bool Autoplay => autoplay;
|
||||||
private bool autoplay;
|
private bool autoplay;
|
||||||
|
|
||||||
@ -44,11 +41,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
private const double fade_in_modifier = -1200;
|
private const double fade_in_modifier = -1200;
|
||||||
|
|
||||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||||
{
|
=> new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
|
||||||
track = (TrackVirtualManual)working.Track;
|
|
||||||
return working;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetConfigCache configCache)
|
private void load(RulesetConfigCache configCache)
|
||||||
@ -72,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
AddStep("enable autoplay", () => autoplay = true);
|
AddStep("enable autoplay", () => autoplay = true);
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||||
|
|
||||||
double startTime = hitObjects[sliderIndex].StartTime;
|
double startTime = hitObjects[sliderIndex].StartTime;
|
||||||
retrieveDrawableSlider(sliderIndex);
|
retrieveDrawableSlider(sliderIndex);
|
||||||
@ -97,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
AddStep("have autoplay", () => autoplay = true);
|
AddStep("have autoplay", () => autoplay = true);
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||||
|
|
||||||
double startTime = hitObjects[sliderIndex].StartTime;
|
double startTime = hitObjects[sliderIndex].StartTime;
|
||||||
retrieveDrawableSlider(sliderIndex);
|
retrieveDrawableSlider(sliderIndex);
|
||||||
@ -201,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
private void addSeekStep(double time)
|
private void addSeekStep(double time)
|
||||||
{
|
{
|
||||||
AddStep($"seek to {time}", () => track.Seek(time));
|
AddStep($"seek to {time}", () => MusicController.SeekTo(time));
|
||||||
|
|
||||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
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 osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
@ -62,7 +63,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
drawableSpinner = new TestDrawableSpinner(spinner, auto)
|
drawableSpinner = new TestDrawableSpinner(spinner, auto)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Depth = depthIndex++
|
Depth = depthIndex++,
|
||||||
|
Scale = new Vector2(0.75f)
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
|
@ -25,7 +25,6 @@ using osu.Game.Scoring;
|
|||||||
using osu.Game.Storyboards;
|
using osu.Game.Storyboards;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
@ -34,18 +33,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private AudioManager audioManager { get; set; }
|
private AudioManager audioManager { get; set; }
|
||||||
|
|
||||||
private TrackVirtualManual track;
|
|
||||||
|
|
||||||
protected override bool Autoplay => true;
|
protected override bool Autoplay => true;
|
||||||
|
|
||||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer();
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer();
|
||||||
|
|
||||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||||
{
|
=> new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
|
||||||
track = (TrackVirtualManual)working.Track;
|
|
||||||
return working;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DrawableSpinner drawableSpinner;
|
private DrawableSpinner drawableSpinner;
|
||||||
private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType<SpriteIcon>().Single();
|
private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType<SpriteIcon>().Single();
|
||||||
@ -55,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
|
|
||||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||||
AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First());
|
AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addSeekStep(0);
|
addSeekStep(0);
|
||||||
|
|
||||||
AddStep("adjust track rate", () => track.AddAdjustment(AdjustableProperty.Tempo, new BindableDouble(rate)));
|
AddStep("adjust track rate", () => MusicController.CurrentTrack.AddAdjustment(AdjustableProperty.Tempo, new BindableDouble(rate)));
|
||||||
// autoplay replay frames use track time;
|
// autoplay replay frames use track time;
|
||||||
// if a spin takes 1000ms in track time and we're playing with a 2x rate adjustment, the spin will take 500ms of *real* time.
|
// if a spin takes 1000ms in track time and we're playing with a 2x rate adjustment, the spin will take 500ms of *real* time.
|
||||||
// therefore we need to apply the rate adjustment to the replay itself to change from track time to real time,
|
// therefore we need to apply the rate adjustment to the replay itself to change from track time to real time,
|
||||||
@ -230,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
private void addSeekStep(double time)
|
private void addSeekStep(double time)
|
||||||
{
|
{
|
||||||
AddStep($"seek to {time}", () => track.Seek(time));
|
AddStep($"seek to {time}", () => MusicController.SeekTo(time));
|
||||||
|
|
||||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||||
}
|
}
|
||||||
|
@ -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.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<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" />
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
@ -23,19 +22,19 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
{
|
{
|
||||||
Name = @"Circle Count",
|
Name = @"Circle Count",
|
||||||
Content = circles.ToString(),
|
Content = circles.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Slider Count",
|
Name = @"Slider Count",
|
||||||
Content = sliders.ToString(),
|
Content = sliders.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Spinner Count",
|
Name = @"Spinner Count",
|
||||||
Content = spinners.ToString(),
|
Content = spinners.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
protected override float SamplePlaybackPosition => HitObject.X / OsuPlayfield.BASE_SIZE.X;
|
protected override float SamplePlaybackPosition => HitObject.X / OsuPlayfield.BASE_SIZE.X;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableOsuHitObject"/> can be hit.
|
/// Whether this <see cref="DrawableOsuHitObject"/> can be hit, given a time value.
|
||||||
/// If non-null, judgements will be ignored (resulting in a shake) whilst the function returns false.
|
/// If non-null, judgements will be ignored (resulting in a shake) whilst the function returns false.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<DrawableHitObject, double, bool> CheckHittable;
|
public Func<DrawableHitObject, double, bool> CheckHittable;
|
||||||
|
@ -30,14 +30,12 @@ using osu.Game.Scoring;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Statistics;
|
using osu.Game.Rulesets.Osu.Statistics;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class OsuRuleset : Ruleset, ILegacyRuleset
|
public class OsuRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
||||||
@ -193,30 +191,46 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo);
|
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo);
|
||||||
|
|
||||||
public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => new[]
|
public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap)
|
||||||
{
|
{
|
||||||
new StatisticRow
|
var timedHitEvents = score.HitEvents.Where(e => e.HitObject is HitCircle && !(e.HitObject is SliderTailCircle)).ToList();
|
||||||
|
|
||||||
|
return new[]
|
||||||
{
|
{
|
||||||
Columns = new[]
|
new StatisticRow
|
||||||
{
|
{
|
||||||
new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(score.HitEvents.Where(e => e.HitObject is HitCircle && !(e.HitObject is SliderTailCircle)).ToList())
|
Columns = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new StatisticItem("Timing Distribution",
|
||||||
Height = 250
|
new HitEventTimingDistributionGraph(timedHitEvents)
|
||||||
}),
|
{
|
||||||
}
|
RelativeSizeAxes = Axes.X,
|
||||||
},
|
Height = 250
|
||||||
new StatisticRow
|
}),
|
||||||
{
|
}
|
||||||
Columns = new[]
|
},
|
||||||
|
new StatisticRow
|
||||||
{
|
{
|
||||||
new StatisticItem("Accuracy Heatmap", new AccuracyHeatmap(score, playableBeatmap)
|
Columns = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new StatisticItem("Accuracy Heatmap", new AccuracyHeatmap(score, playableBeatmap)
|
||||||
Height = 250
|
{
|
||||||
}),
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 250
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new StatisticRow
|
||||||
|
{
|
||||||
|
Columns = new[]
|
||||||
|
{
|
||||||
|
new StatisticItem(string.Empty, new SimpleStatisticTable(3, new SimpleStatisticItem[]
|
||||||
|
{
|
||||||
|
new UnstableRate(timedHitEvents)
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,8 +154,12 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
// The startPosition for the slider should not be its .Position, but the point on the circle whose tangent crosses the current cursor position
|
// The startPosition for the slider should not be its .Position, but the point on the circle whose tangent crosses the current cursor position
|
||||||
// We also modify spinnerDirection so it spins in the direction it enters the spin circle, to make a smooth transition.
|
// We also modify spinnerDirection so it spins in the direction it enters the spin circle, to make a smooth transition.
|
||||||
// TODO: Shouldn't the spinner always spin in the same direction?
|
// TODO: Shouldn't the spinner always spin in the same direction?
|
||||||
if (h is Spinner)
|
if (h is Spinner spinner)
|
||||||
{
|
{
|
||||||
|
// spinners with 0 spins required will auto-complete - don't bother
|
||||||
|
if (spinner.SpinsRequired == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
calcSpinnerStartPosAndDirection(((OsuReplayFrame)Frames[^1]).Position, out startPosition, out spinnerDirection);
|
calcSpinnerStartPosAndDirection(((OsuReplayFrame)Frames[^1]).Position, out startPosition, out spinnerDirection);
|
||||||
|
|
||||||
Vector2 spinCentreOffset = SPINNER_CENTRE - ((OsuReplayFrame)Frames[^1]).Position;
|
Vector2 spinCentreOffset = SPINNER_CENTRE - ((OsuReplayFrame)Frames[^1]).Position;
|
||||||
|
@ -59,7 +59,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
hitCircleSprite = new Sprite
|
hitCircleSprite = new Sprite
|
||||||
{
|
{
|
||||||
Texture = getTextureWithFallback(string.Empty),
|
Texture = getTextureWithFallback(string.Empty),
|
||||||
Colour = drawableObject.AccentColour.Value,
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
@ -107,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
state.BindValueChanged(updateState, true);
|
state.BindValueChanged(updateState, true);
|
||||||
accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true);
|
accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
||||||
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +22,11 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
private DrawableSpinner drawableSpinner;
|
private DrawableSpinner drawableSpinner;
|
||||||
private Sprite disc;
|
private Sprite disc;
|
||||||
|
private Sprite metreSprite;
|
||||||
private Container metre;
|
private Container metre;
|
||||||
|
|
||||||
private const float background_y_offset = 20;
|
|
||||||
|
|
||||||
private const float sprite_scale = 1 / 1.6f;
|
private const float sprite_scale = 1 / 1.6f;
|
||||||
|
private const float final_metre_height = 692 * sprite_scale;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource source, DrawableHitObject drawableObject)
|
private void load(ISkinSource source, DrawableHitObject drawableObject)
|
||||||
@ -35,50 +35,58 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChild = new Container
|
||||||
{
|
{
|
||||||
new Sprite
|
// the old-style spinner relied heavily on absolute screen-space coordinate values.
|
||||||
|
// wrap everything in a container simulating absolute coords to preserve alignment
|
||||||
|
// as there are skins that depend on it.
|
||||||
|
Width = 640,
|
||||||
|
Height = 480,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
new Sprite
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Texture = source.GetTexture("spinner-background"),
|
|
||||||
Y = background_y_offset,
|
|
||||||
Scale = new Vector2(sprite_scale)
|
|
||||||
},
|
|
||||||
disc = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Texture = source.GetTexture("spinner-circle"),
|
|
||||||
Scale = new Vector2(sprite_scale)
|
|
||||||
},
|
|
||||||
metre = new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Y = background_y_offset,
|
|
||||||
Masking = true,
|
|
||||||
Child = new Sprite
|
|
||||||
{
|
{
|
||||||
Texture = source.GetTexture("spinner-metre"),
|
Anchor = Anchor.Centre,
|
||||||
Anchor = Anchor.BottomCentre,
|
Origin = Anchor.Centre,
|
||||||
Origin = Anchor.BottomCentre,
|
Texture = source.GetTexture("spinner-background"),
|
||||||
|
Scale = new Vector2(sprite_scale)
|
||||||
},
|
},
|
||||||
Scale = new Vector2(0.625f)
|
disc = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Texture = source.GetTexture("spinner-circle"),
|
||||||
|
Scale = new Vector2(sprite_scale)
|
||||||
|
},
|
||||||
|
metre = new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
// this anchor makes no sense, but that's what stable uses.
|
||||||
|
Anchor = Anchor.TopLeft,
|
||||||
|
Origin = Anchor.TopLeft,
|
||||||
|
// adjustment for stable (metre has additional offset)
|
||||||
|
Margin = new MarginPadding { Top = 20 },
|
||||||
|
Masking = true,
|
||||||
|
Child = metreSprite = new Sprite
|
||||||
|
{
|
||||||
|
Texture = source.GetTexture("spinner-metre"),
|
||||||
|
Anchor = Anchor.TopLeft,
|
||||||
|
Origin = Anchor.TopLeft,
|
||||||
|
Scale = new Vector2(0.625f)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 metreFinalSize;
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
this.FadeOut();
|
this.FadeOut();
|
||||||
drawableSpinner.State.BindValueChanged(updateStateTransforms, true);
|
drawableSpinner.State.BindValueChanged(updateStateTransforms, true);
|
||||||
|
|
||||||
metreFinalSize = metre.Size = metre.Child.Size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStateTransforms(ValueChangedEvent<ArmedState> state)
|
private void updateStateTransforms(ValueChangedEvent<ArmedState> state)
|
||||||
@ -93,7 +101,16 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
disc.Rotation = drawableSpinner.RotationTracker.Rotation;
|
disc.Rotation = drawableSpinner.RotationTracker.Rotation;
|
||||||
metre.Height = getMetreHeight(drawableSpinner.Progress);
|
|
||||||
|
// careful: need to call this exactly once for all calculations in a frame
|
||||||
|
// as the function has a random factor in it
|
||||||
|
var metreHeight = getMetreHeight(drawableSpinner.Progress);
|
||||||
|
|
||||||
|
// hack to make the metre blink up from below than down from above.
|
||||||
|
// move down the container to be able to apply masking for the metre,
|
||||||
|
// and then move the sprite back up the same amount to keep its position absolute.
|
||||||
|
metre.Y = final_metre_height - metreHeight;
|
||||||
|
metreSprite.Y = -metre.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int total_bars = 10;
|
private const int total_bars = 10;
|
||||||
@ -108,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
if (RNG.NextBool(((int)progress % 10) / 10f))
|
if (RNG.NextBool(((int)progress % 10) / 10f))
|
||||||
barCount++;
|
barCount++;
|
||||||
|
|
||||||
return (float)barCount / total_bars * metreFinalSize.Y;
|
return (float)barCount / total_bars * final_metre_height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin, DrawableHitObject drawableObject)
|
private void load(ISkinSource skin, DrawableHitObject drawableObject)
|
||||||
{
|
{
|
||||||
animationContent.Colour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBall)?.Value ?? Color4.White;
|
var ballColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBall)?.Value ?? Color4.White;
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
@ -39,11 +39,11 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
Texture = skin.GetTexture("sliderb-nd"),
|
Texture = skin.GetTexture("sliderb-nd"),
|
||||||
Colour = new Color4(5, 5, 5, 255),
|
Colour = new Color4(5, 5, 5, 255),
|
||||||
},
|
},
|
||||||
animationContent.With(d =>
|
LegacyColourCompatibility.ApplyWithDoubledAlpha(animationContent.With(d =>
|
||||||
{
|
{
|
||||||
d.Anchor = Anchor.Centre;
|
d.Anchor = Anchor.Centre;
|
||||||
d.Origin = Anchor.Centre;
|
d.Origin = Anchor.Centre;
|
||||||
}),
|
}), ballColour),
|
||||||
layerSpec = new Sprite
|
layerSpec = new Sprite
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
|
@ -18,6 +18,10 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
||||||
|
|
||||||
|
protected new float CalculatedBorderPortion
|
||||||
|
// Roughly matches osu!stable's slider border portions.
|
||||||
|
=> base.CalculatedBorderPortion * 0.77f;
|
||||||
|
|
||||||
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
||||||
|
|
||||||
protected override Color4 ColourAt(float position)
|
protected override Color4 ColourAt(float position)
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Taiko.Tests
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||||
|
@ -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.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<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" />
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
@ -22,20 +21,20 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Hit Count",
|
Name = @"Hit Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
Content = hits.ToString(),
|
Content = hits.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Drumroll Count",
|
Name = @"Drumroll Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
Content = drumrolls.ToString(),
|
Content = drumrolls.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Swell Count",
|
Name = @"Swell Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners),
|
||||||
Content = swells.ToString(),
|
Content = swells.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
private void updateAccentColour()
|
private void updateAccentColour()
|
||||||
{
|
{
|
||||||
backgroundLayer.Colour = accentColour;
|
backgroundLayer.Colour = LegacyColourCompatibility.DisallowZeroAlpha(accentColour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,9 +76,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
private void updateAccentColour()
|
private void updateAccentColour()
|
||||||
{
|
{
|
||||||
headCircle.AccentColour = accentColour;
|
var colour = LegacyColourCompatibility.DisallowZeroAlpha(accentColour);
|
||||||
body.Colour = accentColour;
|
|
||||||
end.Colour = accentColour;
|
headCircle.AccentColour = colour;
|
||||||
|
body.Colour = colour;
|
||||||
|
end.Colour = colour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Skinning
|
namespace osu.Game.Rulesets.Taiko.Skinning
|
||||||
@ -18,9 +19,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
AccentColour = component == TaikoSkinComponents.CentreHit
|
AccentColour = LegacyColourCompatibility.DisallowZeroAlpha(
|
||||||
? new Color4(235, 69, 44, 255)
|
component == TaikoSkinComponents.CentreHit
|
||||||
: new Color4(67, 142, 172, 255);
|
? new Color4(235, 69, 44, 255)
|
||||||
|
: new Color4(67, 142, 172, 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ using osu.Game.Rulesets.Taiko.Scoring;
|
|||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Taiko.Edit;
|
using osu.Game.Rulesets.Taiko.Edit;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
@ -32,7 +31,6 @@ using osu.Game.Skinning;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class TaikoRuleset : Ruleset, ILegacyRuleset
|
public class TaikoRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
||||||
@ -161,19 +159,34 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame();
|
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame();
|
||||||
|
|
||||||
public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => new[]
|
public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap)
|
||||||
{
|
{
|
||||||
new StatisticRow
|
var timedHitEvents = score.HitEvents.Where(e => e.HitObject is Hit).ToList();
|
||||||
|
|
||||||
|
return new[]
|
||||||
{
|
{
|
||||||
Columns = new[]
|
new StatisticRow
|
||||||
{
|
{
|
||||||
new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(score.HitEvents.Where(e => e.HitObject is Hit).ToList())
|
Columns = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(timedHitEvents)
|
||||||
Height = 250
|
{
|
||||||
}),
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 250
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new StatisticRow
|
||||||
|
{
|
||||||
|
Columns = new[]
|
||||||
|
{
|
||||||
|
new StatisticItem(string.Empty, new SimpleStatisticTable(3, new SimpleStatisticItem[]
|
||||||
|
{
|
||||||
|
new UnstableRate(timedHitEvents)
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
osu.Game.Tests/Beatmaps/BeatmapDifficultyManagerTest.cs
Normal file
32
osu.Game.Tests/Beatmaps/BeatmapDifficultyManagerTest.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Beatmaps
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BeatmapDifficultyManagerTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestKeyEqualsWithDifferentModInstances()
|
||||||
|
{
|
||||||
|
var key1 = new BeatmapDifficultyManager.DifficultyCacheLookup(1234, 0, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
var key2 = new BeatmapDifficultyManager.DifficultyCacheLookup(1234, 0, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
|
||||||
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeyEqualsWithDifferentModOrder()
|
||||||
|
{
|
||||||
|
var key1 = new BeatmapDifficultyManager.DifficultyCacheLookup(1234, 0, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
var key2 = new BeatmapDifficultyManager.DifficultyCacheLookup(1234, 0, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
||||||
|
|
||||||
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ using System.Text;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
@ -19,6 +20,7 @@ using osu.Game.Rulesets.Catch;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Taiko;
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.Formats
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
@ -26,18 +28,33 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LegacyBeatmapEncoderTest
|
public class LegacyBeatmapEncoderTest
|
||||||
{
|
{
|
||||||
private static IEnumerable<string> allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
private static readonly DllResourceStore beatmaps_resource_store = TestResources.GetStore();
|
||||||
|
|
||||||
|
private static IEnumerable<string> allBeatmaps = beatmaps_resource_store.GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
||||||
|
|
||||||
[TestCaseSource(nameof(allBeatmaps))]
|
[TestCaseSource(nameof(allBeatmaps))]
|
||||||
public void TestEncodeDecodeStability(string name)
|
public void TestEncodeDecodeStability(string name)
|
||||||
{
|
{
|
||||||
var decoded = decodeFromLegacy(TestResources.GetStore().GetStream(name));
|
var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name);
|
||||||
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded));
|
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name);
|
||||||
|
|
||||||
sort(decoded);
|
sort(decoded.beatmap);
|
||||||
sort(decodedAfterEncode);
|
sort(decodedAfterEncode.beatmap);
|
||||||
|
|
||||||
Assert.That(decodedAfterEncode.Serialize(), Is.EqualTo(decoded.Serialize()));
|
Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(decoded.beatmap.Serialize()));
|
||||||
|
Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b)
|
||||||
|
{
|
||||||
|
// equal to null, no need to SequenceEqual
|
||||||
|
if (a.ComboColours == null && b.ComboColours == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (a.ComboColours == null || b.ComboColours == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return a.ComboColours.SequenceEqual(b.ComboColours);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sort(IBeatmap beatmap)
|
private void sort(IBeatmap beatmap)
|
||||||
@ -50,18 +67,31 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap decodeFromLegacy(Stream stream)
|
private (IBeatmap beatmap, TestLegacySkin beatmapSkin) decodeFromLegacy(Stream stream, string name)
|
||||||
{
|
{
|
||||||
using (var reader = new LineBufferedReader(stream))
|
using (var reader = new LineBufferedReader(stream))
|
||||||
return convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader));
|
{
|
||||||
|
var beatmap = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader);
|
||||||
|
var beatmapSkin = new TestLegacySkin(beatmaps_resource_store, name);
|
||||||
|
return (convert(beatmap), beatmapSkin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream encodeToLegacy(IBeatmap beatmap)
|
private class TestLegacySkin : LegacySkin
|
||||||
{
|
{
|
||||||
|
public TestLegacySkin(IResourceStore<byte[]> storage, string fileName)
|
||||||
|
: base(new SkinInfo { Name = "Test Skin", Creator = "Craftplacer" }, storage, null, fileName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap)
|
||||||
|
{
|
||||||
|
var (beatmap, beatmapSkin) = fullBeatmap;
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
|
|
||||||
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
new LegacyBeatmapEncoder(beatmap).Encode(writer);
|
new LegacyBeatmapEncoder(beatmap, beatmapSkin).Encode(writer);
|
||||||
|
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
@ -106,7 +136,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
|
|
||||||
protected override Texture GetBackground() => throw new NotImplementedException();
|
protected override Texture GetBackground() => throw new NotImplementedException();
|
||||||
|
|
||||||
protected override Track GetTrack() => throw new NotImplementedException();
|
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
70
osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs
Normal file
70
osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Scoring.Legacy;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class LegacyScoreDecoderTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestDecodeManiaReplay()
|
||||||
|
{
|
||||||
|
var decoder = new TestLegacyScoreDecoder();
|
||||||
|
|
||||||
|
using (var resourceStream = TestResources.OpenResource("Replays/mania-replay.osr"))
|
||||||
|
{
|
||||||
|
var score = decoder.Parse(resourceStream);
|
||||||
|
|
||||||
|
Assert.AreEqual(3, score.ScoreInfo.Ruleset.ID);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.Great]);
|
||||||
|
Assert.AreEqual(1, score.ScoreInfo.Statistics[HitResult.Good]);
|
||||||
|
|
||||||
|
Assert.AreEqual(829_931, score.ScoreInfo.TotalScore);
|
||||||
|
Assert.AreEqual(3, score.ScoreInfo.MaxCombo);
|
||||||
|
Assert.IsTrue(Precision.AlmostEquals(0.8889, score.ScoreInfo.Accuracy, 0.0001));
|
||||||
|
Assert.AreEqual(ScoreRank.B, score.ScoreInfo.Rank);
|
||||||
|
|
||||||
|
Assert.That(score.Replay.Frames, Is.Not.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestLegacyScoreDecoder : LegacyScoreDecoder
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<int, Ruleset> rulesets = new Ruleset[]
|
||||||
|
{
|
||||||
|
new OsuRuleset(),
|
||||||
|
new TaikoRuleset(),
|
||||||
|
new CatchRuleset(),
|
||||||
|
new ManiaRuleset()
|
||||||
|
}.ToDictionary(ruleset => ((ILegacyRuleset)ruleset).LegacyID);
|
||||||
|
|
||||||
|
protected override Ruleset GetRuleset(int rulesetId) => rulesets[rulesetId];
|
||||||
|
|
||||||
|
protected override WorkingBeatmap GetBeatmap(string md5Hash) => new TestWorkingBeatmap(new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
{
|
||||||
|
MD5Hash = md5Hash,
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
BaseDifficulty = new BeatmapDifficulty()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,8 +15,10 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
using osu.Game.Users;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using SharpCompress.Archives.Zip;
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
@ -32,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportWhenClosed()
|
public async Task TestImportWhenClosed()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenClosed)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -49,7 +51,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDelete()
|
public async Task TestImportThenDelete()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDelete)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -70,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenImport()
|
public async Task TestImportThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -96,7 +98,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithReZip()
|
public async Task TestImportThenImportWithReZip()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithReZip)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -154,7 +156,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithChangedFile()
|
public async Task TestImportThenImportWithChangedFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithChangedFile)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -205,7 +207,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithDifferentFilename()
|
public async Task TestImportThenImportWithDifferentFilename()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithDifferentFilename)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -257,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportCorruptThenImport()
|
public async Task TestImportCorruptThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportCorruptThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -299,7 +301,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestRollbackOnFailure()
|
public async Task TestRollbackOnFailure()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestRollbackOnFailure)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -376,7 +378,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDeleteThenImport()
|
public async Task TestImportThenDeleteThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDeleteThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -404,7 +406,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"{nameof(TestImportThenDeleteThenImportWithOnlineIDMismatch)}-{set}"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(set.ToString()))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -438,7 +440,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportWithDuplicateBeatmapIDs()
|
public async Task TestImportWithDuplicateBeatmapIDs()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateBeatmapIDs)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -524,7 +526,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWhenFileOpen()
|
public async Task TestImportWhenFileOpen()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenFileOpen)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -546,7 +548,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDuplicateHashes()
|
public async Task TestImportWithDuplicateHashes()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateHashes)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -588,7 +590,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportNestedStructure()
|
public async Task TestImportNestedStructure()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -633,7 +635,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithIgnoredDirectoryInArchive()
|
public async Task TestImportWithIgnoredDirectoryInArchive()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithIgnoredDirectoryInArchive)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -687,7 +689,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapInfo()
|
public async Task TestUpdateBeatmapInfo()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapInfo)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -717,7 +719,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapFile()
|
public async Task TestUpdateBeatmapFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapFile)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -756,6 +758,63 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCreateNewEmptyBeatmap()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
manager.Save(working.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
|
||||||
|
|
||||||
|
// Check that the new file is referenced correctly by attempting a retrieval
|
||||||
|
Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
|
||||||
|
Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCreateNewBeatmapWithObject()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
((Beatmap)working.Beatmap).HitObjects.Add(new HitCircle { StartTime = 5000 });
|
||||||
|
|
||||||
|
manager.Save(working.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
|
||||||
|
|
||||||
|
// Check that the new file is referenced correctly by attempting a retrieval
|
||||||
|
Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
|
||||||
|
Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(updatedBeatmap.HitObjects[0].StartTime, Is.EqualTo(5000));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
||||||
{
|
{
|
||||||
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||||
|
@ -351,7 +351,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
using (var encoded = new MemoryStream())
|
using (var encoded = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var sw = new StreamWriter(encoded))
|
using (var sw = new StreamWriter(encoded))
|
||||||
new LegacyBeatmapEncoder(beatmap).Encode(sw);
|
new LegacyBeatmapEncoder(beatmap, null).Encode(sw);
|
||||||
|
|
||||||
return encoded.ToArray();
|
return encoded.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
// 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;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -19,7 +17,14 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
{
|
{
|
||||||
GameplayClockContainer gcc = null;
|
GameplayClockContainer gcc = null;
|
||||||
|
|
||||||
AddStep("create container", () => Add(gcc = new GameplayClockContainer(CreateWorkingBeatmap(new OsuRuleset().RulesetInfo), Array.Empty<Mod>(), 0)));
|
AddStep("create container", () =>
|
||||||
|
{
|
||||||
|
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
working.LoadTrack();
|
||||||
|
|
||||||
|
Add(gcc = new GameplayClockContainer(working, 0));
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("start track", () => gcc.Start());
|
AddStep("start track", () => gcc.Start());
|
||||||
AddUntilStep("elapsed greater than zero", () => gcc.GameplayClock.ElapsedFrameTime > 0);
|
AddUntilStep("elapsed greater than zero", () => gcc.GameplayClock.ElapsedFrameTime > 0);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,10 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
|
|
||||||
AddStep("create container", () =>
|
AddStep("create container", () =>
|
||||||
{
|
{
|
||||||
Add(gameplayContainer = new GameplayClockContainer(CreateWorkingBeatmap(new OsuRuleset().RulesetInfo), Array.Empty<Mod>(), 0));
|
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
working.LoadTrack();
|
||||||
|
|
||||||
|
Add(gameplayContainer = new GameplayClockContainer(working, 0));
|
||||||
|
|
||||||
gameplayContainer.Add(sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1))
|
gameplayContainer.Add(sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1))
|
||||||
{
|
{
|
||||||
@ -103,7 +106,7 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, Audio);
|
Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, Audio);
|
||||||
SelectedMods.Value = new[] { testedMod };
|
SelectedMods.Value = new[] { testedMod };
|
||||||
|
|
||||||
Add(gameplayContainer = new GameplayClockContainer(Beatmap.Value, SelectedMods.Value, 0));
|
Add(gameplayContainer = new GameplayClockContainer(Beatmap.Value, 0));
|
||||||
|
|
||||||
gameplayContainer.Add(sample = new TestDrawableStoryboardSample(new StoryboardSampleInfo("test-sample", 1, 1))
|
gameplayContainer.Add(sample = new TestDrawableStoryboardSample(new StoryboardSampleInfo("test-sample", 1, 1))
|
||||||
{
|
{
|
||||||
|
43
osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs
Normal file
43
osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs
Normal 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 System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.NonVisual.Ranking
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class UnstableRateTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestDistributedHits()
|
||||||
|
{
|
||||||
|
var events = Enumerable.Range(-5, 11)
|
||||||
|
.Select(t => new HitEvent(t - 5, HitResult.Great, new HitObject(), null, null));
|
||||||
|
|
||||||
|
var unstableRate = new UnstableRate(events);
|
||||||
|
|
||||||
|
Assert.IsTrue(Precision.AlmostEquals(unstableRate.Value, 10 * Math.Sqrt(10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMissesAndEmptyWindows()
|
||||||
|
{
|
||||||
|
var events = new[]
|
||||||
|
{
|
||||||
|
new HitEvent(-100, HitResult.Miss, new HitObject(), null, null),
|
||||||
|
new HitEvent(0, HitResult.Great, new HitObject(), null, null),
|
||||||
|
new HitEvent(200, HitResult.Meh, new HitObject { HitWindows = HitWindows.Empty }, null, null),
|
||||||
|
};
|
||||||
|
|
||||||
|
var unstableRate = new UnstableRate(events);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, unstableRate.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
osu.Game.Tests/Resources/Replays/mania-replay.osr
Normal file
BIN
osu.Game.Tests/Resources/Replays/mania-replay.osr
Normal file
Binary file not shown.
@ -1,5 +0,0 @@
|
|||||||
[General]
|
|
||||||
Version: latest
|
|
||||||
|
|
||||||
[Colours]
|
|
||||||
Combo1: 255,255,255,0
|
|
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestBasicImport()
|
public async Task TestBasicImport()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestBasicImport"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -66,7 +66,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportMods()
|
public async Task TestImportMods()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportMods"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportStatistics()
|
public async Task TestImportStatistics()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportStatistics"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDeletedBeatmapSet()
|
public async Task TestImportWithDeletedBeatmapSet()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWithDeletedBeatmapSet"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -159,7 +159,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestOnlineScoreIsAvailableLocally()
|
public async Task TestOnlineScoreIsAvailableLocally()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestOnlineScoreIsAvailableLocally"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -108,15 +108,5 @@ namespace osu.Game.Tests.Skins
|
|||||||
using (var stream = new LineBufferedReader(resStream))
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
Assert.That(decoder.Decode(stream).LegacyVersion, Is.EqualTo(1.0m));
|
Assert.That(decoder.Decode(stream).LegacyVersion, Is.EqualTo(1.0m));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestDecodeColourWithZeroAlpha()
|
|
||||||
{
|
|
||||||
var decoder = new LegacySkinDecoder();
|
|
||||||
|
|
||||||
using (var resStream = TestResources.OpenResource("skin-zero-alpha-colour.ini"))
|
|
||||||
using (var stream = new LineBufferedReader(resStream))
|
|
||||||
Assert.That(decoder.Decode(stream).ComboColours[0].A, Is.EqualTo(1.0f));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ namespace osu.Game.Tests.Skins
|
|||||||
{
|
{
|
||||||
var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).Result;
|
var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).Result;
|
||||||
beatmap = beatmaps.GetWorkingBeatmap(imported.Beatmaps[0]);
|
beatmap = beatmaps.GetWorkingBeatmap(imported.Beatmaps[0]);
|
||||||
|
beatmap.LoadTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
32
osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
Normal file
32
osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneSetupScreen : EditorClockTestScene
|
||||||
|
{
|
||||||
|
[Cached(typeof(EditorBeatmap))]
|
||||||
|
[Cached(typeof(IBeatSnapProvider))]
|
||||||
|
private readonly EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
|
public TestSceneSetupScreen()
|
||||||
|
{
|
||||||
|
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
||||||
|
Child = new SetupScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -18,8 +17,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestSceneCompletionCancellation : OsuPlayerTestScene
|
public class TestSceneCompletionCancellation : OsuPlayerTestScene
|
||||||
{
|
{
|
||||||
private Track track;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private AudioManager audio { get; set; }
|
private AudioManager audio { get; set; }
|
||||||
|
|
||||||
@ -34,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
|
|
||||||
// Ensure track has actually running before attempting to seek
|
// Ensure track has actually running before attempting to seek
|
||||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -73,13 +70,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private void complete()
|
private void complete()
|
||||||
{
|
{
|
||||||
AddStep("seek to completion", () => track.Seek(5000));
|
AddStep("seek to completion", () => Beatmap.Value.Track.Seek(5000));
|
||||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancel()
|
private void cancel()
|
||||||
{
|
{
|
||||||
AddStep("rewind to cancel", () => track.Seek(4000));
|
AddStep("rewind to cancel", () => Beatmap.Value.Track.Seek(4000));
|
||||||
AddUntilStep("completion cleared by processor", () => !Player.ScoreProcessor.HasCompleted.Value);
|
AddUntilStep("completion cleared by processor", () => !Player.ScoreProcessor.HasCompleted.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,11 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||||
{
|
=> new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio);
|
||||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio);
|
|
||||||
track = working.Track;
|
|
||||||
return working;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,6 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -21,19 +20,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private AudioManager audioManager { get; set; }
|
private AudioManager audioManager { get; set; }
|
||||||
|
|
||||||
private Track track;
|
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) =>
|
||||||
|
new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
|
||||||
{
|
|
||||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
|
||||||
track = working.Track;
|
|
||||||
return working;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNoJudgementsOnRewind()
|
public void TestNoJudgementsOnRewind()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||||
addSeekStep(3000);
|
addSeekStep(3000);
|
||||||
AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
|
AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
|
||||||
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
|
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
|
||||||
@ -46,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private void addSeekStep(double time)
|
private void addSeekStep(double time)
|
||||||
{
|
{
|
||||||
AddStep($"seek to {time}", () => track.Seek(time));
|
AddStep($"seek to {time}", () => Beatmap.Value.Track.Seek(time));
|
||||||
|
|
||||||
// Allow a few frames of lenience
|
// Allow a few frames of lenience
|
||||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||||
|
54
osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs
Normal file
54
osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public class TestSceneOverlayActivation : OsuPlayerTestScene
|
||||||
|
{
|
||||||
|
protected new OverlayTestPlayer Player => base.Player as OverlayTestPlayer;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivation()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationPaused()
|
||||||
|
{
|
||||||
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("pause gameplay", () => Player.Pause());
|
||||||
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationReplayLoaded()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
||||||
|
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationBreaks()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
||||||
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
||||||
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
||||||
|
|
||||||
|
protected class OverlayTestPlayer : TestPlayer
|
||||||
|
{
|
||||||
|
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,9 @@
|
|||||||
// 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;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -32,7 +30,10 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
requestCount = 0;
|
requestCount = 0;
|
||||||
increment = skip_time;
|
increment = skip_time;
|
||||||
|
|
||||||
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), Array.Empty<Mod>(), 0)
|
var working = CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo));
|
||||||
|
working.LoadTrack();
|
||||||
|
|
||||||
|
Child = gameplayClockContainer = new GameplayClockContainer(working, 0)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -22,19 +22,32 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneStoryboard : OsuTestScene
|
public class TestSceneStoryboard : OsuTestScene
|
||||||
{
|
{
|
||||||
private readonly Container<DrawableStoryboard> storyboardContainer;
|
private Container<DrawableStoryboard> storyboardContainer;
|
||||||
private DrawableStoryboard storyboard;
|
private DrawableStoryboard storyboard;
|
||||||
|
|
||||||
[Cached]
|
[Test]
|
||||||
private MusicController musicController = new MusicController();
|
public void TestStoryboard()
|
||||||
|
{
|
||||||
|
AddStep("Restart", restart);
|
||||||
|
AddToggleStep("Passing", passing =>
|
||||||
|
{
|
||||||
|
if (storyboard != null) storyboard.Passing = passing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public TestSceneStoryboard()
|
[Test]
|
||||||
|
public void TestStoryboardMissingVideo()
|
||||||
|
{
|
||||||
|
AddStep("Load storyboard with missing video", loadStoryboardNoVideo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
Clock = new FramedClock();
|
Clock = new FramedClock();
|
||||||
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
musicController,
|
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -58,32 +71,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
State = { Value = Visibility.Visible },
|
State = { Value = Visibility.Visible },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Beatmap.BindValueChanged(beatmapChanged, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e) => loadStoryboard(e.NewValue);
|
||||||
public void TestStoryboard()
|
|
||||||
{
|
|
||||||
AddStep("Restart", restart);
|
|
||||||
AddToggleStep("Passing", passing =>
|
|
||||||
{
|
|
||||||
if (storyboard != null) storyboard.Passing = passing;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestStoryboardMissingVideo()
|
|
||||||
{
|
|
||||||
AddStep("Load storyboard with missing video", loadStoryboardNoVideo);
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
Beatmap.ValueChanged += beatmapChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e)
|
|
||||||
=> loadStoryboard(e.NewValue);
|
|
||||||
|
|
||||||
private void restart()
|
private void restart()
|
||||||
{
|
{
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// 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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Menus
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
@ -15,11 +15,9 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
|
|
||||||
public TestSceneIntroWelcome()
|
public TestSceneIntroWelcome()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for load", () => getTrack() != null);
|
AddUntilStep("wait for load", () => MusicController.TrackLoaded);
|
||||||
|
AddAssert("correct track", () => Precision.AlmostEquals(MusicController.CurrentTrack.Length, 48000, 1));
|
||||||
AddAssert("check if menu music loops", () => getTrack().Looping);
|
AddAssert("check if menu music loops", () => MusicController.CurrentTrack.Looping);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Track getTrack() => (IntroStack?.CurrentScreen as MainMenu)?.Track;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
83
osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
Normal file
83
osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
using osu.Game.Tests.Visual.Navigation;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
|
{
|
||||||
|
public class TestSceneMusicActionHandling : OsuGameTestScene
|
||||||
|
{
|
||||||
|
private GlobalActionContainer globalActionContainer => Game.ChildrenOfType<GlobalActionContainer>().First();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMusicPlayAction()
|
||||||
|
{
|
||||||
|
AddStep("ensure playing something", () => Game.MusicController.EnsurePlayingSomething());
|
||||||
|
AddStep("toggle playback", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPlay));
|
||||||
|
AddAssert("music paused", () => !Game.MusicController.IsPlaying && Game.MusicController.IsUserPaused);
|
||||||
|
AddStep("toggle playback", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPlay));
|
||||||
|
AddAssert("music resumed", () => Game.MusicController.IsPlaying && !Game.MusicController.IsUserPaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMusicNavigationActions()
|
||||||
|
{
|
||||||
|
int importId = 0;
|
||||||
|
Queue<(WorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
|
||||||
|
|
||||||
|
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
|
||||||
|
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
Beatmaps = new List<BeatmapInfo>
|
||||||
|
{
|
||||||
|
new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = $"a test map {importId++}",
|
||||||
|
Title = "title",
|
||||||
|
}
|
||||||
|
}).Wait(), 5);
|
||||||
|
|
||||||
|
AddStep("import beatmap with track", () =>
|
||||||
|
{
|
||||||
|
var setWithTrack = Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result;
|
||||||
|
Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(setWithTrack.Beatmaps.First());
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("bind to track change", () =>
|
||||||
|
{
|
||||||
|
trackChangeQueue = new Queue<(WorkingBeatmap, TrackChangeDirection)>();
|
||||||
|
Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection));
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("seek track to 6 second", () => Game.MusicController.SeekTo(6000));
|
||||||
|
AddUntilStep("wait for current time to update", () => Game.MusicController.CurrentTrack.CurrentTime > 5000);
|
||||||
|
|
||||||
|
AddStep("press previous", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPrev));
|
||||||
|
AddAssert("no track change", () => trackChangeQueue.Count == 0);
|
||||||
|
AddUntilStep("track restarted", () => Game.MusicController.CurrentTrack.CurrentTime < 5000);
|
||||||
|
|
||||||
|
AddStep("press previous", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPrev));
|
||||||
|
AddAssert("track changed to previous", () =>
|
||||||
|
trackChangeQueue.Count == 1 &&
|
||||||
|
trackChangeQueue.Dequeue().changeDirection == TrackChangeDirection.Prev);
|
||||||
|
|
||||||
|
AddStep("press next", () => globalActionContainer.TriggerPressed(GlobalAction.MusicNext));
|
||||||
|
AddAssert("track changed to next", () =>
|
||||||
|
trackChangeQueue.Count == 1 &&
|
||||||
|
trackChangeQueue.Dequeue().changeDirection == TrackChangeDirection.Next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// 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 osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
@ -11,14 +10,10 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
{
|
{
|
||||||
public class TestSceneSongTicker : OsuTestScene
|
public class TestSceneSongTicker : OsuTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
|
||||||
private MusicController musicController = new MusicController();
|
|
||||||
|
|
||||||
public TestSceneSongTicker()
|
public TestSceneSongTicker()
|
||||||
{
|
{
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
musicController,
|
|
||||||
new SongTicker
|
new SongTicker
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
|
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
|
|
||||||
public class TestToolbar : Toolbar
|
public class TestToolbar : Toolbar
|
||||||
{
|
{
|
||||||
public new Bindable<OverlayActivation> OverlayActivationMode => base.OverlayActivationMode;
|
public new Bindable<OverlayActivation> OverlayActivationMode => base.OverlayActivationMode as Bindable<OverlayActivation>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,28 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddAssert("item 2 has rate 2", () => Precision.AlmostEquals(2, ((OsuModDoubleTime)Room.Playlist.Last().RequiredMods[0]).SpeedChange.Value));
|
AddAssert("item 2 has rate 2", () => Precision.AlmostEquals(2, ((OsuModDoubleTime)Room.Playlist.Last().RequiredMods[0]).SpeedChange.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests that the global mod instances are not retained by the rooms, as global mod instances are retained and re-used by the mod select overlay.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestGlobalModInstancesNotRetained()
|
||||||
|
{
|
||||||
|
OsuModDoubleTime mod = null;
|
||||||
|
|
||||||
|
AddStep("set dt mod and store", () =>
|
||||||
|
{
|
||||||
|
SelectedMods.Value = new[] { new OsuModDoubleTime() };
|
||||||
|
|
||||||
|
// Mod select overlay replaces our mod.
|
||||||
|
mod = (OsuModDoubleTime)SelectedMods.Value[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||||
|
|
||||||
|
AddStep("change stored mod rate", () => mod.SpeedChange.Value = 2);
|
||||||
|
AddAssert("item has rate 1.5", () => Precision.AlmostEquals(1.5, ((OsuModDoubleTime)Room.Playlist.First().RequiredMods[0]).SpeedChange.Value));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestMatchSongSelect : MatchSongSelect
|
private class TestMatchSongSelect : MatchSongSelect
|
||||||
{
|
{
|
||||||
public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails;
|
public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails;
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -46,7 +45,6 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
Player player = null;
|
Player player = null;
|
||||||
|
|
||||||
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
||||||
Track track() => beatmap().Track;
|
|
||||||
|
|
||||||
PushAndConfirm(() => new TestSongSelect());
|
PushAndConfirm(() => new TestSongSelect());
|
||||||
|
|
||||||
@ -62,30 +60,27 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
|
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
|
||||||
AddUntilStep("wait for fail", () => player.HasFailed);
|
AddUntilStep("wait for fail", () => player.HasFailed);
|
||||||
|
|
||||||
AddUntilStep("wait for track stop", () => !track().IsRunning);
|
AddUntilStep("wait for track stop", () => !Game.MusicController.IsPlaying);
|
||||||
AddAssert("Ensure time before preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime);
|
AddAssert("Ensure time before preview point", () => Game.MusicController.CurrentTrack.CurrentTime < beatmap().Metadata.PreviewTime);
|
||||||
|
|
||||||
pushEscape();
|
pushEscape();
|
||||||
|
|
||||||
AddUntilStep("wait for track playing", () => track().IsRunning);
|
AddUntilStep("wait for track playing", () => Game.MusicController.IsPlaying);
|
||||||
AddAssert("Ensure time wasn't reset to preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime);
|
AddAssert("Ensure time wasn't reset to preview point", () => Game.MusicController.CurrentTrack.CurrentTime < beatmap().Metadata.PreviewTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMenuMakesMusic()
|
public void TestMenuMakesMusic()
|
||||||
{
|
{
|
||||||
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
|
||||||
Track track() => beatmap().Track;
|
|
||||||
|
|
||||||
TestSongSelect songSelect = null;
|
TestSongSelect songSelect = null;
|
||||||
|
|
||||||
PushAndConfirm(() => songSelect = new TestSongSelect());
|
PushAndConfirm(() => songSelect = new TestSongSelect());
|
||||||
|
|
||||||
AddUntilStep("wait for no track", () => track() is TrackVirtual);
|
AddUntilStep("wait for no track", () => Game.MusicController.CurrentTrack.IsDummyDevice);
|
||||||
|
|
||||||
AddStep("return to menu", () => songSelect.Exit());
|
AddStep("return to menu", () => songSelect.Exit());
|
||||||
|
|
||||||
AddUntilStep("wait for track", () => !(track() is TrackVirtual) && track().IsRunning);
|
AddUntilStep("wait for track", () => !Game.MusicController.CurrentTrack.IsDummyDevice && Game.MusicController.IsPlaying);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -140,12 +135,12 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded);
|
AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded);
|
||||||
AddStep("Seek close to end", () =>
|
AddStep("Seek close to end", () =>
|
||||||
{
|
{
|
||||||
Game.MusicController.SeekTo(Game.Beatmap.Value.Track.Length - 1000);
|
Game.MusicController.SeekTo(Game.MusicController.CurrentTrack.Length - 1000);
|
||||||
Game.Beatmap.Value.Track.Completed += () => trackCompleted = true;
|
Game.MusicController.CurrentTrack.Completed += () => trackCompleted = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("Track was completed", () => trackCompleted);
|
AddUntilStep("Track was completed", () => trackCompleted);
|
||||||
AddUntilStep("Track was restarted", () => Game.Beatmap.Value.Track.IsRunning);
|
AddUntilStep("Track was restarted", () => Game.MusicController.IsPlaying);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pushEscape() =>
|
private void pushEscape() =>
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneFullscreenOverlay : OsuTestScene
|
public class TestSceneFullscreenOverlay : OsuTestScene
|
||||||
{
|
{
|
||||||
private FullscreenOverlay overlay;
|
private FullscreenOverlay<OverlayHeader> overlay;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
@ -38,10 +38,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert("fire count 3", () => fireCount == 3);
|
AddAssert("fire count 3", () => fireCount == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestFullscreenOverlay : FullscreenOverlay
|
private class TestFullscreenOverlay : FullscreenOverlay<OverlayHeader>
|
||||||
{
|
{
|
||||||
public TestFullscreenOverlay()
|
public TestFullscreenOverlay()
|
||||||
: base(OverlayColourScheme.Pink)
|
: base(OverlayColourScheme.Pink, null)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby());
|
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby());
|
||||||
|
|
||||||
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(null, null)
|
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
|
||||||
{
|
{
|
||||||
BeatmapInfo = { OnlineBeatmapID = hasOnlineId ? 1234 : (int?)null }
|
BeatmapInfo = { OnlineBeatmapID = hasOnlineId ? 1234 : (int?)null }
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,18 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
createTest(new List<HitEvent>());
|
createTest(new List<HitEvent>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMissesDontShow()
|
||||||
|
{
|
||||||
|
createTest(Enumerable.Range(0, 100).Select(i =>
|
||||||
|
{
|
||||||
|
if (i % 2 == 0)
|
||||||
|
return new HitEvent(0, HitResult.Perfect, new HitCircle(), new HitCircle(), null);
|
||||||
|
|
||||||
|
return new HitEvent(30, HitResult.Miss, new HitCircle(), new HitCircle(), null);
|
||||||
|
}).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
private void createTest(List<HitEvent> events) => AddStep("create test", () =>
|
private void createTest(List<HitEvent> events) => AddStep("create test", () =>
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -212,6 +213,25 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
AddAssert("expanded panel still on screen", () => this.ChildrenOfType<ScorePanel>().Single(p => p.State == PanelState.Expanded).ScreenSpaceDrawQuad.TopLeft.X > 0);
|
AddAssert("expanded panel still on screen", () => this.ChildrenOfType<ScorePanel>().Single(p => p.State == PanelState.Expanded).ScreenSpaceDrawQuad.TopLeft.X > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDownloadButtonInitiallyDisabled()
|
||||||
|
{
|
||||||
|
TestResultsScreen screen = null;
|
||||||
|
|
||||||
|
AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen()));
|
||||||
|
|
||||||
|
AddAssert("download button is disabled", () => !screen.ChildrenOfType<DownloadButton>().Single().Enabled.Value);
|
||||||
|
|
||||||
|
AddStep("click contracted panel", () =>
|
||||||
|
{
|
||||||
|
var contractedPanel = this.ChildrenOfType<ScorePanel>().First(p => p.State == PanelState.Contracted && p.ScreenSpaceDrawQuad.TopLeft.X > screen.ScreenSpaceDrawQuad.TopLeft.X);
|
||||||
|
InputManager.MoveMouseTo(contractedPanel);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("download button is enabled", () => screen.ChildrenOfType<DownloadButton>().Single().Enabled.Value);
|
||||||
|
}
|
||||||
|
|
||||||
private class TestResultsContainer : Container
|
private class TestResultsContainer : Container
|
||||||
{
|
{
|
||||||
[Cached(typeof(Player))]
|
[Cached(typeof(Player))]
|
||||||
@ -255,6 +275,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
{
|
{
|
||||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
score.TotalScore += 10 - i;
|
score.TotalScore += 10 - i;
|
||||||
|
score.Hash = $"test{i}";
|
||||||
scores.Add(score);
|
scores.Add(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ using osu.Game.Screens.Ranking.Statistics;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Ranking
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
{
|
{
|
||||||
public class TestSceneSimpleStatisticRow : OsuTestScene
|
public class TestSceneSimpleStatisticTable : OsuTestScene
|
||||||
{
|
{
|
||||||
private Container container;
|
private Container container;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
public void TestEmpty()
|
public void TestEmpty()
|
||||||
{
|
{
|
||||||
AddStep("create with no items",
|
AddStep("create with no items",
|
||||||
() => container.Add(new SimpleStatisticRow(2, Enumerable.Empty<SimpleStatisticItem>())));
|
() => container.Add(new SimpleStatisticTable(2, Enumerable.Empty<SimpleStatisticItem>())));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
Value = RNG.Next(100)
|
Value = RNG.Next(100)
|
||||||
});
|
});
|
||||||
|
|
||||||
container.Add(new SimpleStatisticRow(columnCount, items));
|
container.Add(new SimpleStatisticTable(columnCount, items));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,9 +5,9 @@ using System;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
using osu.Game.Online.Leaderboards;
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Select.Leaderboards;
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
@ -53,53 +53,46 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
private void showPersonalBestWithNullPosition()
|
private void showPersonalBestWithNullPosition()
|
||||||
{
|
{
|
||||||
leaderboard.TopScore = new APILegacyUserTopScoreInfo
|
leaderboard.TopScore = new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = null,
|
Rank = ScoreRank.XH,
|
||||||
Score = new APILegacyScoreInfo
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Id = 6602580,
|
||||||
Accuracy = 1,
|
Username = @"waaiiru",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
FullName = @"Spain",
|
||||||
Username = @"waaiiru",
|
FlagName = @"ES",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Spain",
|
|
||||||
FlagName = @"ES",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPersonalBest()
|
private void showPersonalBest()
|
||||||
{
|
{
|
||||||
leaderboard.TopScore = new APILegacyUserTopScoreInfo
|
leaderboard.TopScore = new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 999,
|
Position = 999,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.XH,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Id = 6602580,
|
||||||
Accuracy = 1,
|
Username = @"waaiiru",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
FullName = @"Spain",
|
||||||
Username = @"waaiiru",
|
FlagName = @"ES",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Spain",
|
|
||||||
FlagName = @"ES",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Screens.Select.Leaderboards;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.SongSelect
|
namespace osu.Game.Tests.Visual.SongSelect
|
||||||
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
public TestSceneUserTopScoreContainer()
|
public TestSceneUserTopScoreContainer()
|
||||||
{
|
{
|
||||||
UserTopScoreContainer topScoreContainer;
|
UserTopScoreContainer<ScoreInfo> topScoreContainer;
|
||||||
|
|
||||||
Add(dialogOverlay = new DialogOverlay
|
Add(dialogOverlay = new DialogOverlay
|
||||||
{
|
{
|
||||||
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.DarkGreen,
|
Colour = Color4.DarkGreen,
|
||||||
},
|
},
|
||||||
topScoreContainer = new UserTopScoreContainer
|
topScoreContainer = new UserTopScoreContainer<ScoreInfo>(s => new LeaderboardScore(s, s.Position, false))
|
||||||
{
|
{
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
@ -52,69 +52,60 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
var scores = new[]
|
var scores = new[]
|
||||||
{
|
{
|
||||||
new APILegacyUserTopScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 999,
|
Position = 999,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.XH,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Id = 6602580,
|
||||||
Accuracy = 1,
|
Username = @"waaiiru",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
FullName = @"Spain",
|
||||||
Username = @"waaiiru",
|
FlagName = @"ES",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Spain",
|
|
||||||
FlagName = @"ES",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
new APILegacyUserTopScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 110000,
|
Position = 110000,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.X,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.X,
|
Id = 4608074,
|
||||||
Accuracy = 1,
|
Username = @"Skycries",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 4608074,
|
FullName = @"Brazil",
|
||||||
Username = @"Skycries",
|
FlagName = @"BR",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Brazil",
|
|
||||||
FlagName = @"BR",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
new APILegacyUserTopScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 22333,
|
Position = 22333,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.S,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.S,
|
Id = 1541390,
|
||||||
Accuracy = 1,
|
Username = @"Toukai",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 1541390,
|
FullName = @"Canada",
|
||||||
Username = @"Toukai",
|
FlagName = @"CA",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Canada",
|
|
||||||
FlagName = @"CA",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,9 +26,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
private readonly NowPlayingOverlay np;
|
private readonly NowPlayingOverlay np;
|
||||||
|
|
||||||
[Cached]
|
|
||||||
private MusicController musicController = new MusicController();
|
|
||||||
|
|
||||||
public TestSceneBeatSyncedContainer()
|
public TestSceneBeatSyncedContainer()
|
||||||
{
|
{
|
||||||
Clock = new FramedClock();
|
Clock = new FramedClock();
|
||||||
@ -36,7 +33,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
musicController,
|
|
||||||
new BeatContainer
|
new BeatContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
@ -71,6 +67,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private readonly Box flashLayer;
|
private readonly Box flashLayer;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private MusicController musicController { get; set; }
|
||||||
|
|
||||||
public BeatContainer()
|
public BeatContainer()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -165,7 +164,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
if (timingPoints.Count == 0) return 0;
|
if (timingPoints.Count == 0) return 0;
|
||||||
|
|
||||||
if (timingPoints[^1] == current)
|
if (timingPoints[^1] == current)
|
||||||
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);
|
return (int)Math.Ceiling((musicController.CurrentTrack.Length - current.Time) / current.BeatLength);
|
||||||
|
|
||||||
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
|
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -79,7 +80,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
|
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
|
||||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, Audio, dependencies.Get<GameHost>(), Beatmap.Default));
|
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), dependencies.Get<GameHost>(), Beatmap.Default));
|
||||||
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory));
|
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory));
|
||||||
|
|
||||||
beatmap = beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result.Beatmaps[0];
|
beatmap = beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result.Beatmaps[0];
|
||||||
|
@ -1,15 +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.Collections.Generic;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
@ -20,18 +15,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Cached]
|
[Cached]
|
||||||
private MusicController musicController = new MusicController();
|
private MusicController musicController = new MusicController();
|
||||||
|
|
||||||
private WorkingBeatmap currentBeatmap;
|
|
||||||
|
|
||||||
private NowPlayingOverlay nowPlayingOverlay;
|
private NowPlayingOverlay nowPlayingOverlay;
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio, GameHost host)
|
private void load()
|
||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
|
||||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
|
|
||||||
|
|
||||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
nowPlayingOverlay = new NowPlayingOverlay
|
nowPlayingOverlay = new NowPlayingOverlay
|
||||||
@ -51,44 +39,5 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
|
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
|
||||||
AddStep(@"hide", () => nowPlayingOverlay.Hide());
|
AddStep(@"hide", () => nowPlayingOverlay.Hide());
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapManager manager { get; set; }
|
|
||||||
|
|
||||||
private int importId;
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestPrevTrackBehavior()
|
|
||||||
{
|
|
||||||
// ensure we have at least two beatmaps available.
|
|
||||||
AddRepeatStep("import beatmap", () => manager.Import(new BeatmapSetInfo
|
|
||||||
{
|
|
||||||
Beatmaps = new List<BeatmapInfo>
|
|
||||||
{
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
|
||||||
Artist = $"a test map {importId++}",
|
|
||||||
Title = "title",
|
|
||||||
}
|
|
||||||
}).Wait(), 5);
|
|
||||||
|
|
||||||
AddStep(@"Next track", () => musicController.NextTrack());
|
|
||||||
AddStep("Store track", () => currentBeatmap = Beatmap.Value);
|
|
||||||
|
|
||||||
AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000));
|
|
||||||
AddUntilStep(@"Wait for current time to update", () => currentBeatmap.Track.CurrentTime > 5000);
|
|
||||||
|
|
||||||
AddStep(@"Set previous", () => musicController.PreviousTrack());
|
|
||||||
|
|
||||||
AddAssert(@"Check beatmap didn't change", () => currentBeatmap == Beatmap.Value);
|
|
||||||
AddUntilStep("Wait for current time to update", () => currentBeatmap.Track.CurrentTime < 5000);
|
|
||||||
|
|
||||||
AddStep(@"Set previous", () => musicController.PreviousTrack());
|
|
||||||
AddAssert(@"Check beatmap did change", () => currentBeatmap != Beatmap.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Tests
|
|||||||
|
|
||||||
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
||||||
|
|
||||||
protected override Track GetTrack() => trackStore.Get(firstAudioFile);
|
protected override Track GetBeatmapTrack() => trackStore.Get(firstAudioFile);
|
||||||
|
|
||||||
private string firstAudioFile
|
private string firstAudioFile
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<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="DeepEqual" Version="2.0.0" />
|
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<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" />
|
||||||
|
41
osu.Game.Tournament.Tests/Components/TestSceneDateTextBox.cs
Normal file
41
osu.Game.Tournament.Tests/Components/TestSceneDateTextBox.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 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.Game.Tests.Visual;
|
||||||
|
using osu.Game.Tournament.Components;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament.Tests.Components
|
||||||
|
{
|
||||||
|
public class TestSceneDateTextBox : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
private DateTextBox textBox;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup() => Schedule(() =>
|
||||||
|
{
|
||||||
|
Child = textBox = new DateTextBox
|
||||||
|
{
|
||||||
|
Width = 0.3f
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCommitWithoutSettingBindable()
|
||||||
|
{
|
||||||
|
AddStep("click textbox", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(textBox);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("unfocus", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(Vector2.Zero);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,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.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -22,11 +22,12 @@ namespace osu.Game.Tournament.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hold a reference to the provided bindable so we don't have to in every settings section.
|
// hold a reference to the provided bindable so we don't have to in every settings section.
|
||||||
private Bindable<DateTimeOffset> bindable;
|
private Bindable<DateTimeOffset> bindable = new Bindable<DateTimeOffset>();
|
||||||
|
|
||||||
public DateTextBox()
|
public DateTextBox()
|
||||||
{
|
{
|
||||||
base.Bindable = new Bindable<string>();
|
base.Bindable = new Bindable<string>();
|
||||||
|
|
||||||
((OsuTextBox)Control).OnCommit = (sender, newText) =>
|
((OsuTextBox)Control).OnCommit = (sender, newText) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -26,6 +26,8 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
[Cached]
|
[Cached]
|
||||||
private LadderEditorInfo editorInfo = new LadderEditorInfo();
|
private LadderEditorInfo editorInfo = new LadderEditorInfo();
|
||||||
|
|
||||||
|
private WarningBox rightClickMessage;
|
||||||
|
|
||||||
protected override bool DrawLoserPaths => true;
|
protected override bool DrawLoserPaths => true;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -37,6 +39,16 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Margin = new MarginPadding(5)
|
Margin = new MarginPadding(5)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddInternal(rightClickMessage = new WarningBox("Right click to place and link matches"));
|
||||||
|
|
||||||
|
LadderInfo.Matches.CollectionChanged += (_, __) => updateMessage();
|
||||||
|
updateMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMessage()
|
||||||
|
{
|
||||||
|
rightClickMessage.Alpha = LadderInfo.Matches.Count > 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginJoin(TournamentMatch match, bool losers)
|
public void BeginJoin(TournamentMatch match, bool losers)
|
||||||
|
@ -87,30 +87,7 @@ namespace osu.Game.Tournament
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
heightWarning = new Container
|
heightWarning = new WarningBox("Please make the window wider"),
|
||||||
{
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 5,
|
|
||||||
Depth = float.MinValue,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Colour = Color4.Red,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
new TournamentSpriteText
|
|
||||||
{
|
|
||||||
Text = "Please make the window wider",
|
|
||||||
Font = OsuFont.Torus.With(weight: FontWeight.Bold),
|
|
||||||
Colour = Color4.White,
|
|
||||||
Padding = new MarginPadding(20)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new OsuContextMenuContainer
|
new OsuContextMenuContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
40
osu.Game.Tournament/WarningBox.cs
Normal file
40
osu.Game.Tournament/WarningBox.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament
|
||||||
|
{
|
||||||
|
internal class WarningBox : Container
|
||||||
|
{
|
||||||
|
public WarningBox(string text)
|
||||||
|
{
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = 5;
|
||||||
|
Depth = float.MinValue;
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.Red,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new TournamentSpriteText
|
||||||
|
{
|
||||||
|
Text = text,
|
||||||
|
Font = OsuFont.Torus.With(weight: FontWeight.Bold),
|
||||||
|
Colour = Color4.White,
|
||||||
|
Padding = new MarginPadding(20)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -89,8 +89,14 @@ namespace osu.Game.Beatmaps
|
|||||||
if (tryGetExisting(beatmapInfo, rulesetInfo, mods, out var existing, out var key))
|
if (tryGetExisting(beatmapInfo, rulesetInfo, mods, out var existing, out var key))
|
||||||
return existing;
|
return existing;
|
||||||
|
|
||||||
return await Task.Factory.StartNew(() => computeDifficulty(key, beatmapInfo, rulesetInfo), cancellationToken,
|
return await Task.Factory.StartNew(() =>
|
||||||
TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler);
|
{
|
||||||
|
// Computation may have finished in a previous task.
|
||||||
|
if (tryGetExisting(beatmapInfo, rulesetInfo, mods, out existing, out _))
|
||||||
|
return existing;
|
||||||
|
|
||||||
|
return computeDifficulty(key, beatmapInfo, rulesetInfo);
|
||||||
|
}, cancellationToken, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -245,7 +251,7 @@ namespace osu.Game.Beatmaps
|
|||||||
updateScheduler?.Dispose();
|
updateScheduler?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly struct DifficultyCacheLookup : IEquatable<DifficultyCacheLookup>
|
public readonly struct DifficultyCacheLookup : IEquatable<DifficultyCacheLookup>
|
||||||
{
|
{
|
||||||
public readonly int BeatmapId;
|
public readonly int BeatmapId;
|
||||||
public readonly int RulesetId;
|
public readonly int RulesetId;
|
||||||
@ -261,7 +267,7 @@ namespace osu.Game.Beatmaps
|
|||||||
public bool Equals(DifficultyCacheLookup other)
|
public bool Equals(DifficultyCacheLookup other)
|
||||||
=> BeatmapId == other.BeatmapId
|
=> BeatmapId == other.BeatmapId
|
||||||
&& RulesetId == other.RulesetId
|
&& RulesetId == other.RulesetId
|
||||||
&& Mods.SequenceEqual(other.Mods);
|
&& Mods.Select(m => m.Acronym).SequenceEqual(other.Mods.Select(m => m.Acronym));
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -14,6 +15,7 @@ using osu.Game.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user