mirror of
https://github.com/osukey/osukey.git
synced 2025-08-08 00:53:56 +09:00
Merge branch 'master' into update-ios-native-linking
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -38,7 +38,7 @@ jobs:
|
|||||||
run: dotnet build -c Debug -warnaserror osu.Desktop.slnf
|
run: dotnet build -c Debug -warnaserror osu.Desktop.slnf
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: dotnet test $pwd/*.Tests/bin/Debug/*/*.Tests.dll --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx"
|
run: dotnet test $pwd/*.Tests/bin/Debug/*/*.Tests.dll --blame-crash --blame-hang --blame-hang-timeout 5m --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx"
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
# Attempt to upload results even if test fails.
|
# Attempt to upload results even if test fails.
|
||||||
@ -48,7 +48,7 @@ jobs:
|
|||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}}
|
name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}}
|
||||||
path: ${{github.workspace}}/TestResults/TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx
|
path: ${{github.workspace}}/TestResults/**/*
|
||||||
|
|
||||||
build-only-android:
|
build-only-android:
|
||||||
name: Build only (Android)
|
name: Build only (Android)
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.EmptyFreeform
|
|||||||
{
|
{
|
||||||
public class EmptyFreeformDifficultyCalculator : DifficultyCalculator
|
public class EmptyFreeformDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
public EmptyFreeformDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public EmptyFreeformDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ namespace osu.Game.Rulesets.EmptyFreeform
|
|||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
||||||
new EmptyFreeformBeatmapConverter(beatmap, this);
|
new EmptyFreeformBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) =>
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) =>
|
||||||
new EmptyFreeformDifficultyCalculator(this, beatmap);
|
new EmptyFreeformDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
{
|
{
|
||||||
public class PippidonDifficultyCalculator : DifficultyCalculator
|
public class PippidonDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
public PippidonDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public PippidonDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
||||||
new PippidonBeatmapConverter(beatmap, this);
|
new PippidonBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) =>
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) =>
|
||||||
new PippidonDifficultyCalculator(this, beatmap);
|
new PippidonDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.EmptyScrolling
|
|||||||
{
|
{
|
||||||
public class EmptyScrollingDifficultyCalculator : DifficultyCalculator
|
public class EmptyScrollingDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
public EmptyScrollingDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public EmptyScrollingDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.EmptyScrolling
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new EmptyScrollingBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new EmptyScrollingBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new EmptyScrollingDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new EmptyScrollingDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
{
|
{
|
||||||
public class PippidonDifficultyCalculator : DifficultyCalculator
|
public class PippidonDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
public PippidonDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public PippidonDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new PippidonBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new PippidonBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new PippidonDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new PippidonDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
|
@ -51,8 +51,8 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1112.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1108.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1118.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
@ -93,6 +93,11 @@ namespace osu.Desktop
|
|||||||
|
|
||||||
protected override UpdateManager CreateUpdateManager()
|
protected override UpdateManager CreateUpdateManager()
|
||||||
{
|
{
|
||||||
|
string packageManaged = Environment.GetEnvironmentVariable("OSU_EXTERNAL_UPDATE_PROVIDER");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(packageManaged))
|
||||||
|
return new NoActionUpdateManager();
|
||||||
|
|
||||||
switch (RuntimeInfo.OS)
|
switch (RuntimeInfo.OS)
|
||||||
{
|
{
|
||||||
case RuntimeInfo.Platform.Windows:
|
case RuntimeInfo.Platform.Windows:
|
||||||
|
@ -183,6 +183,19 @@ namespace osu.Desktop.Updater
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
// cancelling updates is not currently supported by the underlying updater.
|
||||||
|
// only allow dismissing for now.
|
||||||
|
|
||||||
|
switch (State)
|
||||||
|
{
|
||||||
|
case ProgressNotificationState.Cancelled:
|
||||||
|
base.Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SquirrelLogger : Splat.ILogger, IDisposable
|
private class SquirrelLogger : Splat.ILogger, IDisposable
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new CatchModDoubleTime());
|
=> Test(expected, name, new CatchModDoubleTime());
|
||||||
|
|
||||||
protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(new CatchRuleset(), beatmap);
|
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new CatchDifficultyCalculator(new CatchRuleset().RulesetInfo, beatmap);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new CatchRuleset();
|
protected override Ruleset CreateRuleset() => new CatchRuleset();
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,28 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
checkHyperDash(false);
|
checkHyperDash(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLastBananaShouldClearPlateOnMiss()
|
||||||
|
{
|
||||||
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
|
checkPlate(1);
|
||||||
|
AddStep("miss banana", () => attemptCatch(new Banana { X = 100 }));
|
||||||
|
checkPlate(1);
|
||||||
|
AddStep("miss last banana", () => attemptCatch(new Banana { LastInCombo = true, X = 100 }));
|
||||||
|
checkPlate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLastBananaShouldClearPlateOnCatch()
|
||||||
|
{
|
||||||
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
|
checkPlate(1);
|
||||||
|
AddStep("catch banana", () => attemptCatch(new Banana()));
|
||||||
|
checkPlate(2);
|
||||||
|
AddStep("catch last banana", () => attemptCatch(new Banana { LastInCombo = true }));
|
||||||
|
checkPlate(0);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCatcherRandomStacking()
|
public void TestCatcherRandomStacking()
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
var controlPointInfo = new ControlPointInfo();
|
var controlPointInfo = new ControlPointInfo();
|
||||||
controlPointInfo.Add(0, new TimingControlPoint());
|
controlPointInfo.Add(0, new TimingControlPoint());
|
||||||
|
|
||||||
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject> { new Fruit() },
|
HitObjects = new List<HitObject> { new Fruit() },
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
return base.GetDisplayNameForHitResult(result);
|
return base.GetDisplayNameForHitResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new CatchDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new CatchLegacySkinTransformer(skin);
|
public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new CatchLegacySkinTransformer(skin);
|
||||||
|
|
||||||
|
@ -1,12 +1,35 @@
|
|||||||
// 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 Newtonsoft.Json;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Difficulty
|
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||||
{
|
{
|
||||||
public class CatchDifficultyAttributes : DifficultyAttributes
|
public class CatchDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
|
[JsonProperty("approach_rate")]
|
||||||
public double ApproachRate { get; set; }
|
public double ApproachRate { get; set; }
|
||||||
|
|
||||||
|
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
|
{
|
||||||
|
foreach (var v in base.ToDatabaseAttributes())
|
||||||
|
yield return v;
|
||||||
|
|
||||||
|
// Todo: osu!catch should not output star rating in the 'aim' attribute.
|
||||||
|
yield return (ATTRIB_ID_AIM, StarRating);
|
||||||
|
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
||||||
|
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
|
||||||
|
{
|
||||||
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
|
StarRating = values[ATTRIB_ID_AIM];
|
||||||
|
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
||||||
|
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
|
|
||||||
private float halfCatcherWidth;
|
private float halfCatcherWidth;
|
||||||
|
|
||||||
public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public CatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
catchResult.CatcherAnimationState = CurrentState;
|
catchResult.CatcherAnimationState = CurrentState;
|
||||||
catchResult.CatcherHyperDash = HyperDashing;
|
catchResult.CatcherHyperDash = HyperDashing;
|
||||||
|
|
||||||
|
// Ignore JuiceStreams and BananaShowers
|
||||||
if (!(drawableObject is DrawablePalpableCatchHitObject palpableObject)) return;
|
if (!(drawableObject is DrawablePalpableCatchHitObject palpableObject)) return;
|
||||||
|
|
||||||
var hitObject = palpableObject.HitObject;
|
var hitObject = palpableObject.HitObject;
|
||||||
@ -244,6 +245,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
CurrentState = hitObject.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle;
|
CurrentState = hitObject.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle;
|
||||||
else if (!(hitObject is Banana))
|
else if (!(hitObject is Banana))
|
||||||
CurrentState = CatcherAnimationState.Fail;
|
CurrentState = CatcherAnimationState.Fail;
|
||||||
|
|
||||||
|
if (palpableObject.HitObject.LastInCombo)
|
||||||
|
{
|
||||||
|
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
||||||
|
Explode();
|
||||||
|
else
|
||||||
|
Drop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||||
|
@ -6,11 +6,9 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -72,18 +70,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
Catcher.OnNewResult(hitObject, result);
|
Catcher.OnNewResult(hitObject, result);
|
||||||
|
|
||||||
if (!result.Type.IsScorable())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (hitObject.HitObject.LastInCombo)
|
|
||||||
{
|
|
||||||
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
|
||||||
Catcher.Explode();
|
|
||||||
else
|
|
||||||
Catcher.Drop();
|
|
||||||
}
|
|
||||||
|
|
||||||
comboDisplay.OnNewResult(hitObject, result);
|
comboDisplay.OnNewResult(hitObject, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new ManiaModDoubleTime());
|
=> Test(expected, name, new ManiaModDoubleTime());
|
||||||
|
|
||||||
protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(new ManiaRuleset(), beatmap);
|
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new ManiaDifficultyCalculator(new ManiaRuleset().RulesetInfo, beatmap);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,38 @@
|
|||||||
// 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 Newtonsoft.Json;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
{
|
{
|
||||||
public class ManiaDifficultyAttributes : DifficultyAttributes
|
public class ManiaDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
|
[JsonProperty("great_hit_window")]
|
||||||
public double GreatHitWindow { get; set; }
|
public double GreatHitWindow { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("score_multiplier")]
|
||||||
public double ScoreMultiplier { get; set; }
|
public double ScoreMultiplier { get; set; }
|
||||||
|
|
||||||
|
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
|
{
|
||||||
|
foreach (var v in base.ToDatabaseAttributes())
|
||||||
|
yield return v;
|
||||||
|
|
||||||
|
// Todo: osu!mania doesn't output MaxCombo attribute for some reason.
|
||||||
|
yield return (ATTRIB_ID_STRAIN, StarRating);
|
||||||
|
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||||
|
yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
|
||||||
|
{
|
||||||
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
|
StarRating = values[ATTRIB_ID_STRAIN];
|
||||||
|
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||||
|
ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Difficulty.Skills;
|
using osu.Game.Rulesets.Difficulty.Skills;
|
||||||
@ -28,11 +29,11 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
private readonly bool isForCurrentRuleset;
|
private readonly bool isForCurrentRuleset;
|
||||||
private readonly double originalOverallDifficulty;
|
private readonly double originalOverallDifficulty;
|
||||||
|
|
||||||
public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public ManiaDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo);
|
isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.MatchesOnlineID(ruleset);
|
||||||
originalOverallDifficulty = beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty;
|
originalOverallDifficulty = beatmap.BeatmapInfo.Difficulty.OverallDifficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
|
@ -272,7 +272,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania };
|
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania };
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new ManiaDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public int LegacyID => 3;
|
public int LegacyID => 3;
|
||||||
|
|
||||||
|
@ -0,0 +1,185 @@
|
|||||||
|
// 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.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||||
|
{
|
||||||
|
public class TestSceneSliderStreamConversion : TestSceneOsuEditor
|
||||||
|
{
|
||||||
|
private BindableBeatDivisor beatDivisor => (BindableBeatDivisor)Editor.Dependencies.Get(typeof(BindableBeatDivisor));
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSimpleConversion()
|
||||||
|
{
|
||||||
|
Slider slider = null;
|
||||||
|
|
||||||
|
AddStep("select first slider", () =>
|
||||||
|
{
|
||||||
|
slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider);
|
||||||
|
EditorClock.Seek(slider.StartTime);
|
||||||
|
EditorBeatmap.SelectedHitObjects.Add(slider);
|
||||||
|
});
|
||||||
|
|
||||||
|
convertToStream();
|
||||||
|
|
||||||
|
AddAssert("stream created", () => streamCreatedFor(slider,
|
||||||
|
(time: 0, pathPosition: 0),
|
||||||
|
(time: 0.25, pathPosition: 0.25),
|
||||||
|
(time: 0.5, pathPosition: 0.5),
|
||||||
|
(time: 0.75, pathPosition: 0.75),
|
||||||
|
(time: 1, pathPosition: 1)));
|
||||||
|
|
||||||
|
AddStep("undo", () => Editor.Undo());
|
||||||
|
AddAssert("slider restored", () => sliderRestored(slider));
|
||||||
|
|
||||||
|
AddStep("select first slider", () =>
|
||||||
|
{
|
||||||
|
slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider);
|
||||||
|
EditorClock.Seek(slider.StartTime);
|
||||||
|
EditorBeatmap.SelectedHitObjects.Add(slider);
|
||||||
|
});
|
||||||
|
AddStep("change beat divisor", () => beatDivisor.Value = 8);
|
||||||
|
|
||||||
|
convertToStream();
|
||||||
|
AddAssert("stream created", () => streamCreatedFor(slider,
|
||||||
|
(time: 0, pathPosition: 0),
|
||||||
|
(time: 0.125, pathPosition: 0.125),
|
||||||
|
(time: 0.25, pathPosition: 0.25),
|
||||||
|
(time: 0.375, pathPosition: 0.375),
|
||||||
|
(time: 0.5, pathPosition: 0.5),
|
||||||
|
(time: 0.625, pathPosition: 0.625),
|
||||||
|
(time: 0.75, pathPosition: 0.75),
|
||||||
|
(time: 0.875, pathPosition: 0.875),
|
||||||
|
(time: 1, pathPosition: 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestConversionWithNonMatchingDivisor()
|
||||||
|
{
|
||||||
|
Slider slider = null;
|
||||||
|
|
||||||
|
AddStep("select second slider", () =>
|
||||||
|
{
|
||||||
|
slider = (Slider)EditorBeatmap.HitObjects.Where(h => h is Slider).ElementAt(1);
|
||||||
|
EditorClock.Seek(slider.StartTime);
|
||||||
|
EditorBeatmap.SelectedHitObjects.Add(slider);
|
||||||
|
});
|
||||||
|
AddStep("change beat divisor", () => beatDivisor.Value = 3);
|
||||||
|
|
||||||
|
convertToStream();
|
||||||
|
|
||||||
|
AddAssert("stream created", () => streamCreatedFor(slider,
|
||||||
|
(time: 0, pathPosition: 0),
|
||||||
|
(time: 2 / 3d, pathPosition: 2 / 3d)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestConversionWithRepeats()
|
||||||
|
{
|
||||||
|
Slider slider = null;
|
||||||
|
|
||||||
|
AddStep("select first slider with repeats", () =>
|
||||||
|
{
|
||||||
|
slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider s && s.RepeatCount > 0);
|
||||||
|
EditorClock.Seek(slider.StartTime);
|
||||||
|
EditorBeatmap.SelectedHitObjects.Add(slider);
|
||||||
|
});
|
||||||
|
AddStep("change beat divisor", () => beatDivisor.Value = 2);
|
||||||
|
|
||||||
|
convertToStream();
|
||||||
|
|
||||||
|
AddAssert("stream created", () => streamCreatedFor(slider,
|
||||||
|
(time: 0, pathPosition: 0),
|
||||||
|
(time: 0.25, pathPosition: 0.5),
|
||||||
|
(time: 0.5, pathPosition: 1),
|
||||||
|
(time: 0.75, pathPosition: 0.5),
|
||||||
|
(time: 1, pathPosition: 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestConversionPreservesSliderProperties()
|
||||||
|
{
|
||||||
|
Slider slider = null;
|
||||||
|
|
||||||
|
AddStep("select second new-combo-starting slider", () =>
|
||||||
|
{
|
||||||
|
slider = (Slider)EditorBeatmap.HitObjects.Where(h => h is Slider s && s.NewCombo).ElementAt(1);
|
||||||
|
EditorClock.Seek(slider.StartTime);
|
||||||
|
EditorBeatmap.SelectedHitObjects.Add(slider);
|
||||||
|
});
|
||||||
|
|
||||||
|
convertToStream();
|
||||||
|
|
||||||
|
AddAssert("stream created", () => streamCreatedFor(slider,
|
||||||
|
(time: 0, pathPosition: 0),
|
||||||
|
(time: 0.25, pathPosition: 0.25),
|
||||||
|
(time: 0.5, pathPosition: 0.5),
|
||||||
|
(time: 0.75, pathPosition: 0.75),
|
||||||
|
(time: 1, pathPosition: 1)));
|
||||||
|
|
||||||
|
AddStep("undo", () => Editor.Undo());
|
||||||
|
AddAssert("slider restored", () => sliderRestored(slider));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertToStream()
|
||||||
|
{
|
||||||
|
AddStep("convert to stream", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.LControl);
|
||||||
|
InputManager.PressKey(Key.LShift);
|
||||||
|
InputManager.Key(Key.F);
|
||||||
|
InputManager.ReleaseKey(Key.LShift);
|
||||||
|
InputManager.ReleaseKey(Key.LControl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool streamCreatedFor(Slider slider, params (double time, double pathPosition)[] expectedCircles)
|
||||||
|
{
|
||||||
|
if (EditorBeatmap.HitObjects.Contains(slider))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach ((double expectedTime, double expectedPathPosition) in expectedCircles)
|
||||||
|
{
|
||||||
|
double time = slider.StartTime + slider.Duration * expectedTime;
|
||||||
|
Vector2 position = slider.Position + slider.Path.PositionAt(expectedPathPosition);
|
||||||
|
|
||||||
|
if (!EditorBeatmap.HitObjects.OfType<HitCircle>().Any(h => matches(h, time, position, slider.NewCombo && expectedTime == 0)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool matches(HitCircle circle, double time, Vector2 position, bool startsNewCombo) =>
|
||||||
|
Precision.AlmostEquals(circle.StartTime, time, 1)
|
||||||
|
&& Precision.AlmostEquals(circle.Position, position, 0.01f)
|
||||||
|
&& circle.NewCombo == startsNewCombo
|
||||||
|
&& circle.Samples.SequenceEqual(slider.HeadCircle.Samples)
|
||||||
|
&& circle.SampleControlPoint.IsRedundant(slider.SampleControlPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool sliderRestored(Slider slider)
|
||||||
|
{
|
||||||
|
var objects = EditorBeatmap.HitObjects.Where(h => h.StartTime >= slider.StartTime && h.GetEndTime() <= slider.EndTime).ToList();
|
||||||
|
|
||||||
|
if (objects.Count > 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var hitObject = objects.Single();
|
||||||
|
if (!(hitObject is Slider restoredSlider))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Precision.AlmostEquals(slider.StartTime, restoredSlider.StartTime)
|
||||||
|
&& Precision.AlmostEquals(slider.GetEndTime(), restoredSlider.GetEndTime())
|
||||||
|
&& Precision.AlmostEquals(slider.Position, restoredSlider.Position, 0.01f)
|
||||||
|
&& Precision.AlmostEquals(slider.EndPosition, restoredSlider.EndPosition, 0.01f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,17 +15,17 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
[TestCase(6.6975550434910005d, "diffcalc-test")]
|
[TestCase(6.6972307565739273d, "diffcalc-test")]
|
||||||
[TestCase(1.4670676815251105d, "zero-length-sliders")]
|
[TestCase(1.4484754139145539d, "zero-length-sliders")]
|
||||||
public void Test(double expected, string name)
|
public void Test(double expected, string name)
|
||||||
=> base.Test(expected, name);
|
=> base.Test(expected, name);
|
||||||
|
|
||||||
[TestCase(8.9389769779826267d, "diffcalc-test")]
|
[TestCase(8.9382559208689809d, "diffcalc-test")]
|
||||||
[TestCase(1.7786917985891204d, "zero-length-sliders")]
|
[TestCase(1.7548875851757628d, "zero-length-sliders")]
|
||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new OsuModDoubleTime());
|
=> Test(expected, name, new OsuModDoubleTime());
|
||||||
|
|
||||||
protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset(), beatmap);
|
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset().RulesetInfo, beatmap);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,77 @@
|
|||||||
// 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 System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Difficulty
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuDifficultyAttributes : DifficultyAttributes
|
public class OsuDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
|
[JsonProperty("aim_strain")]
|
||||||
public double AimStrain { get; set; }
|
public double AimStrain { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("speed_strain")]
|
||||||
public double SpeedStrain { get; set; }
|
public double SpeedStrain { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("flashlight_rating")]
|
||||||
public double FlashlightRating { get; set; }
|
public double FlashlightRating { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("slider_factor")]
|
||||||
|
public double SliderFactor { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("approach_rate")]
|
||||||
public double ApproachRate { get; set; }
|
public double ApproachRate { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("overall_difficulty")]
|
||||||
public double OverallDifficulty { get; set; }
|
public double OverallDifficulty { get; set; }
|
||||||
|
|
||||||
public double DrainRate { get; set; }
|
public double DrainRate { get; set; }
|
||||||
|
|
||||||
public int HitCircleCount { get; set; }
|
public int HitCircleCount { get; set; }
|
||||||
|
|
||||||
public int SliderCount { get; set; }
|
public int SliderCount { get; set; }
|
||||||
|
|
||||||
public int SpinnerCount { get; set; }
|
public int SpinnerCount { get; set; }
|
||||||
|
|
||||||
|
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
|
{
|
||||||
|
foreach (var v in base.ToDatabaseAttributes())
|
||||||
|
yield return v;
|
||||||
|
|
||||||
|
yield return (ATTRIB_ID_AIM, AimStrain);
|
||||||
|
yield return (ATTRIB_ID_SPEED, SpeedStrain);
|
||||||
|
yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
|
||||||
|
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
||||||
|
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
|
yield return (ATTRIB_ID_STRAIN, StarRating);
|
||||||
|
|
||||||
|
if (ShouldSerializeFlashlightRating())
|
||||||
|
yield return (ATTRIB_ID_FLASHLIGHT, FlashlightRating);
|
||||||
|
|
||||||
|
yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
|
||||||
|
{
|
||||||
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
|
AimStrain = values[ATTRIB_ID_AIM];
|
||||||
|
SpeedStrain = values[ATTRIB_ID_SPEED];
|
||||||
|
OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY];
|
||||||
|
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
||||||
|
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
||||||
|
StarRating = values[ATTRIB_ID_STRAIN];
|
||||||
|
FlashlightRating = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
|
||||||
|
SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used implicitly by Newtonsoft.Json to not serialize flashlight property in some cases.
|
||||||
|
[UsedImplicitly]
|
||||||
|
public bool ShouldSerializeFlashlightRating() => Mods.Any(m => m is ModFlashlight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
private const double difficulty_multiplier = 0.0675;
|
private const double difficulty_multiplier = 0.0675;
|
||||||
private double hitWindowGreat;
|
private double hitWindowGreat;
|
||||||
|
|
||||||
public OsuDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -34,8 +34,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
|
return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
|
||||||
|
|
||||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||||
double flashlightRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
|
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
|
||||||
|
double flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;
|
||||||
|
|
||||||
|
double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
|
||||||
|
|
||||||
if (mods.Any(h => h is OsuModRelax))
|
if (mods.Any(h => h is OsuModRelax))
|
||||||
speedRating = 0.0;
|
speedRating = 0.0;
|
||||||
@ -74,6 +77,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
AimStrain = aimRating,
|
AimStrain = aimRating,
|
||||||
SpeedStrain = speedRating,
|
SpeedStrain = speedRating,
|
||||||
FlashlightRating = flashlightRating,
|
FlashlightRating = flashlightRating,
|
||||||
|
SliderFactor = sliderFactor,
|
||||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||||
DrainRate = drainRate,
|
DrainRate = drainRate,
|
||||||
@ -108,7 +112,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
return new Skill[]
|
return new Skill[]
|
||||||
{
|
{
|
||||||
new Aim(mods),
|
new Aim(mods, true),
|
||||||
|
new Aim(mods, false),
|
||||||
new Speed(mods, hitWindowGreat),
|
new Speed(mods, hitWindowGreat),
|
||||||
new Flashlight(mods)
|
new Flashlight(mods)
|
||||||
};
|
};
|
||||||
|
@ -125,6 +125,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);
|
aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We assume 15% of sliders in a map are difficult since there's no way to tell from the performance calculator.
|
||||||
|
double estimateDifficultSliders = Attributes.SliderCount * 0.15;
|
||||||
|
|
||||||
|
if (Attributes.SliderCount > 0)
|
||||||
|
{
|
||||||
|
double estimateSliderEndsDropped = Math.Clamp(Math.Min(countOk + countMeh + countMiss, Attributes.MaxCombo - scoreMaxCombo), 0, estimateDifficultSliders);
|
||||||
|
double sliderNerfFactor = (1 - Attributes.SliderFactor) * Math.Pow(1 - estimateSliderEndsDropped / estimateDifficultSliders, 3) + Attributes.SliderFactor;
|
||||||
|
aimValue *= sliderNerfFactor;
|
||||||
|
}
|
||||||
|
|
||||||
aimValue *= accuracy;
|
aimValue *= accuracy;
|
||||||
// It is important to also consider accuracy difficulty when doing that.
|
// It is important to also consider accuracy difficulty when doing that.
|
||||||
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
|
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||||
private const int min_delta_time = 25;
|
private const int min_delta_time = 25;
|
||||||
private const float maximum_slider_radius = normalized_radius * 2.4f;
|
private const float maximum_slider_radius = normalized_radius * 2.4f;
|
||||||
private const float assumed_slider_radius = normalized_radius * 1.65f;
|
private const float assumed_slider_radius = normalized_radius * 1.8f;
|
||||||
|
|
||||||
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
||||||
|
|
||||||
|
@ -14,11 +14,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Aim : OsuStrainSkill
|
public class Aim : OsuStrainSkill
|
||||||
{
|
{
|
||||||
public Aim(Mod[] mods)
|
public Aim(Mod[] mods, bool withSliders)
|
||||||
: base(mods)
|
: base(mods)
|
||||||
{
|
{
|
||||||
|
this.withSliders = withSliders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly bool withSliders;
|
||||||
|
|
||||||
protected override int HistoryLength => 2;
|
protected override int HistoryLength => 2;
|
||||||
|
|
||||||
private const double wide_angle_multiplier = 1.5;
|
private const double wide_angle_multiplier = 1.5;
|
||||||
@ -44,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
|
double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
|
||||||
|
|
||||||
// But if the last object is a slider, then we extend the travel velocity through the slider into the current object.
|
// But if the last object is a slider, then we extend the travel velocity through the slider into the current object.
|
||||||
if (osuLastObj.BaseObject is Slider)
|
if (osuLastObj.BaseObject is Slider && withSliders)
|
||||||
{
|
{
|
||||||
double movementVelocity = osuCurrObj.MovementDistance / osuCurrObj.MovementTime; // calculate the movement velocity from slider end to current object
|
double movementVelocity = osuCurrObj.MovementDistance / osuCurrObj.MovementTime; // calculate the movement velocity from slider end to current object
|
||||||
double travelVelocity = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // calculate the slider velocity from slider head to slider end.
|
double travelVelocity = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // calculate the slider velocity from slider head to slider end.
|
||||||
@ -55,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
// As above, do the same for the previous hitobject.
|
// As above, do the same for the previous hitobject.
|
||||||
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
|
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
|
||||||
|
|
||||||
if (osuLastLastObj.BaseObject is Slider)
|
if (osuLastLastObj.BaseObject is Slider && withSliders)
|
||||||
{
|
{
|
||||||
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
|
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
|
||||||
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
||||||
@ -135,7 +138,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
|
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
|
||||||
|
|
||||||
// Add in additional slider velocity bonus.
|
// Add in additional slider velocity bonus.
|
||||||
aimStrain += sliderBonus * slider_multiplier;
|
if (withSliders)
|
||||||
|
aimStrain += sliderBonus * slider_multiplier;
|
||||||
|
|
||||||
return aimStrain;
|
return aimStrain;
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,12 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||||
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;
|
||||||
@ -47,6 +50,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IEditorChangeHandler changeHandler { get; set; }
|
private IEditorChangeHandler changeHandler { get; set; }
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private BindableBeatDivisor beatDivisor { get; set; }
|
||||||
|
|
||||||
public override Quad SelectionQuad => BodyPiece.ScreenSpaceDrawQuad;
|
public override Quad SelectionQuad => BodyPiece.ScreenSpaceDrawQuad;
|
||||||
|
|
||||||
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
|
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
|
||||||
@ -173,6 +179,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
|
{
|
||||||
|
if (!IsSelected)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (e.Key == Key.F && e.ControlPressed && e.ShiftPressed)
|
||||||
|
{
|
||||||
|
convertToStream();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private int addControlPoint(Vector2 position)
|
private int addControlPoint(Vector2 position)
|
||||||
{
|
{
|
||||||
position -= HitObject.Position;
|
position -= HitObject.Position;
|
||||||
@ -234,9 +254,56 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
editorBeatmap?.Update(HitObject);
|
editorBeatmap?.Update(HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void convertToStream()
|
||||||
|
{
|
||||||
|
if (editorBeatmap == null || changeHandler == null || beatDivisor == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(HitObject.StartTime);
|
||||||
|
double streamSpacing = timingPoint.BeatLength / beatDivisor.Value;
|
||||||
|
|
||||||
|
changeHandler.BeginChange();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
double time = HitObject.StartTime;
|
||||||
|
|
||||||
|
while (!Precision.DefinitelyBigger(time, HitObject.GetEndTime(), 1))
|
||||||
|
{
|
||||||
|
// positionWithRepeats is a fractional number in the range of [0, HitObject.SpanCount()]
|
||||||
|
// and indicates how many fractional spans of a slider have passed up to time.
|
||||||
|
double positionWithRepeats = (time - HitObject.StartTime) / HitObject.Duration * HitObject.SpanCount();
|
||||||
|
double pathPosition = positionWithRepeats - (int)positionWithRepeats;
|
||||||
|
// every second span is in the reverse direction - need to reverse the path position.
|
||||||
|
if (Precision.AlmostBigger(positionWithRepeats % 2, 1))
|
||||||
|
pathPosition = 1 - pathPosition;
|
||||||
|
|
||||||
|
Vector2 position = HitObject.Position + HitObject.Path.PositionAt(pathPosition);
|
||||||
|
|
||||||
|
var samplePoint = (SampleControlPoint)HitObject.SampleControlPoint.DeepClone();
|
||||||
|
samplePoint.Time = time;
|
||||||
|
|
||||||
|
editorBeatmap.Add(new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = time,
|
||||||
|
Position = position,
|
||||||
|
NewCombo = i == 0 && HitObject.NewCombo,
|
||||||
|
SampleControlPoint = samplePoint,
|
||||||
|
Samples = HitObject.HeadCircle.Samples.Select(s => s.With()).ToList()
|
||||||
|
});
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
time = HitObject.StartTime + i * streamSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
editorBeatmap.Remove(HitObject);
|
||||||
|
|
||||||
|
changeHandler.EndChange();
|
||||||
|
}
|
||||||
|
|
||||||
public override MenuItem[] ContextMenuItems => new MenuItem[]
|
public override MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
{
|
{
|
||||||
new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)),
|
new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)),
|
||||||
|
new OsuMenuItem("Convert to stream", MenuItemType.Destructive, convertToStream),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Always refer to the drawable object's slider body so subsequent movement deltas are calculated with updated positions.
|
// Always refer to the drawable object's slider body so subsequent movement deltas are calculated with updated positions.
|
||||||
|
@ -208,7 +208,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetOsu };
|
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetOsu };
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new OsuPerformanceCalculator(this, attributes, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new OsuPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
var controlPointInfo = new ControlPointInfo();
|
var controlPointInfo = new ControlPointInfo();
|
||||||
controlPointInfo.Add(0, new TimingControlPoint());
|
controlPointInfo.Add(0, new TimingControlPoint());
|
||||||
|
|
||||||
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new TaikoModDoubleTime());
|
=> Test(expected, name, new TaikoModDoubleTime());
|
||||||
|
|
||||||
protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(new TaikoRuleset(), beatmap);
|
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new TaikoDifficultyCalculator(new TaikoRuleset().RulesetInfo, beatmap);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new TaikoRuleset();
|
protected override Ruleset CreateRuleset() => new TaikoRuleset();
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,46 @@
|
|||||||
// 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 Newtonsoft.Json;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Difficulty
|
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||||
{
|
{
|
||||||
public class TaikoDifficultyAttributes : DifficultyAttributes
|
public class TaikoDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
|
[JsonProperty("stamina_strain")]
|
||||||
public double StaminaStrain { get; set; }
|
public double StaminaStrain { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("rhythm_strain")]
|
||||||
public double RhythmStrain { get; set; }
|
public double RhythmStrain { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("colour_strain")]
|
||||||
public double ColourStrain { get; set; }
|
public double ColourStrain { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("approach_rate")]
|
||||||
public double ApproachRate { get; set; }
|
public double ApproachRate { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("great_hit_window")]
|
||||||
public double GreatHitWindow { get; set; }
|
public double GreatHitWindow { get; set; }
|
||||||
|
|
||||||
|
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
|
{
|
||||||
|
foreach (var v in base.ToDatabaseAttributes())
|
||||||
|
yield return v;
|
||||||
|
|
||||||
|
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
|
yield return (ATTRIB_ID_STRAIN, StarRating);
|
||||||
|
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
|
||||||
|
{
|
||||||
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
|
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
||||||
|
StarRating = values[ATTRIB_ID_STRAIN];
|
||||||
|
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private const double colour_skill_multiplier = 0.01;
|
private const double colour_skill_multiplier = 0.01;
|
||||||
private const double stamina_skill_multiplier = 0.02;
|
private const double stamina_skill_multiplier = 0.02;
|
||||||
|
|
||||||
public TaikoDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new TaikoHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new TaikoHitObjectComposer(this);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new TaikoDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new TaikoPerformanceCalculator(this, attributes, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new TaikoPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
|
@ -116,8 +116,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual("Insane", beatmapInfo.DifficultyName);
|
Assert.AreEqual("Insane", beatmapInfo.DifficultyName);
|
||||||
Assert.AreEqual(string.Empty, metadata.Source);
|
Assert.AreEqual(string.Empty, metadata.Source);
|
||||||
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
|
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
|
||||||
Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID);
|
Assert.AreEqual(557821, beatmapInfo.OnlineID);
|
||||||
Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID);
|
Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
var beatmap = decodeAsJson(normal);
|
var beatmap = decodeAsJson(normal);
|
||||||
var meta = beatmap.BeatmapInfo.Metadata;
|
var meta = beatmap.BeatmapInfo.Metadata;
|
||||||
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
|
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
|
||||||
Assert.AreEqual("Soleily", meta.Artist);
|
Assert.AreEqual("Soleily", meta.Artist);
|
||||||
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
||||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||||
|
@ -18,6 +18,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -387,6 +388,41 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestModelCreationFailureDoesntReturn()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
var importer = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var progressNotification = new ImportProgressNotification();
|
||||||
|
|
||||||
|
var zipStream = new MemoryStream();
|
||||||
|
|
||||||
|
using (var zip = ZipArchive.Create())
|
||||||
|
zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate));
|
||||||
|
|
||||||
|
var imported = await importer.Import(
|
||||||
|
progressNotification,
|
||||||
|
new ImportTask(zipStream, string.Empty)
|
||||||
|
);
|
||||||
|
|
||||||
|
checkBeatmapSetCount(osu, 0);
|
||||||
|
checkBeatmapCount(osu, 0);
|
||||||
|
|
||||||
|
Assert.IsEmpty(imported);
|
||||||
|
Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task TestRollbackOnFailure()
|
public async Task TestRollbackOnFailure()
|
||||||
{
|
{
|
||||||
@ -506,7 +542,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
|
|
||||||
foreach (var b in imported.Beatmaps)
|
foreach (var b in imported.Beatmaps)
|
||||||
b.OnlineBeatmapID = null;
|
b.OnlineID = null;
|
||||||
|
|
||||||
osu.Dependencies.Get<BeatmapManager>().Update(imported);
|
osu.Dependencies.Get<BeatmapManager>().Update(imported);
|
||||||
|
|
||||||
@ -545,19 +581,19 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var toImport = new BeatmapSetInfo
|
var toImport = new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1,
|
OnlineID = 1,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
Beatmaps = new List<BeatmapInfo>
|
Beatmaps = new List<BeatmapInfo>
|
||||||
{
|
{
|
||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = 2,
|
OnlineID = 2,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = difficulty
|
BaseDifficulty = difficulty
|
||||||
},
|
},
|
||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = 2,
|
OnlineID = 2,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
Status = BeatmapSetOnlineStatus.Loved,
|
Status = BeatmapSetOnlineStatus.Loved,
|
||||||
BaseDifficulty = difficulty
|
BaseDifficulty = difficulty
|
||||||
@ -570,8 +606,8 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
var imported = await manager.Import(toImport);
|
var imported = await manager.Import(toImport);
|
||||||
|
|
||||||
Assert.NotNull(imported);
|
Assert.NotNull(imported);
|
||||||
Assert.AreEqual(null, imported.Value.Beatmaps[0].OnlineBeatmapID);
|
Assert.AreEqual(null, imported.Value.Beatmaps[0].OnlineID);
|
||||||
Assert.AreEqual(null, imported.Value.Beatmaps[1].OnlineBeatmapID);
|
Assert.AreEqual(null, imported.Value.Beatmaps[1].OnlineID);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -1020,13 +1056,13 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
{
|
{
|
||||||
IEnumerable<BeatmapSetInfo> resultSets = null;
|
IEnumerable<BeatmapSetInfo> resultSets = null;
|
||||||
var store = osu.Dependencies.Get<BeatmapManager>();
|
var store = osu.Dependencies.Get<BeatmapManager>();
|
||||||
waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any(),
|
waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineID == 241526)).Any(),
|
||||||
@"BeatmapSet did not import to the database in allocated time.", timeout);
|
@"BeatmapSet did not import to the database in allocated time.", timeout);
|
||||||
|
|
||||||
// ensure we were stored to beatmap database backing...
|
// ensure we were stored to beatmap database backing...
|
||||||
Assert.IsTrue(resultSets.Count() == 1, $@"Incorrect result count found ({resultSets.Count()} but should be 1).");
|
Assert.IsTrue(resultSets.Count() == 1, $@"Incorrect result count found ({resultSets.Count()} but should be 1).");
|
||||||
IEnumerable<BeatmapInfo> queryBeatmaps() => store.QueryBeatmaps(s => s.BeatmapSet.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0);
|
IEnumerable<BeatmapInfo> queryBeatmaps() => store.QueryBeatmaps(s => s.BeatmapSet.OnlineID == 241526 && s.BaseDifficultyID > 0);
|
||||||
IEnumerable<BeatmapSetInfo> queryBeatmapSets() => store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526);
|
IEnumerable<BeatmapSetInfo> queryBeatmapSets() => store.QueryBeatmapSets(s => s.OnlineID == 241526);
|
||||||
|
|
||||||
// if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
|
// if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
|
||||||
waitForOrAssert(() => queryBeatmaps().Count() == 12,
|
waitForOrAssert(() => queryBeatmaps().Count() == 12,
|
||||||
@ -1042,7 +1078,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var set = queryBeatmapSets().First();
|
var set = queryBeatmapSets().First();
|
||||||
foreach (BeatmapInfo b in set.Beatmaps)
|
foreach (BeatmapInfo b in set.Beatmaps)
|
||||||
Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineBeatmapID == b.OnlineBeatmapID));
|
Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
|
||||||
Assert.IsTrue(set.Beatmaps.Count > 0);
|
Assert.IsTrue(set.Beatmaps.Count > 0);
|
||||||
var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
||||||
Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var meta = beatmap.Metadata;
|
var meta = beatmap.Metadata;
|
||||||
|
|
||||||
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
|
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
|
||||||
Assert.AreEqual("Soleily", meta.Artist);
|
Assert.AreEqual("Soleily", meta.Artist);
|
||||||
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
||||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||||
|
114
osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs
Normal file
114
osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// 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 System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Beatmaps
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class WorkingBeatmapTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestGetPlayableSuccess()
|
||||||
|
{
|
||||||
|
var working = new TestNeverLoadsWorkingBeatmap();
|
||||||
|
|
||||||
|
working.ResetEvent.Set();
|
||||||
|
|
||||||
|
Assert.NotNull(working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGetPlayableCancellationToken()
|
||||||
|
{
|
||||||
|
var working = new TestNeverLoadsWorkingBeatmap();
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
var loadStarted = new ManualResetEventSlim();
|
||||||
|
var loadCompleted = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
Task.Factory.StartNew(() =>
|
||||||
|
{
|
||||||
|
loadStarted.Set();
|
||||||
|
Assert.Throws<OperationCanceledException>(() => working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, cancellationToken: cts.Token));
|
||||||
|
loadCompleted.Set();
|
||||||
|
}, TaskCreationOptions.LongRunning);
|
||||||
|
|
||||||
|
Assert.IsTrue(loadStarted.Wait(10000));
|
||||||
|
|
||||||
|
cts.Cancel();
|
||||||
|
|
||||||
|
Assert.IsTrue(loadCompleted.Wait(10000));
|
||||||
|
|
||||||
|
working.ResetEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGetPlayableDefaultTimeout()
|
||||||
|
{
|
||||||
|
var working = new TestNeverLoadsWorkingBeatmap();
|
||||||
|
|
||||||
|
Assert.Throws<OperationCanceledException>(() => working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo));
|
||||||
|
|
||||||
|
working.ResetEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGetPlayableRulesetLoadFailure()
|
||||||
|
{
|
||||||
|
var working = new TestWorkingBeatmap(new Beatmap());
|
||||||
|
|
||||||
|
// by default mocks return nulls if not set up, which is actually desired here to simulate a ruleset load failure scenario.
|
||||||
|
var ruleset = new Mock<IRulesetInfo>();
|
||||||
|
|
||||||
|
Assert.Throws<RulesetLoadException>(() => working.GetPlayableBeatmap(ruleset.Object));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestNeverLoadsWorkingBeatmap : TestWorkingBeatmap
|
||||||
|
{
|
||||||
|
public ManualResetEventSlim ResetEvent = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
public TestNeverLoadsWorkingBeatmap()
|
||||||
|
: base(new Beatmap())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => new TestConverter(beatmap, ResetEvent);
|
||||||
|
|
||||||
|
public class TestConverter : IBeatmapConverter
|
||||||
|
{
|
||||||
|
private readonly ManualResetEventSlim resetEvent;
|
||||||
|
|
||||||
|
public TestConverter(IBeatmap beatmap, ManualResetEventSlim resetEvent)
|
||||||
|
{
|
||||||
|
this.resetEvent = resetEvent;
|
||||||
|
Beatmap = beatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
|
||||||
|
|
||||||
|
protected virtual void OnObjectConverted(HitObject arg1, IEnumerable<HitObject> arg2) => ObjectConverted?.Invoke(arg1, arg2);
|
||||||
|
|
||||||
|
public IBeatmap Beatmap { get; }
|
||||||
|
|
||||||
|
public bool CanConvert() => true;
|
||||||
|
|
||||||
|
public IBeatmap Convert(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
resetEvent.Wait(cancellationToken);
|
||||||
|
return new OsuBeatmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Stores;
|
using osu.Game.Stores;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
using Realms;
|
using Realms;
|
||||||
@ -367,6 +368,34 @@ namespace osu.Game.Tests.Database
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestModelCreationFailureDoesntReturn()
|
||||||
|
{
|
||||||
|
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
||||||
|
{
|
||||||
|
using var importer = new BeatmapImporter(realmFactory, storage);
|
||||||
|
using var store = new RealmRulesetStore(realmFactory, storage);
|
||||||
|
|
||||||
|
var progressNotification = new ImportProgressNotification();
|
||||||
|
|
||||||
|
var zipStream = new MemoryStream();
|
||||||
|
|
||||||
|
using (var zip = ZipArchive.Create())
|
||||||
|
zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate));
|
||||||
|
|
||||||
|
var imported = await importer.Import(
|
||||||
|
progressNotification,
|
||||||
|
new ImportTask(zipStream, string.Empty)
|
||||||
|
);
|
||||||
|
|
||||||
|
checkBeatmapSetCount(realmFactory.Context, 0);
|
||||||
|
checkBeatmapCount(realmFactory.Context, 0);
|
||||||
|
|
||||||
|
Assert.IsEmpty(imported);
|
||||||
|
Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRollbackOnFailure()
|
public void TestRollbackOnFailure()
|
||||||
{
|
{
|
||||||
|
@ -10,19 +10,28 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace osu.Game.Tests.Models
|
namespace osu.Game.Tests.Models
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class DisplayStringTest
|
public class DisplayStringTest
|
||||||
{
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestNull()
|
||||||
|
{
|
||||||
|
IBeatmapSetInfo? beatmap = null;
|
||||||
|
Assert.That(beatmap.GetDisplayString(), Is.EqualTo("null"));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBeatmapSet()
|
public void TestBeatmapSet()
|
||||||
{
|
{
|
||||||
var mock = new Mock<IBeatmapSetInfo>();
|
var mock = new Mock<IBeatmapSetInfo>();
|
||||||
|
|
||||||
mock.Setup(m => m.Metadata.Artist).Returns("artist");
|
mock.Setup(m => m.Metadata!.Artist).Returns("artist");
|
||||||
mock.Setup(m => m.Metadata.Title).Returns("title");
|
mock.Setup(m => m.Metadata!.Title).Returns("title");
|
||||||
mock.Setup(m => m.Metadata.Author.Username).Returns("author");
|
mock.Setup(m => m.Metadata!.Author.Username).Returns("author");
|
||||||
|
|
||||||
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title (author)"));
|
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title (author)"));
|
||||||
}
|
}
|
||||||
@ -32,9 +41,9 @@ namespace osu.Game.Tests.Models
|
|||||||
{
|
{
|
||||||
var mock = new Mock<IBeatmapSetInfo>();
|
var mock = new Mock<IBeatmapSetInfo>();
|
||||||
|
|
||||||
mock.Setup(m => m.Metadata.Artist).Returns("artist");
|
mock.Setup(m => m.Metadata!.Artist).Returns("artist");
|
||||||
mock.Setup(m => m.Metadata.Title).Returns("title");
|
mock.Setup(m => m.Metadata!.Title).Returns("title");
|
||||||
mock.Setup(m => m.Metadata.Author.Username).Returns(string.Empty);
|
mock.Setup(m => m.Metadata!.Author.Username).Returns(string.Empty);
|
||||||
|
|
||||||
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title"));
|
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title"));
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ namespace osu.Game.Tests.Mods
|
|||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap)
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Extensions;
|
||||||
|
|
||||||
namespace osu.Game.Tests.NonVisual
|
namespace osu.Game.Tests.NonVisual
|
||||||
{
|
{
|
||||||
@ -12,10 +13,11 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestOnlineWithOnline()
|
public void TestOnlineWithOnline()
|
||||||
{
|
{
|
||||||
var ourInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
|
var ourInfo = new BeatmapSetInfo { OnlineID = 123 };
|
||||||
var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
|
var otherInfo = new BeatmapSetInfo { OnlineID = 123 };
|
||||||
|
|
||||||
Assert.AreEqual(ourInfo, otherInfo);
|
Assert.AreNotEqual(ourInfo, otherInfo);
|
||||||
|
Assert.IsTrue(ourInfo.MatchesOnlineID(otherInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -30,10 +32,11 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDatabasedWithOnline()
|
public void TestDatabasedWithOnline()
|
||||||
{
|
{
|
||||||
var ourInfo = new BeatmapSetInfo { ID = 123, OnlineBeatmapSetID = 12 };
|
var ourInfo = new BeatmapSetInfo { ID = 123, OnlineID = 12 };
|
||||||
var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 12 };
|
var otherInfo = new BeatmapSetInfo { OnlineID = 12 };
|
||||||
|
|
||||||
Assert.AreEqual(ourInfo, otherInfo);
|
Assert.AreNotEqual(ourInfo, otherInfo);
|
||||||
|
Assert.IsTrue(ourInfo.MatchesOnlineID(otherInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -207,8 +207,8 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
public void TestCriteriaMatchingBeatmapIDs(string query, bool filtered)
|
public void TestCriteriaMatchingBeatmapIDs(string query, bool filtered)
|
||||||
{
|
{
|
||||||
var beatmap = getExampleBeatmap();
|
var beatmap = getExampleBeatmap();
|
||||||
beatmap.OnlineBeatmapID = 20201010;
|
beatmap.OnlineID = 20201010;
|
||||||
beatmap.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = 1535 };
|
beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
|
||||||
|
|
||||||
var criteria = new FilterCriteria { SearchText = query };
|
var criteria = new FilterCriteria { SearchText = query };
|
||||||
var carouselItem = new CarouselBeatmap(beatmap);
|
var carouselItem = new CarouselBeatmap(beatmap);
|
||||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override string Description { get; } = string.Empty;
|
public override string Description { get; } = string.Empty;
|
||||||
public override string ShortName { get; } = string.Empty;
|
public override string ShortName { get; } = string.Empty;
|
||||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException();
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new System.NotImplementedException();
|
||||||
|
|
||||||
public override string Description { get; } = string.Empty;
|
public override string Description { get; } = string.Empty;
|
||||||
public override string ShortName { get; } = string.Empty;
|
public override string ShortName { get; } = string.Empty;
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
private static readonly BeatmapSetInfo test_db_model = new BeatmapSetInfo
|
private static readonly BeatmapSetInfo test_db_model = new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1,
|
OnlineID = 1,
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
Artist = "test author",
|
Artist = "test author",
|
||||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Online
|
|||||||
testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile);
|
testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile);
|
||||||
testBeatmapSet = testBeatmapInfo.BeatmapSet;
|
testBeatmapSet = testBeatmapInfo.BeatmapSet;
|
||||||
|
|
||||||
var existing = beatmaps.QueryBeatmapSet(s => s.OnlineBeatmapSetID == testBeatmapSet.OnlineBeatmapSetID);
|
var existing = beatmaps.QueryBeatmapSet(s => s.OnlineID == testBeatmapSet.OnlineID);
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
beatmaps.Delete(existing);
|
beatmaps.Delete(existing);
|
||||||
|
|
||||||
@ -101,10 +101,10 @@ namespace osu.Game.Tests.Online
|
|||||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).Wait());
|
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).Wait());
|
||||||
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
||||||
|
|
||||||
AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == testBeatmapSet.OnlineBeatmapSetID)));
|
AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
|
||||||
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
|
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
|
||||||
|
|
||||||
AddStep("undelete beatmap", () => beatmaps.Undelete(beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == testBeatmapSet.OnlineBeatmapSetID)));
|
AddStep("undelete beatmap", () => beatmaps.Undelete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
|
||||||
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Skins
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
private WorkingBeatmap beatmap;
|
private IWorkingBeatmap beatmap;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -79,7 +79,7 @@ namespace osu.Game.Tests.Testing
|
|||||||
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
|
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => null;
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => null;
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null;
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null;
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => null;
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestRulesetConfigManager : IRulesetConfigManager
|
private class TestRulesetConfigManager : IRulesetConfigManager
|
||||||
|
@ -428,7 +428,7 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
|
|
||||||
public float CurrentDim => dimmable.DimLevel;
|
public float CurrentDim => dimmable.DimLevel;
|
||||||
|
|
||||||
public Vector2 CurrentBlur => Background.BlurSigma;
|
public Vector2 CurrentBlur => Background?.BlurSigma ?? Vector2.Zero;
|
||||||
|
|
||||||
private TestDimmableBackground dimmable;
|
private TestDimmableBackground dimmable;
|
||||||
|
|
||||||
|
192
osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
Normal file
192
osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.Backgrounds;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||||
|
using osu.Game.Screens.Edit.GameplayTest;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
public class TestSceneEditorTestGameplay : EditorTestScene
|
||||||
|
{
|
||||||
|
protected override bool IsolateSavingFromDatabase => false;
|
||||||
|
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuGameBase game { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
|
private BeatmapSetInfo importedBeatmapSet;
|
||||||
|
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game).Result);
|
||||||
|
base.SetUpSteps();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadEditor()
|
||||||
|
{
|
||||||
|
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
|
||||||
|
base.LoadEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBasicGameplayTest()
|
||||||
|
{
|
||||||
|
AddStep("click test gameplay button", () =>
|
||||||
|
{
|
||||||
|
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
EditorPlayer editorPlayer = null;
|
||||||
|
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
|
||||||
|
AddStep("exit player", () => editorPlayer.Exit());
|
||||||
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
||||||
|
AddUntilStep("background has correct params", () =>
|
||||||
|
{
|
||||||
|
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single();
|
||||||
|
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayTestWhenTrackRunning()
|
||||||
|
{
|
||||||
|
AddStep("start track", () => EditorClock.Start());
|
||||||
|
AddAssert("sample playback enabled", () => !Editor.SamplePlaybackDisabled.Value);
|
||||||
|
|
||||||
|
AddStep("click test gameplay button", () =>
|
||||||
|
{
|
||||||
|
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
EditorPlayer editorPlayer = null;
|
||||||
|
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
|
||||||
|
AddAssert("editor track stopped", () => !EditorClock.IsRunning);
|
||||||
|
AddAssert("sample playback disabled", () => Editor.SamplePlaybackDisabled.Value);
|
||||||
|
|
||||||
|
AddStep("exit player", () => editorPlayer.Exit());
|
||||||
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
||||||
|
AddUntilStep("background has correct params", () =>
|
||||||
|
{
|
||||||
|
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single();
|
||||||
|
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("start track", () => EditorClock.Start());
|
||||||
|
AddAssert("sample playback re-enabled", () => !Editor.SamplePlaybackDisabled.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCancelGameplayTestWithUnsavedChanges()
|
||||||
|
{
|
||||||
|
AddStep("delete all but first object", () => EditorBeatmap.RemoveRange(EditorBeatmap.HitObjects.Skip(1).ToList()));
|
||||||
|
|
||||||
|
AddStep("click test gameplay button", () =>
|
||||||
|
{
|
||||||
|
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveBeforeGameplayTestDialog);
|
||||||
|
|
||||||
|
AddStep("dismiss prompt", () =>
|
||||||
|
{
|
||||||
|
var button = DialogOverlay.CurrentDialog.Buttons.Last();
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddWaitStep("wait some", 3);
|
||||||
|
AddAssert("stayed in editor", () => Stack.CurrentScreen is Editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSaveChangesBeforeGameplayTest()
|
||||||
|
{
|
||||||
|
AddStep("delete all but first object", () => EditorBeatmap.RemoveRange(EditorBeatmap.HitObjects.Skip(1).ToList()));
|
||||||
|
// bit of a hack to ensure this test can be ran multiple times without running into UNIQUE constraint failures
|
||||||
|
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = Guid.NewGuid().ToString());
|
||||||
|
|
||||||
|
AddStep("click test gameplay button", () =>
|
||||||
|
{
|
||||||
|
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveBeforeGameplayTestDialog);
|
||||||
|
|
||||||
|
AddStep("save changes", () => DialogOverlay.CurrentDialog.PerformOkAction());
|
||||||
|
|
||||||
|
EditorPlayer editorPlayer = null;
|
||||||
|
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
|
||||||
|
AddAssert("beatmap has 1 object", () => editorPlayer.Beatmap.Value.Beatmap.HitObjects.Count == 1);
|
||||||
|
|
||||||
|
AddUntilStep("wait for return to editor", () => Stack.CurrentScreen is Editor);
|
||||||
|
AddAssert("track stopped", () => !Beatmap.Value.Track.IsRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSharedClockState()
|
||||||
|
{
|
||||||
|
AddStep("seek to 00:01:00", () => EditorClock.Seek(60_000));
|
||||||
|
AddStep("click test gameplay button", () =>
|
||||||
|
{
|
||||||
|
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
EditorPlayer editorPlayer = null;
|
||||||
|
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
|
||||||
|
|
||||||
|
GameplayClockContainer gameplayClockContainer = null;
|
||||||
|
AddStep("fetch gameplay clock", () => gameplayClockContainer = editorPlayer.ChildrenOfType<GameplayClockContainer>().First());
|
||||||
|
AddUntilStep("gameplay clock running", () => gameplayClockContainer.IsRunning);
|
||||||
|
AddAssert("gameplay time past 00:01:00", () => gameplayClockContainer.CurrentTime >= 60_000);
|
||||||
|
|
||||||
|
double timeAtPlayerExit = 0;
|
||||||
|
AddWaitStep("wait some", 5);
|
||||||
|
AddStep("store time before exit", () => timeAtPlayerExit = gameplayClockContainer.CurrentTime);
|
||||||
|
|
||||||
|
AddStep("exit player", () => editorPlayer.Exit());
|
||||||
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
||||||
|
AddAssert("time is past player exit", () => EditorClock.CurrentTime >= timeAtPlayerExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TearDownSteps()
|
||||||
|
{
|
||||||
|
base.TearDownSteps();
|
||||||
|
AddStep("delete imported", () =>
|
||||||
|
{
|
||||||
|
beatmaps.Delete(importedBeatmapSet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -81,11 +81,11 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
public class EditorBeatmapContainer : Container
|
public class EditorBeatmapContainer : Container
|
||||||
{
|
{
|
||||||
private readonly WorkingBeatmap working;
|
private readonly IWorkingBeatmap working;
|
||||||
|
|
||||||
public EditorBeatmap EditorBeatmap { get; private set; }
|
public EditorBeatmap EditorBeatmap { get; private set; }
|
||||||
|
|
||||||
public EditorBeatmapContainer(WorkingBeatmap working)
|
public EditorBeatmapContainer(IWorkingBeatmap working)
|
||||||
{
|
{
|
||||||
this.working = working;
|
this.working = working;
|
||||||
|
|
||||||
|
@ -0,0 +1,171 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
|
using osu.Game.Screens.Edit.Timing;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
public class TestSceneHitObjectDifficultyPointAdjustments : EditorTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
||||||
|
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
base.SetUpSteps();
|
||||||
|
|
||||||
|
AddStep("add test objects", () =>
|
||||||
|
{
|
||||||
|
EditorBeatmap.Add(new Slider
|
||||||
|
{
|
||||||
|
StartTime = 0,
|
||||||
|
Position = (OsuPlayfield.BASE_SIZE - new Vector2(0, 100)) / 2,
|
||||||
|
Path = new SliderPath
|
||||||
|
{
|
||||||
|
ControlPoints =
|
||||||
|
{
|
||||||
|
new PathControlPoint(new Vector2(0, 0)),
|
||||||
|
new PathControlPoint(new Vector2(0, 100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
EditorBeatmap.Add(new Slider
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = (OsuPlayfield.BASE_SIZE - new Vector2(100, 0)) / 2,
|
||||||
|
Path = new SliderPath
|
||||||
|
{
|
||||||
|
ControlPoints =
|
||||||
|
{
|
||||||
|
new PathControlPoint(new Vector2(0, 0)),
|
||||||
|
new PathControlPoint(new Vector2(100, 0))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DifficultyControlPoint = new DifficultyControlPoint
|
||||||
|
{
|
||||||
|
SliderVelocity = 2
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleSelection()
|
||||||
|
{
|
||||||
|
clickDifficultyPiece(0);
|
||||||
|
velocityPopoverHasSingleValue(1);
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
// select first object to ensure that difficulty pieces for unselected objects
|
||||||
|
// work independently from selection state.
|
||||||
|
AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.First()));
|
||||||
|
|
||||||
|
clickDifficultyPiece(1);
|
||||||
|
velocityPopoverHasSingleValue(2);
|
||||||
|
|
||||||
|
setVelocityViaPopover(5);
|
||||||
|
hitObjectHasVelocity(1, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleSelectionWithSameSliderVelocity()
|
||||||
|
{
|
||||||
|
AddStep("unify slider velocity", () =>
|
||||||
|
{
|
||||||
|
foreach (var h in EditorBeatmap.HitObjects)
|
||||||
|
h.DifficultyControlPoint.SliderVelocity = 1.5;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
clickDifficultyPiece(0);
|
||||||
|
velocityPopoverHasSingleValue(1.5);
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
clickDifficultyPiece(1);
|
||||||
|
velocityPopoverHasSingleValue(1.5);
|
||||||
|
|
||||||
|
setVelocityViaPopover(5);
|
||||||
|
hitObjectHasVelocity(0, 5);
|
||||||
|
hitObjectHasVelocity(1, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleSelectionWithDifferentSliderVelocity()
|
||||||
|
{
|
||||||
|
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
clickDifficultyPiece(0);
|
||||||
|
velocityPopoverHasIndeterminateValue();
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
clickDifficultyPiece(1);
|
||||||
|
velocityPopoverHasIndeterminateValue();
|
||||||
|
|
||||||
|
setVelocityViaPopover(3);
|
||||||
|
hitObjectHasVelocity(0, 3);
|
||||||
|
hitObjectHasVelocity(1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickDifficultyPiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} difficulty piece", () =>
|
||||||
|
{
|
||||||
|
var difficultyPiece = this.ChildrenOfType<DifficultyPointPiece>().Single(piece => piece.HitObject == EditorBeatmap.HitObjects.ElementAt(objectIndex));
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(difficultyPiece);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void velocityPopoverHasSingleValue(double velocity) => AddUntilStep($"velocity popover has {velocity}", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<DifficultyPointPiece.DifficultyEditPopover>().SingleOrDefault();
|
||||||
|
var slider = popover?.ChildrenOfType<IndeterminateSliderWithTextBoxInput<double>>().Single();
|
||||||
|
|
||||||
|
return slider?.Current.Value == velocity;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void velocityPopoverHasIndeterminateValue() => AddUntilStep("velocity popover has indeterminate value", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<DifficultyPointPiece.DifficultyEditPopover>().SingleOrDefault();
|
||||||
|
var slider = popover?.ChildrenOfType<IndeterminateSliderWithTextBoxInput<double>>().Single();
|
||||||
|
|
||||||
|
return slider != null && slider.Current.Value == null;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void dismissPopover()
|
||||||
|
{
|
||||||
|
AddStep("dismiss popover", () => InputManager.Key(Key.Escape));
|
||||||
|
AddUntilStep("wait for dismiss", () => !this.ChildrenOfType<DifficultyPointPiece.DifficultyEditPopover>().Any(popover => popover.IsPresent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setVelocityViaPopover(double velocity) => AddStep($"set {velocity} via popover", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<DifficultyPointPiece.DifficultyEditPopover>().Single();
|
||||||
|
var slider = popover.ChildrenOfType<IndeterminateSliderWithTextBoxInput<double>>().Single();
|
||||||
|
slider.Current.Value = velocity;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void hitObjectHasVelocity(int objectIndex, double velocity) => AddAssert($"{objectIndex.ToOrdinalWords()} has velocity {velocity}", () =>
|
||||||
|
{
|
||||||
|
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex);
|
||||||
|
return h.DifficultyControlPoint.SliderVelocity == velocity;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,252 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
|
using osu.Game.Screens.Edit.Timing;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
public class TestSceneHitObjectSamplePointAdjustments : EditorTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
||||||
|
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
base.SetUpSteps();
|
||||||
|
|
||||||
|
AddStep("add test objects", () =>
|
||||||
|
{
|
||||||
|
EditorBeatmap.Add(new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 0,
|
||||||
|
Position = (OsuPlayfield.BASE_SIZE - new Vector2(100, 0)) / 2,
|
||||||
|
SampleControlPoint = new SampleControlPoint
|
||||||
|
{
|
||||||
|
SampleBank = "normal",
|
||||||
|
SampleVolume = 80
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
EditorBeatmap.Add(new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = (OsuPlayfield.BASE_SIZE + new Vector2(100, 0)) / 2,
|
||||||
|
SampleControlPoint = new SampleControlPoint
|
||||||
|
{
|
||||||
|
SampleBank = "soft",
|
||||||
|
SampleVolume = 60
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleSelection()
|
||||||
|
{
|
||||||
|
clickSamplePiece(0);
|
||||||
|
samplePopoverHasSingleBank("normal");
|
||||||
|
samplePopoverHasSingleVolume(80);
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
// select first object to ensure that sample pieces for unselected objects
|
||||||
|
// work independently from selection state.
|
||||||
|
AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.First()));
|
||||||
|
|
||||||
|
clickSamplePiece(1);
|
||||||
|
samplePopoverHasSingleBank("soft");
|
||||||
|
samplePopoverHasSingleVolume(60);
|
||||||
|
|
||||||
|
setVolumeViaPopover(90);
|
||||||
|
hitObjectHasSampleVolume(1, 90);
|
||||||
|
|
||||||
|
setBankViaPopover("drum");
|
||||||
|
hitObjectHasSampleBank(1, "drum");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleSelectionWithSameSampleVolume()
|
||||||
|
{
|
||||||
|
AddStep("unify sample volume", () =>
|
||||||
|
{
|
||||||
|
foreach (var h in EditorBeatmap.HitObjects)
|
||||||
|
h.SampleControlPoint.SampleVolume = 50;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
clickSamplePiece(0);
|
||||||
|
samplePopoverHasSingleVolume(50);
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
clickSamplePiece(1);
|
||||||
|
samplePopoverHasSingleVolume(50);
|
||||||
|
|
||||||
|
setVolumeViaPopover(75);
|
||||||
|
hitObjectHasSampleVolume(0, 75);
|
||||||
|
hitObjectHasSampleVolume(1, 75);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleSelectionWithDifferentSampleVolume()
|
||||||
|
{
|
||||||
|
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
clickSamplePiece(0);
|
||||||
|
samplePopoverHasIndeterminateVolume();
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
clickSamplePiece(1);
|
||||||
|
samplePopoverHasIndeterminateVolume();
|
||||||
|
|
||||||
|
setVolumeViaPopover(30);
|
||||||
|
hitObjectHasSampleVolume(0, 30);
|
||||||
|
hitObjectHasSampleVolume(1, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleSelectionWithSameSampleBank()
|
||||||
|
{
|
||||||
|
AddStep("unify sample bank", () =>
|
||||||
|
{
|
||||||
|
foreach (var h in EditorBeatmap.HitObjects)
|
||||||
|
h.SampleControlPoint.SampleBank = "soft";
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
clickSamplePiece(0);
|
||||||
|
samplePopoverHasSingleBank("soft");
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
clickSamplePiece(1);
|
||||||
|
samplePopoverHasSingleBank("soft");
|
||||||
|
|
||||||
|
setBankViaPopover(string.Empty);
|
||||||
|
hitObjectHasSampleBank(0, "soft");
|
||||||
|
hitObjectHasSampleBank(1, "soft");
|
||||||
|
samplePopoverHasSingleBank("soft");
|
||||||
|
|
||||||
|
setBankViaPopover("drum");
|
||||||
|
hitObjectHasSampleBank(0, "drum");
|
||||||
|
hitObjectHasSampleBank(1, "drum");
|
||||||
|
samplePopoverHasSingleBank("drum");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleSelectionWithDifferentSampleBank()
|
||||||
|
{
|
||||||
|
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
clickSamplePiece(0);
|
||||||
|
samplePopoverHasIndeterminateBank();
|
||||||
|
|
||||||
|
dismissPopover();
|
||||||
|
|
||||||
|
clickSamplePiece(1);
|
||||||
|
samplePopoverHasIndeterminateBank();
|
||||||
|
|
||||||
|
setBankViaPopover(string.Empty);
|
||||||
|
hitObjectHasSampleBank(0, "normal");
|
||||||
|
hitObjectHasSampleBank(1, "soft");
|
||||||
|
samplePopoverHasIndeterminateBank();
|
||||||
|
|
||||||
|
setBankViaPopover("normal");
|
||||||
|
hitObjectHasSampleBank(0, "normal");
|
||||||
|
hitObjectHasSampleBank(1, "normal");
|
||||||
|
samplePopoverHasSingleBank("normal");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickSamplePiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} difficulty piece", () =>
|
||||||
|
{
|
||||||
|
var difficultyPiece = this.ChildrenOfType<SamplePointPiece>().Single(piece => piece.HitObject == EditorBeatmap.HitObjects.ElementAt(objectIndex));
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(difficultyPiece);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void samplePopoverHasSingleVolume(int volume) => AddUntilStep($"sample popover has volume {volume}", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
|
||||||
|
var slider = popover?.ChildrenOfType<IndeterminateSliderWithTextBoxInput<int>>().Single();
|
||||||
|
|
||||||
|
return slider?.Current.Value == volume;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void samplePopoverHasIndeterminateVolume() => AddUntilStep("sample popover has indeterminate volume", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
|
||||||
|
var slider = popover?.ChildrenOfType<IndeterminateSliderWithTextBoxInput<int>>().Single();
|
||||||
|
|
||||||
|
return slider != null && slider.Current.Value == null;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void samplePopoverHasSingleBank(string bank) => AddUntilStep($"sample popover has bank {bank}", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
|
||||||
|
var textBox = popover?.ChildrenOfType<OsuTextBox>().First();
|
||||||
|
|
||||||
|
return textBox?.Current.Value == bank && string.IsNullOrEmpty(textBox?.PlaceholderText.ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
private void samplePopoverHasIndeterminateBank() => AddUntilStep("sample popover has indeterminate bank", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
|
||||||
|
var textBox = popover?.ChildrenOfType<OsuTextBox>().First();
|
||||||
|
|
||||||
|
return textBox != null && string.IsNullOrEmpty(textBox.Current.Value) && !string.IsNullOrEmpty(textBox.PlaceholderText.ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
private void dismissPopover()
|
||||||
|
{
|
||||||
|
AddStep("dismiss popover", () => InputManager.Key(Key.Escape));
|
||||||
|
AddUntilStep("wait for dismiss", () => !this.ChildrenOfType<DifficultyPointPiece.DifficultyEditPopover>().Any(popover => popover.IsPresent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setVolumeViaPopover(int volume) => AddStep($"set volume {volume} via popover", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().Single();
|
||||||
|
var slider = popover.ChildrenOfType<IndeterminateSliderWithTextBoxInput<int>>().Single();
|
||||||
|
slider.Current.Value = volume;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void hitObjectHasSampleVolume(int objectIndex, int volume) => AddAssert($"{objectIndex.ToOrdinalWords()} has volume {volume}", () =>
|
||||||
|
{
|
||||||
|
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex);
|
||||||
|
return h.SampleControlPoint.SampleVolume == volume;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void setBankViaPopover(string bank) => AddStep($"set bank {bank} via popover", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().Single();
|
||||||
|
var textBox = popover.ChildrenOfType<LabelledTextBox>().First();
|
||||||
|
textBox.Current.Value = bank;
|
||||||
|
// force a commit via keyboard.
|
||||||
|
// this is needed when testing attempting to set empty bank - which should revert to the previous value, but only on commit.
|
||||||
|
InputManager.ChangeFocus(textBox);
|
||||||
|
InputManager.Key(Key.Enter);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void hitObjectHasSampleBank(int objectIndex, string bank) => AddAssert($"{objectIndex.ToOrdinalWords()} has bank {bank}", () =>
|
||||||
|
{
|
||||||
|
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex);
|
||||||
|
return h.SampleControlPoint.SampleBank == bank;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -23,6 +24,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Cached(typeof(IBeatSnapProvider))]
|
[Cached(typeof(IBeatSnapProvider))]
|
||||||
private readonly EditorBeatmap editorBeatmap;
|
private readonly EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||||
|
|
||||||
public TestSceneSetupScreen()
|
public TestSceneSetupScreen()
|
||||||
{
|
{
|
||||||
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
@ -18,6 +19,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Cached(typeof(IBeatSnapProvider))]
|
[Cached(typeof(IBeatSnapProvider))]
|
||||||
private readonly EditorBeatmap editorBeatmap;
|
private readonly EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||||
|
|
||||||
protected override bool ScrollUsingMouseWheel => false;
|
protected override bool ScrollUsingMouseWheel => false;
|
||||||
|
|
||||||
public TestSceneTimingScreen()
|
public TestSceneTimingScreen()
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneWaveform : OsuTestScene
|
public class TestSceneWaveform : OsuTestScene
|
||||||
{
|
{
|
||||||
private WorkingBeatmap waveformBeatmap;
|
private IWorkingBeatmap waveformBeatmap;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
|
@ -293,7 +293,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap, null);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap, null);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override string Description { get; } = string.Empty;
|
public override string Description { get; } = string.Empty;
|
||||||
|
|
||||||
|
@ -31,12 +31,18 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||||
AddUntilStep("wait for fail overlay", () => ((FailPlayer)Player).FailOverlay.State.Value == Visibility.Visible);
|
AddUntilStep("wait for fail overlay", () => ((FailPlayer)Player).FailOverlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
// The pause screen and fail animation both ramp frequency.
|
||||||
|
// This tests to ensure that it doesn't reset during that handoff.
|
||||||
|
AddAssert("frequency only ever decreased", () => !((FailPlayer)Player).FrequencyIncreased);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FailPlayer : TestPlayer
|
private class FailPlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new FailOverlay FailOverlay => base.FailOverlay;
|
public new FailOverlay FailOverlay => base.FailOverlay;
|
||||||
|
|
||||||
|
public bool FrequencyIncreased { get; private set; }
|
||||||
|
|
||||||
public FailPlayer()
|
public FailPlayer()
|
||||||
: base(false, false)
|
: base(false, false)
|
||||||
{
|
{
|
||||||
@ -47,6 +53,19 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
HealthProcessor.FailConditions += (_, __) => true;
|
HealthProcessor.FailConditions += (_, __) => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double lastFrequency = double.MaxValue;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
double freq = Beatmap.Value.Track.AggregateFrequency.Value;
|
||||||
|
|
||||||
|
FrequencyIncreased |= freq > lastFrequency;
|
||||||
|
|
||||||
|
lastFrequency = freq;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) =>
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) =>
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
|
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
|
||||||
@ -83,6 +83,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
||||||
{
|
{
|
||||||
|
if (e.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
ReceivedAction = e.Action == TestAction.Down;
|
ReceivedAction = e.Action == TestAction.Down;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +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;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -20,16 +21,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestScenePerformancePointsCounter : OsuTestScene
|
public class TestScenePerformancePointsCounter : OsuTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
private DependencyProvidingContainer dependencyContainer;
|
||||||
private GameplayState gameplayState;
|
|
||||||
|
|
||||||
[Cached]
|
private GameplayState gameplayState;
|
||||||
private ScoreProcessor scoreProcessor;
|
private ScoreProcessor scoreProcessor;
|
||||||
|
|
||||||
private int iteration;
|
private int iteration;
|
||||||
|
private Bindable<JudgementResult> lastJudgementResult = new Bindable<JudgementResult>();
|
||||||
private PerformancePointsCounter counter;
|
private PerformancePointsCounter counter;
|
||||||
|
|
||||||
public TestScenePerformancePointsCounter()
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps() => AddStep("create components", () =>
|
||||||
{
|
{
|
||||||
var ruleset = CreateRuleset();
|
var ruleset = CreateRuleset();
|
||||||
|
|
||||||
@ -38,32 +40,43 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
var beatmap = CreateWorkingBeatmap(ruleset.RulesetInfo)
|
var beatmap = CreateWorkingBeatmap(ruleset.RulesetInfo)
|
||||||
.GetPlayableBeatmap(ruleset.RulesetInfo);
|
.GetPlayableBeatmap(ruleset.RulesetInfo);
|
||||||
|
|
||||||
|
lastJudgementResult = new Bindable<JudgementResult>();
|
||||||
|
|
||||||
gameplayState = new GameplayState(beatmap, ruleset);
|
gameplayState = new GameplayState(beatmap, ruleset);
|
||||||
|
gameplayState.LastJudgementResult.BindTo(lastJudgementResult);
|
||||||
|
|
||||||
scoreProcessor = new ScoreProcessor();
|
scoreProcessor = new ScoreProcessor();
|
||||||
}
|
|
||||||
|
Child = dependencyContainer = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new (Type, object)[]
|
||||||
|
{
|
||||||
|
(typeof(GameplayState), gameplayState),
|
||||||
|
(typeof(ScoreProcessor), scoreProcessor)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
iteration = 0;
|
||||||
|
});
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
[SetUpSteps]
|
private void createCounter() => AddStep("Create counter", () =>
|
||||||
public void SetUpSteps()
|
|
||||||
{
|
{
|
||||||
AddStep("Create counter", () =>
|
dependencyContainer.Child = counter = new PerformancePointsCounter
|
||||||
{
|
{
|
||||||
iteration = 0;
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
Child = counter = new PerformancePointsCounter
|
Scale = new Vector2(5),
|
||||||
{
|
};
|
||||||
Anchor = Anchor.Centre,
|
});
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Scale = new Vector2(5),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBasicCounting()
|
public void TestBasicCounting()
|
||||||
{
|
{
|
||||||
int previousValue = 0;
|
int previousValue = 0;
|
||||||
|
createCounter();
|
||||||
|
|
||||||
AddAssert("counter displaying zero", () => counter.Current.Value == 0);
|
AddAssert("counter displaying zero", () => counter.Current.Value == 0);
|
||||||
|
|
||||||
@ -86,6 +99,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddUntilStep("counter non-zero", () => counter.Current.Value > 0);
|
AddUntilStep("counter non-zero", () => counter.Current.Value > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCounterUpdatesWithJudgementsBeforeCreation()
|
||||||
|
{
|
||||||
|
AddRepeatStep("Add judgement", applyOneJudgement, 10);
|
||||||
|
|
||||||
|
createCounter();
|
||||||
|
|
||||||
|
AddUntilStep("counter non-zero", () => counter.Current.Value > 0);
|
||||||
|
AddUntilStep("counter opaque", () => counter.Child.Alpha == 1);
|
||||||
|
}
|
||||||
|
|
||||||
private void applyOneJudgement()
|
private void applyOneJudgement()
|
||||||
{
|
{
|
||||||
var scoreInfo = gameplayState.Score.ScoreInfo;
|
var scoreInfo = gameplayState.Score.ScoreInfo;
|
||||||
@ -94,13 +118,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
scoreInfo.Accuracy = 1;
|
scoreInfo.Accuracy = 1;
|
||||||
scoreInfo.Statistics[HitResult.Great] = iteration * 1000;
|
scoreInfo.Statistics[HitResult.Great] = iteration * 1000;
|
||||||
|
|
||||||
scoreProcessor.ApplyResult(new OsuJudgementResult(new HitObject
|
lastJudgementResult.Value = new OsuJudgementResult(new HitObject
|
||||||
{
|
{
|
||||||
StartTime = iteration * 10000,
|
StartTime = iteration * 10000,
|
||||||
}, new OsuJudgement())
|
}, new OsuJudgement())
|
||||||
{
|
{
|
||||||
Type = HitResult.Perfect,
|
Type = HitResult.Perfect,
|
||||||
});
|
};
|
||||||
|
scoreProcessor.ApplyResult(lastJudgementResult.Value);
|
||||||
|
|
||||||
iteration++;
|
iteration++;
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private void prepareBeatmap()
|
private void prepareBeatmap()
|
||||||
{
|
{
|
||||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
var workingBeatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
|
workingBeatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
|
||||||
|
Beatmap.Value = workingBeatmap;
|
||||||
|
|
||||||
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
|
||||||
mod.ApplyToTrack(Beatmap.Value.Track);
|
mod.ApplyToTrack(Beatmap.Value.Track);
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers
|
public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers
|
||||||
{
|
{
|
||||||
private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>();
|
private readonly WeakList<IWorkingBeatmap> workingWeakReferences = new WeakList<IWorkingBeatmap>();
|
||||||
|
|
||||||
private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>();
|
private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>();
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
createPlayerTest(false, r =>
|
createPlayerTest(false, r =>
|
||||||
{
|
{
|
||||||
var beatmap = createTestBeatmap(r);
|
var beatmap = createTestBeatmap(r);
|
||||||
beatmap.BeatmapInfo.OnlineBeatmapID = null;
|
beatmap.BeatmapInfo.OnlineID = null;
|
||||||
return beatmap;
|
return beatmap;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override string Description { get; } = string.Empty;
|
public override string Description { get; } = string.Empty;
|
||||||
|
|
||||||
|
@ -231,6 +231,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
||||||
{
|
{
|
||||||
|
if (e.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
box.Colour = Color4.White;
|
box.Colour = Color4.White;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -164,6 +164,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
||||||
{
|
{
|
||||||
|
if (e.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
box.Colour = Color4.White;
|
box.Colour = Color4.White;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("import beatmap", () =>
|
AddStep("import beatmap", () =>
|
||||||
{
|
{
|
||||||
importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
|
importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
|
||||||
importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineBeatmapID ?? -1;
|
importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineID ?? -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +283,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
public bool OnPressed(KeyBindingPressEvent<TestAction> e)
|
||||||
{
|
{
|
||||||
|
if (e.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
box.Colour = Color4.White;
|
box.Colour = Color4.White;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
track.Start();
|
track.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadStoryboard(WorkingBeatmap working)
|
private void loadStoryboard(IWorkingBeatmap working)
|
||||||
{
|
{
|
||||||
if (storyboard != null)
|
if (storyboard != null)
|
||||||
storyboardContainer.Remove(storyboard);
|
storyboardContainer.Remove(storyboard);
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
public void TestMusicNavigationActions()
|
public void TestMusicNavigationActions()
|
||||||
{
|
{
|
||||||
int importId = 0;
|
int importId = 0;
|
||||||
Queue<(WorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
|
Queue<(IWorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
|
||||||
|
|
||||||
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
|
// 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
|
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo
|
||||||
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
|
|
||||||
AddStep("bind to track change", () =>
|
AddStep("bind to track change", () =>
|
||||||
{
|
{
|
||||||
trackChangeQueue = new Queue<(WorkingBeatmap, TrackChangeDirection)>();
|
trackChangeQueue = new Queue<(IWorkingBeatmap, TrackChangeDirection)>();
|
||||||
Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection));
|
Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -67,6 +67,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
|
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMarkInvalid()
|
||||||
|
{
|
||||||
|
createPlaylist(true, true);
|
||||||
|
|
||||||
|
AddStep("mark item 0 as invalid", () => playlist.Items[0].MarkInvalid());
|
||||||
|
|
||||||
|
moveToItem(0);
|
||||||
|
|
||||||
|
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSelectable()
|
public void TestSelectable()
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
importedSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
|
importedSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
|
||||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
||||||
importedBeatmapId = importedBeatmap.OnlineBeatmapID ?? -1;
|
importedBeatmapId = importedBeatmap.OnlineID ?? -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
foreach (int user in users)
|
foreach (int user in users)
|
||||||
{
|
{
|
||||||
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID ?? 0);
|
||||||
multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true));
|
multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
foreach (int user in users)
|
foreach (int user in users)
|
||||||
{
|
{
|
||||||
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID ?? 0);
|
||||||
var roomUser = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true);
|
var roomUser = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true);
|
||||||
|
|
||||||
roomUser.MatchState = new TeamVersusUserState
|
roomUser.MatchState = new TeamVersusUserState
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new BeatmapInfo
|
||||||
{
|
{
|
||||||
Ruleset = rulesets.GetRuleset(i % 4),
|
Ruleset = rulesets.GetRuleset(i % 4),
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineID = beatmapId,
|
||||||
Length = length,
|
Length = length,
|
||||||
BPM = bpm,
|
BPM = bpm,
|
||||||
BaseDifficulty = new BeatmapDifficulty()
|
BaseDifficulty = new BeatmapDifficulty()
|
||||||
@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
manager.Import(new BeatmapSetInfo
|
manager.Import(new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 10,
|
OnlineID = 10,
|
||||||
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
|
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new BeatmapInfo
|
||||||
{
|
{
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineID = beatmapId,
|
||||||
DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||||
Length = length,
|
Length = length,
|
||||||
BPM = bpm,
|
BPM = bpm,
|
||||||
@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
manager.Import(new BeatmapSetInfo
|
manager.Import(new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 10,
|
OnlineID = 10,
|
||||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
|
@ -174,7 +174,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
{
|
{
|
||||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
|
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
|
||||||
PushAndConfirm(() => new TestPlaySongSelect());
|
PushAndConfirm(() => new TestPlaySongSelect());
|
||||||
AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineBeatmapSetID == 241526);
|
AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID == 241526);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DialogBlockingScreen : OsuScreen
|
public class DialogBlockingScreen : OsuScreen
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
@ -107,20 +108,20 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
imported = Game.BeatmapManager.Import(new BeatmapSetInfo
|
imported = Game.BeatmapManager.Import(new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
Hash = Guid.NewGuid().ToString(),
|
Hash = Guid.NewGuid().ToString(),
|
||||||
OnlineBeatmapSetID = i,
|
OnlineID = i,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
Beatmaps = new List<BeatmapInfo>
|
Beatmaps = new List<BeatmapInfo>
|
||||||
{
|
{
|
||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = i * 1024,
|
OnlineID = i * 1024,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = difficulty,
|
BaseDifficulty = difficulty,
|
||||||
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = i * 2048,
|
OnlineID = i * 2048,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = difficulty,
|
BaseDifficulty = difficulty,
|
||||||
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
||||||
@ -139,17 +140,17 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
||||||
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.ID == getImport().ID);
|
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.MatchesOnlineID(getImport()));
|
||||||
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
|
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentSecondDifficultyAndConfirm(Func<BeatmapSetInfo> getImport, int importedID)
|
private void presentSecondDifficultyAndConfirm(Func<BeatmapSetInfo> getImport, int importedID)
|
||||||
{
|
{
|
||||||
Predicate<BeatmapInfo> pred = b => b.OnlineBeatmapID == importedID * 2048;
|
Predicate<BeatmapInfo> pred = b => b.OnlineID == importedID * 2048;
|
||||||
AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred));
|
AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred));
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
||||||
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID * 2048);
|
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID == importedID * 2048);
|
||||||
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
|
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,20 +39,20 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
beatmap = Game.BeatmapManager.Import(new BeatmapSetInfo
|
beatmap = Game.BeatmapManager.Import(new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
Hash = Guid.NewGuid().ToString(),
|
Hash = Guid.NewGuid().ToString(),
|
||||||
OnlineBeatmapSetID = 1,
|
OnlineID = 1,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
Beatmaps = new List<BeatmapInfo>
|
Beatmaps = new List<BeatmapInfo>
|
||||||
{
|
{
|
||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = 1 * 1024,
|
OnlineID = 1 * 1024,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = difficulty,
|
BaseDifficulty = difficulty,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
Ruleset = new OsuRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = 1 * 2048,
|
OnlineID = 1 * 2048,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = difficulty,
|
BaseDifficulty = difficulty,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
Ruleset = new OsuRuleset().RulesetInfo
|
||||||
|
@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
Player player = null;
|
Player player = null;
|
||||||
ResultsScreen results = null;
|
ResultsScreen results = null;
|
||||||
|
|
||||||
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
|
||||||
|
|
||||||
PushAndConfirm(() => new TestPlaySongSelect());
|
PushAndConfirm(() => new TestPlaySongSelect());
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
{
|
{
|
||||||
Player player = null;
|
Player player = null;
|
||||||
|
|
||||||
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
|
||||||
|
|
||||||
PushAndConfirm(() => new TestPlaySongSelect());
|
PushAndConfirm(() => new TestPlaySongSelect());
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
|
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
|
||||||
AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()));
|
AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()));
|
||||||
|
|
||||||
AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
|
AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineID == 241526));
|
||||||
AddUntilStep("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
|
AddUntilStep("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
|
||||||
|
|
||||||
createButtonWithBeatmap(createSoleily());
|
createButtonWithBeatmap(createSoleily());
|
||||||
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
AddStep("remove soleily", () =>
|
AddStep("remove soleily", () =>
|
||||||
{
|
{
|
||||||
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 241526);
|
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineID == 241526);
|
||||||
|
|
||||||
if (beatmap != null) beatmaps.Delete(beatmap);
|
if (beatmap != null) beatmaps.Delete(beatmap);
|
||||||
});
|
});
|
||||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
|
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
|
||||||
{
|
{
|
||||||
BeatmapInfo = { OnlineBeatmapID = hasOnlineId ? 1234 : (int?)null }
|
BeatmapInfo = { OnlineID = hasOnlineId ? 1234 : (int?)null }
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Run command", () => Add(new NowPlayingCommand()));
|
AddStep("Run command", () => Add(new NowPlayingCommand()));
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
RoomManager.CreateRequested = r =>
|
RoomManager.CreateRequested = r =>
|
||||||
{
|
{
|
||||||
createdRoom = r;
|
createdRoom = r;
|
||||||
return true;
|
return string.Empty;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,28 +82,58 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddAssert("has correct duration", () => createdRoom.Duration.Value == expectedDuration);
|
AddAssert("has correct duration", () => createdRoom.Duration.Value == expectedDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInvalidBeatmapError()
|
||||||
|
{
|
||||||
|
const string not_found_prefix = "beatmaps not found:";
|
||||||
|
|
||||||
|
string errorMesage = null;
|
||||||
|
|
||||||
|
AddStep("setup", () =>
|
||||||
|
{
|
||||||
|
var beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo;
|
||||||
|
|
||||||
|
SelectedRoom.Value.Name.Value = "Test Room";
|
||||||
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = beatmap } });
|
||||||
|
|
||||||
|
errorMesage = $"{not_found_prefix} {beatmap.OnlineID}";
|
||||||
|
|
||||||
|
RoomManager.CreateRequested = _ => errorMesage;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
|
||||||
|
AddAssert("playlist item valid", () => SelectedRoom.Value.Playlist[0].Valid.Value);
|
||||||
|
|
||||||
|
AddStep("create room", () => settings.ApplyButton.Action.Invoke());
|
||||||
|
|
||||||
|
AddAssert("error displayed", () => settings.ErrorText.IsPresent);
|
||||||
|
AddAssert("error has custom text", () => settings.ErrorText.Text != errorMesage);
|
||||||
|
AddAssert("playlist item marked invalid", () => !SelectedRoom.Value.Playlist[0].Valid.Value);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCreationFailureDisplaysError()
|
public void TestCreationFailureDisplaysError()
|
||||||
{
|
{
|
||||||
bool fail;
|
const string error_message = "failed";
|
||||||
|
|
||||||
|
string failText = error_message;
|
||||||
|
|
||||||
AddStep("setup", () =>
|
AddStep("setup", () =>
|
||||||
{
|
{
|
||||||
SelectedRoom.Value.Name.Value = "Test Room";
|
SelectedRoom.Value.Name.Value = "Test Room";
|
||||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } });
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } });
|
||||||
|
|
||||||
fail = true;
|
RoomManager.CreateRequested = _ => failText;
|
||||||
RoomManager.CreateRequested = _ => !fail;
|
|
||||||
});
|
});
|
||||||
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
|
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
|
||||||
|
|
||||||
AddStep("create room", () => settings.ApplyButton.Action.Invoke());
|
AddStep("create room", () => settings.ApplyButton.Action.Invoke());
|
||||||
AddAssert("error displayed", () => settings.ErrorText.IsPresent);
|
AddAssert("error displayed", () => settings.ErrorText.IsPresent);
|
||||||
AddAssert("error has correct text", () => settings.ErrorText.Text == TestRoomManager.FAILED_TEXT);
|
AddAssert("error has correct text", () => settings.ErrorText.Text == error_message);
|
||||||
|
|
||||||
AddStep("create room no fail", () =>
|
AddStep("create room no fail", () =>
|
||||||
{
|
{
|
||||||
fail = false;
|
failText = string.Empty;
|
||||||
settings.ApplyButton.Action.Invoke();
|
settings.ApplyButton.Action.Invoke();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -132,9 +162,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
|
|
||||||
protected class TestRoomManager : IRoomManager
|
protected class TestRoomManager : IRoomManager
|
||||||
{
|
{
|
||||||
public const string FAILED_TEXT = "failed";
|
public Func<Room, string> CreateRequested;
|
||||||
|
|
||||||
public Func<Room, bool> CreateRequested;
|
|
||||||
|
|
||||||
public event Action RoomsUpdated
|
public event Action RoomsUpdated
|
||||||
{
|
{
|
||||||
@ -157,8 +185,10 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
if (CreateRequested == null)
|
if (CreateRequested == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!CreateRequested.Invoke(room))
|
string error = CreateRequested.Invoke(room);
|
||||||
onError?.Invoke(FAILED_TEXT);
|
|
||||||
|
if (!string.IsNullOrEmpty(error))
|
||||||
|
onError?.Invoke(error);
|
||||||
else
|
else
|
||||||
onSuccess?.Invoke(room);
|
onSuccess?.Invoke(room);
|
||||||
}
|
}
|
||||||
|
@ -121,8 +121,8 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
beatmap.BeatmapInfo.BaseDifficulty.CircleSize = 1;
|
beatmap.BeatmapInfo.BaseDifficulty.CircleSize = 1;
|
||||||
|
|
||||||
// intentionally increment online IDs to clash with import below.
|
// intentionally increment online IDs to clash with import below.
|
||||||
beatmap.BeatmapInfo.OnlineBeatmapID++;
|
beatmap.BeatmapInfo.OnlineID++;
|
||||||
beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID++;
|
beatmap.BeatmapInfo.BeatmapSet.OnlineID++;
|
||||||
|
|
||||||
importedSet = manager.Import(beatmap.BeatmapInfo.BeatmapSet).Result.Value;
|
importedSet = manager.Import(beatmap.BeatmapInfo.BeatmapSet).Result.Value;
|
||||||
});
|
});
|
||||||
|
@ -337,7 +337,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
public UnrankedSoloResultsScreen(ScoreInfo score)
|
public UnrankedSoloResultsScreen(ScoreInfo score)
|
||||||
: base(score, true)
|
: base(score, true)
|
||||||
{
|
{
|
||||||
Score.BeatmapInfo.OnlineBeatmapID = 0;
|
Score.BeatmapInfo.OnlineID = 0;
|
||||||
Score.BeatmapInfo.Status = BeatmapSetOnlineStatus.Pending;
|
Score.BeatmapInfo.Status = BeatmapSetOnlineStatus.Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,7 +838,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
return new BeatmapSetInfo
|
return new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
ID = id,
|
ID = id,
|
||||||
OnlineBeatmapSetID = id,
|
OnlineID = id,
|
||||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
@ -867,7 +867,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
yield return new BeatmapInfo
|
yield return new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = id++ * 10,
|
OnlineID = id++ * 10,
|
||||||
DifficultyName = version,
|
DifficultyName = version,
|
||||||
StarRating = diff,
|
StarRating = diff,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
@ -884,7 +884,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
var toReturn = new BeatmapSetInfo
|
var toReturn = new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
ID = id,
|
ID = id,
|
||||||
OnlineBeatmapSetID = id,
|
OnlineID = id,
|
||||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
@ -900,7 +900,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
toReturn.Beatmaps.Add(new BeatmapInfo
|
toReturn.Beatmaps.Add(new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = b * 10,
|
OnlineID = b * 10,
|
||||||
Path = $"extra{b}.osu",
|
Path = $"extra{b}.osu",
|
||||||
DifficultyName = $"Extra {b}",
|
DifficultyName = $"Extra {b}",
|
||||||
Ruleset = rulesets.GetRuleset((b - 1) % 4),
|
Ruleset = rulesets.GetRuleset((b - 1) % 4),
|
||||||
|
@ -388,7 +388,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
leaderboard.BeatmapInfo = new BeatmapInfo
|
leaderboard.BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = 1113057,
|
OnlineID = 1113057,
|
||||||
Status = status,
|
Status = status,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMetadataForBeatmap(Func<WorkingBeatmap> getBeatmap)
|
private void showMetadataForBeatmap(Func<IWorkingBeatmap> getBeatmap)
|
||||||
{
|
{
|
||||||
AddStep("setup display", () =>
|
AddStep("setup display", () =>
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -102,8 +103,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo catchSet = null, mixedSet = null;
|
BeatmapSetInfo catchSet = null, mixedSet = null;
|
||||||
|
|
||||||
AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(0, new[] { new CatchRuleset().RulesetInfo }));
|
AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(1, new[] { new CatchRuleset().RulesetInfo }));
|
||||||
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1,
|
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
|
||||||
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { catchSet, mixedSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { catchSet, mixedSet }));
|
||||||
@ -120,8 +121,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo osuSet = null, mixedSet = null;
|
BeatmapSetInfo osuSet = null, mixedSet = null;
|
||||||
|
|
||||||
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo }));
|
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
|
||||||
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1,
|
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
|
||||||
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
||||||
@ -138,8 +139,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo osuSet = null, mixedSet = null;
|
BeatmapSetInfo osuSet = null, mixedSet = null;
|
||||||
|
|
||||||
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo }));
|
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
|
||||||
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1,
|
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
|
||||||
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo }));
|
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo }));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
||||||
@ -156,8 +157,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo osuSet = null, maniaSet = null;
|
BeatmapSetInfo osuSet = null, maniaSet = null;
|
||||||
|
|
||||||
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo }));
|
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
|
||||||
AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(1, Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10)));
|
AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(2, Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10)));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, maniaSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, maniaSet }));
|
||||||
|
|
||||||
@ -180,11 +181,11 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
var beatmapSet = new BeatmapSetInfo
|
var beatmapSet = new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
Hash = Guid.NewGuid().ToString(),
|
Hash = Guid.NewGuid().ToString(),
|
||||||
OnlineBeatmapSetID = importID,
|
OnlineID = importID,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
Beatmaps = difficultyRulesets.Select((ruleset, difficultyIndex) => new BeatmapInfo
|
Beatmaps = difficultyRulesets.Select((ruleset, difficultyIndex) => new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = importID * 1024 + difficultyIndex,
|
OnlineID = importID * 1024 + difficultyIndex,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
BaseDifficulty = new BeatmapDifficulty(),
|
||||||
Ruleset = ruleset,
|
Ruleset = ruleset,
|
||||||
@ -203,11 +204,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
||||||
AddUntilStep("recommended beatmap displayed", () =>
|
AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.MatchesOnlineID(getImport().Beatmaps[expectedDiff - 1]));
|
||||||
{
|
|
||||||
int? expectedID = getImport().Beatmaps[expectedDiff - 1].OnlineBeatmapID;
|
|
||||||
return Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == expectedID;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
@ -360,7 +361,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target));
|
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target));
|
||||||
|
|
||||||
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
|
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
|
||||||
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target));
|
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -392,7 +393,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0);
|
AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0);
|
||||||
|
|
||||||
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
|
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
|
||||||
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target));
|
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -507,13 +508,13 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0);
|
i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineBeatmapID == target.OnlineBeatmapID);
|
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
|
||||||
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target));
|
||||||
|
|
||||||
AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = string.Empty);
|
AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = string.Empty);
|
||||||
|
|
||||||
AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.MatchesOnlineID(target) == true);
|
||||||
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.MatchesOnlineID(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -544,8 +545,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null);
|
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null);
|
||||||
|
|
||||||
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineBeatmapID == target.OnlineBeatmapID);
|
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
|
||||||
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target));
|
||||||
|
|
||||||
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nononoo");
|
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nononoo");
|
||||||
|
|
||||||
@ -672,7 +673,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("wait for selection", () => !Beatmap.IsDefault);
|
AddUntilStep("wait for selection", () => !Beatmap.IsDefault);
|
||||||
|
|
||||||
AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID);
|
AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID);
|
||||||
AddAssert("selection changed once", () => changeCount == 1);
|
AddAssert("selection changed once", () => changeCount == 1);
|
||||||
|
|
||||||
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
|
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
|
||||||
@ -683,8 +684,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("selection changed", () => changeCount > 1);
|
AddUntilStep("selection changed", () => changeCount > 1);
|
||||||
|
|
||||||
AddAssert("Selected beatmap still same set", () => Beatmap.Value.BeatmapSetInfo.ID == previousSetID);
|
AddAssert("Selected beatmap still same set", () => Beatmap.Value.BeatmapSetInfo.OnlineID == previousSetID);
|
||||||
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3);
|
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3);
|
||||||
|
|
||||||
AddAssert("selection changed only fired twice", () => changeCount == 2);
|
AddAssert("selection changed only fired twice", () => changeCount == 2);
|
||||||
|
|
||||||
@ -727,7 +728,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
int previousSetID = 0;
|
int previousSetID = 0;
|
||||||
|
|
||||||
AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID);
|
AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID);
|
||||||
|
|
||||||
AddStep("Click on a difficulty", () =>
|
AddStep("Click on a difficulty", () =>
|
||||||
{
|
{
|
||||||
@ -738,8 +739,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
||||||
|
|
||||||
AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.ID == previousSetID);
|
AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.OnlineID == previousSetID);
|
||||||
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3);
|
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -784,7 +785,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
||||||
|
|
||||||
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.Equals(groupIcon.Items.First().BeatmapInfo));
|
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(groupIcon.Items.First().BeatmapInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -815,7 +816,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
|
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
|
||||||
|
|
||||||
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.Equals(getPresentBeatmap()));
|
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
|
||||||
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
|
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,7 +848,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
|
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
|
||||||
|
|
||||||
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.Equals(getPresentBeatmap()));
|
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
|
||||||
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
|
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -918,7 +919,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new BeatmapInfo
|
||||||
{
|
{
|
||||||
Ruleset = getRuleset(),
|
Ruleset = getRuleset(),
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineID = beatmapId,
|
||||||
DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||||
Length = length,
|
Length = length,
|
||||||
BPM = bpm,
|
BPM = bpm,
|
||||||
@ -931,7 +932,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
return new BeatmapSetInfo
|
return new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = setId,
|
OnlineID = setId,
|
||||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
@ -960,7 +961,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
public new FilterControl FilterControl => base.FilterControl;
|
public new FilterControl FilterControl => base.FilterControl;
|
||||||
|
|
||||||
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
|
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
|
||||||
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
|
public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
|
||||||
public new BeatmapCarousel Carousel => base.Carousel;
|
public new BeatmapCarousel Carousel => base.Carousel;
|
||||||
|
|
||||||
public new void PresentScore(ScoreInfo score) => base.PresentScore(score);
|
public new void PresentScore(ScoreInfo score) => base.PresentScore(score);
|
||||||
|
@ -199,7 +199,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override string Description { get; } = "test";
|
public override string Description { get; } = "test";
|
||||||
public override string ShortName { get; } = "tst";
|
public override string ShortName { get; } = "tst";
|
||||||
|
@ -140,21 +140,21 @@ namespace osu.Game.Beatmaps
|
|||||||
return GetAsync(new DifficultyCacheLookup(localBeatmapInfo, localRulesetInfo, mods), cancellationToken);
|
return GetAsync(new DifficultyCacheLookup(localBeatmapInfo, localRulesetInfo, mods), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task<StarDifficulty> ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken token = default)
|
protected override Task<StarDifficulty> ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return Task.Factory.StartNew(() =>
|
return Task.Factory.StartNew(() =>
|
||||||
{
|
{
|
||||||
if (CheckExists(lookup, out var existing))
|
if (CheckExists(lookup, out var existing))
|
||||||
return existing;
|
return existing;
|
||||||
|
|
||||||
return computeDifficulty(lookup);
|
return computeDifficulty(lookup, cancellationToken);
|
||||||
}, token, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler);
|
}, cancellationToken, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<List<TimedDifficultyAttributes>> GetTimedDifficultyAttributesAsync(WorkingBeatmap beatmap, Ruleset ruleset, Mod[] mods, CancellationToken token = default)
|
public Task<List<TimedDifficultyAttributes>> GetTimedDifficultyAttributesAsync(IWorkingBeatmap beatmap, Ruleset ruleset, Mod[] mods, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return Task.Factory.StartNew(() => ruleset.CreateDifficultyCalculator(beatmap).CalculateTimed(mods),
|
return Task.Factory.StartNew(() => ruleset.CreateDifficultyCalculator(beatmap).CalculateTimed(mods, cancellationToken),
|
||||||
token,
|
cancellationToken,
|
||||||
TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously,
|
TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously,
|
||||||
updateScheduler);
|
updateScheduler);
|
||||||
}
|
}
|
||||||
@ -270,8 +270,9 @@ namespace osu.Game.Beatmaps
|
|||||||
/// Computes the difficulty defined by a <see cref="DifficultyCacheLookup"/> key, and stores it to the timed cache.
|
/// Computes the difficulty defined by a <see cref="DifficultyCacheLookup"/> key, and stores it to the timed cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The <see cref="DifficultyCacheLookup"/> that defines the computation parameters.</param>
|
/// <param name="key">The <see cref="DifficultyCacheLookup"/> that defines the computation parameters.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
||||||
private StarDifficulty computeDifficulty(in DifficultyCacheLookup key)
|
private StarDifficulty computeDifficulty(in DifficultyCacheLookup key, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
||||||
var beatmapInfo = key.BeatmapInfo;
|
var beatmapInfo = key.BeatmapInfo;
|
||||||
@ -283,14 +284,14 @@ namespace osu.Game.Beatmaps
|
|||||||
Debug.Assert(ruleset != null);
|
Debug.Assert(ruleset != null);
|
||||||
|
|
||||||
var calculator = ruleset.CreateDifficultyCalculator(beatmapManager.GetWorkingBeatmap(key.BeatmapInfo));
|
var calculator = ruleset.CreateDifficultyCalculator(beatmapManager.GetWorkingBeatmap(key.BeatmapInfo));
|
||||||
var attributes = calculator.Calculate(key.OrderedMods);
|
var attributes = calculator.Calculate(key.OrderedMods, cancellationToken);
|
||||||
|
|
||||||
return new StarDifficulty(attributes);
|
return new StarDifficulty(attributes);
|
||||||
}
|
}
|
||||||
catch (BeatmapInvalidForRulesetException e)
|
catch (BeatmapInvalidForRulesetException e)
|
||||||
{
|
{
|
||||||
if (rulesetInfo.Equals(beatmapInfo.Ruleset))
|
if (rulesetInfo.Equals(beatmapInfo.Ruleset))
|
||||||
Logger.Error(e, $"Failed to convert {beatmapInfo.OnlineBeatmapID} to the beatmap's default ruleset ({beatmapInfo.Ruleset}).");
|
Logger.Error(e, $"Failed to convert {beatmapInfo.OnlineID} to the beatmap's default ruleset ({beatmapInfo.Ruleset}).");
|
||||||
|
|
||||||
return new StarDifficulty();
|
return new StarDifficulty();
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,14 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public int BeatmapVersion;
|
public int BeatmapVersion;
|
||||||
|
|
||||||
private int? onlineBeatmapID;
|
private int? onlineID;
|
||||||
|
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public int? OnlineBeatmapID
|
[Column("OnlineBeatmapID")]
|
||||||
|
public int? OnlineID
|
||||||
{
|
{
|
||||||
get => onlineBeatmapID;
|
get => onlineID;
|
||||||
set => onlineBeatmapID = value > 0 ? value : null;
|
set => onlineID = value > 0 ? value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
@ -153,14 +154,17 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public bool Equals(BeatmapInfo other)
|
public bool Equals(BeatmapInfo other)
|
||||||
{
|
{
|
||||||
if (ID == 0 || other?.ID == 0)
|
if (ReferenceEquals(this, other)) return true;
|
||||||
// one of the two BeatmapInfos we are comparing isn't sourced from a database.
|
if (other == null) return false;
|
||||||
// fall back to reference equality.
|
|
||||||
return ReferenceEquals(this, other);
|
|
||||||
|
|
||||||
return ID == other?.ID;
|
if (ID != 0 && other.ID != 0)
|
||||||
|
return ID == other.ID;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Equals(IBeatmapInfo other) => other is BeatmapInfo b && Equals(b);
|
||||||
|
|
||||||
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||||
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||||
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
|
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
|
||||||
@ -176,7 +180,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
#region Implementation of IHasOnlineID
|
#region Implementation of IHasOnlineID
|
||||||
|
|
||||||
public int OnlineID => OnlineBeatmapID ?? -1;
|
int IHasOnlineID<int>.OnlineID => OnlineID ?? -1;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap;
|
public IWorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when a notification should be presented to the user.
|
/// Fired when a notification should be presented to the user.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user