mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 04:02:57 +08:00
Merge branch 'master' into improve_retry_behaviour
This commit is contained in:
commit
c9baadcf88
@ -4,8 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
@ -50,9 +48,6 @@ namespace osu.Game.Rulesets.Pippidon
|
||||
new KeyBinding(InputKey.X, PippidonAction.Button2),
|
||||
};
|
||||
|
||||
public override Drawable CreateIcon() => new Sprite
|
||||
{
|
||||
Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/coin"),
|
||||
};
|
||||
public override Drawable CreateIcon() => new PippidonRulesetIcon(this);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
|
||||
namespace osu.Game.Rulesets.Pippidon
|
||||
{
|
||||
public class PippidonRulesetIcon : Sprite
|
||||
{
|
||||
private readonly Ruleset ruleset;
|
||||
|
||||
public PippidonRulesetIcon(Ruleset ruleset)
|
||||
{
|
||||
this.ruleset = ruleset;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IRenderer renderer)
|
||||
{
|
||||
Texture = new TextureStore(renderer, new TextureLoaderStore(ruleset.CreateResourceStore()), false).Get("Textures/coin");
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
@ -47,10 +45,6 @@ namespace osu.Game.Rulesets.Pippidon
|
||||
new KeyBinding(InputKey.S, PippidonAction.MoveDown),
|
||||
};
|
||||
|
||||
public override Drawable CreateIcon() => new Sprite
|
||||
{
|
||||
Margin = new MarginPadding { Top = 3 },
|
||||
Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/coin"),
|
||||
};
|
||||
public override Drawable CreateIcon() => new PippidonRulesetIcon(this);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
|
||||
namespace osu.Game.Rulesets.Pippidon
|
||||
{
|
||||
public class PippidonRulesetIcon : Sprite
|
||||
{
|
||||
private readonly Ruleset ruleset;
|
||||
|
||||
public PippidonRulesetIcon(Ruleset ruleset)
|
||||
{
|
||||
this.ruleset = ruleset;
|
||||
|
||||
Margin = new MarginPadding { Top = 3 };
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IRenderer renderer)
|
||||
{
|
||||
Texture = new TextureStore(renderer, new TextureLoaderStore(ruleset.CreateResourceStore()), false).Get("Textures/coin");
|
||||
}
|
||||
}
|
||||
}
|
@ -51,8 +51,8 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.722.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.730.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.810.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.810.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
52
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs
Normal file
52
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneBarLine : ManiaSkinnableTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestMinor()
|
||||
{
|
||||
AddStep("Create barlines", () => recreate());
|
||||
}
|
||||
|
||||
private void recreate(Func<IEnumerable<BarLine>>? createBarLines = null)
|
||||
{
|
||||
var stageDefinitions = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 4 },
|
||||
};
|
||||
|
||||
SetContents(_ => new ManiaPlayfield(stageDefinitions).With(s =>
|
||||
{
|
||||
if (createBarLines != null)
|
||||
{
|
||||
var barLines = createBarLines();
|
||||
|
||||
foreach (var b in barLines)
|
||||
s.Add(b);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
s.Add(new BarLine
|
||||
{
|
||||
StartTime = Time.Current + i * 500,
|
||||
Major = i % 4 == 0,
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
public override string Acronym => "CS";
|
||||
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
|
||||
public override string Description => "No more tricky speed changes!";
|
||||
|
||||
|
@ -1,12 +1,9 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
@ -16,21 +13,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
public class DrawableBarLine : DrawableManiaHitObject<BarLine>
|
||||
{
|
||||
/// <summary>
|
||||
/// Height of major bar line triangles.
|
||||
/// </summary>
|
||||
private const float triangle_height = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Offset of the major bar line triangles from the sides of the bar line.
|
||||
/// </summary>
|
||||
private const float triangle_offset = 9;
|
||||
|
||||
public DrawableBarLine(BarLine barLine)
|
||||
: base(barLine)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 2f;
|
||||
Height = barLine.Major ? 1.7f : 1.2f;
|
||||
|
||||
AddInternal(new Box
|
||||
{
|
||||
@ -38,34 +25,33 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = new Color4(255, 204, 33, 255),
|
||||
Alpha = barLine.Major ? 0.5f : 0.2f
|
||||
});
|
||||
|
||||
if (barLine.Major)
|
||||
{
|
||||
AddInternal(new EquilateralTriangle
|
||||
Vector2 size = new Vector2(22, 6);
|
||||
const float line_offset = 4;
|
||||
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Name = "Left triangle",
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopCentre,
|
||||
Size = new Vector2(triangle_height),
|
||||
X = -triangle_offset,
|
||||
Rotation = 90
|
||||
Name = "Left line",
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreRight,
|
||||
|
||||
Size = size,
|
||||
X = -line_offset,
|
||||
});
|
||||
|
||||
AddInternal(new EquilateralTriangle
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Name = "Right triangle",
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.TopCentre,
|
||||
Size = new Vector2(triangle_height),
|
||||
X = triangle_offset,
|
||||
Rotation = -90
|
||||
Name = "Right line",
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = size,
|
||||
X = line_offset,
|
||||
});
|
||||
}
|
||||
|
||||
if (!barLine.Major)
|
||||
Alpha = 0.2f;
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
|
@ -9,7 +9,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
@ -9,7 +9,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
@ -6,7 +6,8 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
@ -19,6 +20,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[HeadlessTest]
|
||||
public class LegacyMainCirclePieceTest : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private IRenderer renderer { get; set; } = null!;
|
||||
|
||||
private static readonly object?[][] texture_priority_cases =
|
||||
{
|
||||
// default priority lookup
|
||||
@ -76,7 +80,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
skin.Setup(s => s.GetTexture(It.IsAny<string>())).CallBase();
|
||||
|
||||
skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny<WrapMode>(), It.IsAny<WrapMode>()))
|
||||
.Returns((string componentName, WrapMode _, WrapMode _) => new Texture(1, 1) { AssetName = componentName });
|
||||
.Returns((string componentName, WrapMode _, WrapMode _) =>
|
||||
{
|
||||
var tex = renderer.CreateTexture(1, 1);
|
||||
tex.AssetName = componentName;
|
||||
return tex;
|
||||
});
|
||||
|
||||
Child = new DependencyProvidingContainer
|
||||
{
|
||||
@ -84,7 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
Child = piece = new TestLegacyMainCirclePiece(priorityLookup),
|
||||
};
|
||||
|
||||
var sprites = this.ChildrenOfType<Sprite>().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray();
|
||||
var sprites = this.ChildrenOfType<Sprite>().Where(s => !string.IsNullOrEmpty(s.Texture.AssetName)).DistinctBy(s => s.Texture.AssetName).ToArray();
|
||||
Debug.Assert(sprites.Length <= 2);
|
||||
});
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = mod,
|
||||
PassCondition = () => Player.ScoreProcessor.JudgedHits >= 2 &&
|
||||
Precision.AlmostEquals(Player.GameplayClockContainer.GameplayClock.Rate, mod.SpeedChange.Value)
|
||||
Precision.AlmostEquals(Player.GameplayClockContainer.Rate, mod.SpeedChange.Value)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -17,18 +17,18 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||
|
||||
[TestCase(6.6369583000323935d, 206, "diffcalc-test")]
|
||||
[TestCase(1.4476531024675374d, 45, "zero-length-sliders")]
|
||||
[TestCase(6.7115569159190587d, 206, "diffcalc-test")]
|
||||
[TestCase(1.4391311903612753d, 45, "zero-length-sliders")]
|
||||
public void Test(double expectedStarRating, int expectedMaxCombo, string name)
|
||||
=> base.Test(expectedStarRating, expectedMaxCombo, name);
|
||||
|
||||
[TestCase(8.8816128335486386d, 206, "diffcalc-test")]
|
||||
[TestCase(1.7540389962596916d, 45, "zero-length-sliders")]
|
||||
[TestCase(8.9757300665532966d, 206, "diffcalc-test")]
|
||||
[TestCase(1.7437232654020756d, 45, "zero-length-sliders")]
|
||||
public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
|
||||
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime());
|
||||
|
||||
[TestCase(6.6369583000323935d, 239, "diffcalc-test")]
|
||||
[TestCase(1.4476531024675374d, 54, "zero-length-sliders")]
|
||||
[TestCase(6.7115569159190587d, 239, "diffcalc-test")]
|
||||
[TestCase(1.4391311903612753d, 54, "zero-length-sliders")]
|
||||
public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)
|
||||
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic());
|
||||
|
||||
|
@ -11,7 +11,7 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing.Input;
|
||||
using osu.Game.Audio;
|
||||
@ -25,6 +25,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneCursorTrail : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private IRenderer renderer { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestSmoothCursorTrail()
|
||||
{
|
||||
@ -44,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
createTest(() =>
|
||||
{
|
||||
var skinContainer = new LegacySkinContainer(false);
|
||||
var skinContainer = new LegacySkinContainer(renderer, false);
|
||||
var legacyCursorTrail = new LegacyCursorTrail(skinContainer);
|
||||
|
||||
skinContainer.Child = legacyCursorTrail;
|
||||
@ -58,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
createTest(() =>
|
||||
{
|
||||
var skinContainer = new LegacySkinContainer(true);
|
||||
var skinContainer = new LegacySkinContainer(renderer, true);
|
||||
var legacyCursorTrail = new LegacyCursorTrail(skinContainer);
|
||||
|
||||
skinContainer.Child = legacyCursorTrail;
|
||||
@ -82,10 +85,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[Cached(typeof(ISkinSource))]
|
||||
private class LegacySkinContainer : Container, ISkinSource
|
||||
{
|
||||
private readonly IRenderer renderer;
|
||||
private readonly bool disjoint;
|
||||
|
||||
public LegacySkinContainer(bool disjoint)
|
||||
public LegacySkinContainer(IRenderer renderer, bool disjoint)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.disjoint = disjoint;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
@ -98,14 +103,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
switch (componentName)
|
||||
{
|
||||
case "cursortrail":
|
||||
var tex = new Texture(Texture.WhitePixel.TextureGL);
|
||||
var tex = new Texture(renderer.WhitePixel);
|
||||
|
||||
if (disjoint)
|
||||
tex.ScaleAdjust = 1 / 25f;
|
||||
return tex;
|
||||
|
||||
case "cursormiddle":
|
||||
return disjoint ? null : Texture.WhitePixel;
|
||||
return disjoint ? null : renderer.WhitePixel;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
|
@ -12,7 +12,6 @@ using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Timing;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -12,7 +10,6 @@ using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -36,16 +33,16 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
private const double spinner_duration = 6000;
|
||||
|
||||
[Resolved]
|
||||
private AudioManager audioManager { get; set; }
|
||||
private AudioManager audioManager { get; set; } = null!;
|
||||
|
||||
protected override bool Autoplay => true;
|
||||
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer();
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null)
|
||||
=> new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
|
||||
private DrawableSpinner drawableSpinner;
|
||||
private DrawableSpinner drawableSpinner = null!;
|
||||
private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType<SpriteIcon>().Single();
|
||||
|
||||
[SetUpSteps]
|
||||
@ -67,12 +64,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
trackerRotationTolerance = Math.Abs(drawableSpinner.RotationTracker.Rotation * 0.1f);
|
||||
});
|
||||
AddAssert("is disc rotation not almost 0", () => !Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, 0, 100));
|
||||
AddAssert("is disc rotation absolute not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, 0, 100));
|
||||
AddAssert("is disc rotation not almost 0", () => drawableSpinner.RotationTracker.Rotation, () => Is.Not.EqualTo(0).Within(100));
|
||||
AddAssert("is disc rotation absolute not almost 0", () => drawableSpinner.Result.RateAdjustedRotation, () => Is.Not.EqualTo(0).Within(100));
|
||||
|
||||
addSeekStep(0);
|
||||
AddAssert("is disc rotation almost 0", () => Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, 0, trackerRotationTolerance));
|
||||
AddAssert("is disc rotation absolute almost 0", () => Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, 0, 100));
|
||||
AddAssert("is disc rotation almost 0", () => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(0).Within(trackerRotationTolerance));
|
||||
AddAssert("is disc rotation absolute almost 0", () => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(0).Within(100));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -100,20 +97,20 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
// we want to make sure that the rotation at time 2500 is in the same direction as at time 5000, but about half-way in.
|
||||
// due to the exponential damping applied we're allowing a larger margin of error of about 10%
|
||||
// (5% relative to the final rotation value, but we're half-way through the spin).
|
||||
() => Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, finalTrackerRotation / 2, trackerRotationTolerance));
|
||||
() => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(finalTrackerRotation / 2).Within(trackerRotationTolerance));
|
||||
AddAssert("symbol rotation rewound",
|
||||
() => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation / 2, spinnerSymbolRotationTolerance));
|
||||
() => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation / 2).Within(spinnerSymbolRotationTolerance));
|
||||
AddAssert("is cumulative rotation rewound",
|
||||
// cumulative rotation is not damped, so we're treating it as the "ground truth" and allowing a comparatively smaller margin of error.
|
||||
() => Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, finalCumulativeTrackerRotation / 2, 100));
|
||||
() => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(finalCumulativeTrackerRotation / 2).Within(100));
|
||||
|
||||
addSeekStep(spinner_start_time + 5000);
|
||||
AddAssert("is disc rotation almost same",
|
||||
() => Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, finalTrackerRotation, trackerRotationTolerance));
|
||||
() => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(finalTrackerRotation).Within(trackerRotationTolerance));
|
||||
AddAssert("is symbol rotation almost same",
|
||||
() => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation, spinnerSymbolRotationTolerance));
|
||||
() => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation).Within(spinnerSymbolRotationTolerance));
|
||||
AddAssert("is cumulative rotation almost same",
|
||||
() => Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, finalCumulativeTrackerRotation, 100));
|
||||
() => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(finalCumulativeTrackerRotation).Within(100));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -177,10 +174,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
AddStep("retrieve spm", () => estimatedSpm = drawableSpinner.SpinsPerMinute.Value);
|
||||
|
||||
addSeekStep(2000);
|
||||
AddAssert("spm still valid", () => Precision.AlmostEquals(drawableSpinner.SpinsPerMinute.Value, estimatedSpm, 1.0));
|
||||
AddAssert("spm still valid", () => drawableSpinner.SpinsPerMinute.Value, () => Is.EqualTo(estimatedSpm).Within(1.0));
|
||||
|
||||
addSeekStep(1000);
|
||||
AddAssert("spm still valid", () => Precision.AlmostEquals(drawableSpinner.SpinsPerMinute.Value, estimatedSpm, 1.0));
|
||||
AddAssert("spm still valid", () => drawableSpinner.SpinsPerMinute.Value, () => Is.EqualTo(estimatedSpm).Within(1.0));
|
||||
}
|
||||
|
||||
[TestCase(0.5)]
|
||||
@ -202,14 +199,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
AddStep("adjust track rate", () => ((MasterGameplayClockContainer)Player.GameplayClockContainer).UserPlaybackRate.Value = rate);
|
||||
|
||||
addSeekStep(1000);
|
||||
AddAssert("progress almost same", () => Precision.AlmostEquals(expectedProgress, drawableSpinner.Progress, 0.05));
|
||||
AddAssert("spm almost same", () => Precision.AlmostEquals(expectedSpm, drawableSpinner.SpinsPerMinute.Value, 2.0));
|
||||
AddAssert("progress almost same", () => expectedProgress, () => Is.EqualTo(drawableSpinner.Progress).Within(0.05));
|
||||
AddAssert("spm almost same", () => expectedSpm, () => Is.EqualTo(drawableSpinner.SpinsPerMinute.Value).Within(2.0));
|
||||
}
|
||||
|
||||
private void addSeekStep(double time)
|
||||
{
|
||||
AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time));
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
AddUntilStep("wait for seek to finish", () => time, () => Is.EqualTo(Player.DrawableRuleset.FrameStableClock.CurrentTime).Within(100));
|
||||
}
|
||||
|
||||
private void transformReplay(Func<Replay, Replay> replayTransformation) => AddStep("set replay", () =>
|
||||
|
@ -13,8 +13,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
public static class AimEvaluator
|
||||
{
|
||||
private const double wide_angle_multiplier = 1.5;
|
||||
private const double acute_angle_multiplier = 2.0;
|
||||
private const double slider_multiplier = 1.5;
|
||||
private const double acute_angle_multiplier = 1.95;
|
||||
private const double slider_multiplier = 1.35;
|
||||
private const double velocity_change_multiplier = 0.75;
|
||||
|
||||
/// <summary>
|
||||
@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2);
|
||||
}
|
||||
|
||||
if (osuLastObj.TravelTime != 0)
|
||||
if (osuLastObj.BaseObject is Slider)
|
||||
{
|
||||
// Reward sliders based on velocity.
|
||||
sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
||||
|
@ -15,11 +15,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
private const double max_opacity_bonus = 0.4;
|
||||
private const double hidden_bonus = 0.2;
|
||||
|
||||
private const double min_velocity = 0.5;
|
||||
private const double slider_multiplier = 1.3;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the difficulty of memorising and hitting an object, based on:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>distance between the previous and current object,</description></item>
|
||||
/// <item><description>distance between a number of previous objects and the current object,</description></item>
|
||||
/// <item><description>the visual opacity of the current object,</description></item>
|
||||
/// <item><description>length and speed of the current object (for sliders),</description></item>
|
||||
/// <item><description>and whether the hidden mod is enabled.</description></item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
@ -73,6 +77,26 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
if (hidden)
|
||||
result *= 1.0 + hidden_bonus;
|
||||
|
||||
double sliderBonus = 0.0;
|
||||
|
||||
if (osuCurrent.BaseObject is Slider osuSlider)
|
||||
{
|
||||
// Invert the scaling factor to determine the true travel distance independent of circle size.
|
||||
double pixelTravelDistance = osuSlider.LazyTravelDistance / scalingFactor;
|
||||
|
||||
// Reward sliders based on velocity.
|
||||
sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5);
|
||||
|
||||
// Longer sliders require more memorisation.
|
||||
sliderBonus *= pixelTravelDistance;
|
||||
|
||||
// Nerf sliders with repeats, as less memorisation is required.
|
||||
if (osuSlider.RepeatCount > 0)
|
||||
sliderBonus /= (osuSlider.RepeatCount + 1);
|
||||
}
|
||||
|
||||
result += sliderBonus * slider_multiplier;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
|
||||
|
||||
if (mods.Any(h => h is OsuModRelax))
|
||||
{
|
||||
aimRating *= 0.9;
|
||||
speedRating = 0.0;
|
||||
flashlightRating *= 0.7;
|
||||
}
|
||||
|
||||
double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000;
|
||||
double baseSpeedPerformance = Math.Pow(5 * Math.Max(1, speedRating / 0.0675) - 4, 3) / 100000;
|
||||
@ -62,7 +66,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1
|
||||
);
|
||||
|
||||
double starRating = basePerformance > 0.00001 ? Math.Cbrt(1.12) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0;
|
||||
double starRating = basePerformance > 0.00001 ? Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0;
|
||||
|
||||
double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;
|
||||
double drainRate = beatmap.Difficulty.DrainRate;
|
||||
|
@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
{
|
||||
public class OsuPerformanceCalculator : PerformanceCalculator
|
||||
{
|
||||
public const double PERFORMANCE_BASE_MULTIPLIER = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things.
|
||||
|
||||
private double accuracy;
|
||||
private int scoreMaxCombo;
|
||||
private int countGreat;
|
||||
@ -41,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss);
|
||||
effectiveMissCount = calculateEffectiveMissCount(osuAttributes);
|
||||
|
||||
double multiplier = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things.
|
||||
double multiplier = PERFORMANCE_BASE_MULTIPLIER;
|
||||
|
||||
if (score.Mods.Any(m => m is OsuModNoFail))
|
||||
multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount);
|
||||
@ -51,10 +53,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
if (score.Mods.Any(h => h is OsuModRelax))
|
||||
{
|
||||
// As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it.
|
||||
effectiveMissCount = Math.Min(effectiveMissCount + countOk + countMeh, totalHits);
|
||||
// https://www.desmos.com/calculator/bc9eybdthb
|
||||
// we use OD13.3 as maximum since it's the value at which great hitwidow becomes 0
|
||||
// this is well beyond currently maximum achievable OD which is 12.17 (DTx2 + DA with OD11)
|
||||
double okMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 1.8) : 1.0);
|
||||
double mehMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 5) : 1.0);
|
||||
|
||||
multiplier *= 0.6;
|
||||
// As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it.
|
||||
effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits);
|
||||
}
|
||||
|
||||
double aimValue = computeAimValue(score, osuAttributes);
|
||||
@ -103,7 +109,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
if (attributes.ApproachRate > 10.33)
|
||||
approachRateFactor = 0.3 * (attributes.ApproachRate - 10.33);
|
||||
else if (attributes.ApproachRate < 8.0)
|
||||
approachRateFactor = 0.1 * (8.0 - attributes.ApproachRate);
|
||||
approachRateFactor = 0.05 * (8.0 - attributes.ApproachRate);
|
||||
|
||||
if (score.Mods.Any(h => h is OsuModRelax))
|
||||
approachRateFactor = 0.0;
|
||||
|
||||
aimValue *= 1.0 + approachRateFactor * lengthBonus; // Buff for longer maps with high AR.
|
||||
|
||||
@ -134,6 +143,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attributes)
|
||||
{
|
||||
if (score.Mods.Any(h => h is OsuModRelax))
|
||||
return 0.0;
|
||||
|
||||
double speedValue = Math.Pow(5.0 * Math.Max(1.0, attributes.SpeedDifficulty / 0.0675) - 4.0, 3.0) / 100000.0;
|
||||
|
||||
double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) +
|
||||
@ -174,7 +186,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
speedValue *= (0.95 + Math.Pow(attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(attributes.OverallDifficulty, 8)) / 2);
|
||||
|
||||
// Scale the speed value with # of 50s to punish doubletapping.
|
||||
speedValue *= Math.Pow(0.98, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0);
|
||||
speedValue *= Math.Pow(0.99, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0);
|
||||
|
||||
return speedValue;
|
||||
}
|
||||
@ -266,6 +278,5 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0);
|
||||
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
||||
private int totalSuccessfulHits => countGreat + countOk + countMeh;
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
{
|
||||
public class OsuDifficultyHitObject : DifficultyHitObject
|
||||
{
|
||||
private const int normalised_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||
/// <summary>
|
||||
/// A distance by which all distances should be scaled in order to assume a uniform circle size.
|
||||
/// </summary>
|
||||
public const int NORMALISED_RADIUS = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||
|
||||
private const int min_delta_time = 25;
|
||||
private const float maximum_slider_radius = normalised_radius * 2.4f;
|
||||
private const float assumed_slider_radius = normalised_radius * 1.8f;
|
||||
private const float maximum_slider_radius = NORMALISED_RADIUS * 2.4f;
|
||||
private const float assumed_slider_radius = NORMALISED_RADIUS * 1.8f;
|
||||
|
||||
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
||||
|
||||
@ -64,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
public double TravelDistance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time taken to travel through <see cref="TravelDistance"/>, with a minimum value of 25ms for a non-zero distance.
|
||||
/// The time taken to travel through <see cref="TravelDistance"/>, with a minimum value of 25ms for <see cref="Slider"/> objects.
|
||||
/// </summary>
|
||||
public double TravelTime { get; private set; }
|
||||
|
||||
@ -123,7 +127,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
if (BaseObject is Slider currentSlider)
|
||||
{
|
||||
computeSliderCursorPosition(currentSlider);
|
||||
TravelDistance = currentSlider.LazyTravelDistance;
|
||||
// Bonus for repeat sliders until a better per nested object strain system can be achieved.
|
||||
TravelDistance = currentSlider.LazyTravelDistance * (float)Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5);
|
||||
TravelTime = Math.Max(currentSlider.LazyTravelTime / clockRate, min_delta_time);
|
||||
}
|
||||
|
||||
@ -132,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
return;
|
||||
|
||||
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
||||
float scalingFactor = normalised_radius / (float)BaseObject.Radius;
|
||||
float scalingFactor = NORMALISED_RADIUS / (float)BaseObject.Radius;
|
||||
|
||||
if (BaseObject.Radius < 30)
|
||||
{
|
||||
@ -206,7 +211,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
|
||||
slider.LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived.
|
||||
var currCursorPosition = slider.StackedPosition;
|
||||
double scalingFactor = normalised_radius / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used.
|
||||
double scalingFactor = NORMALISED_RADIUS / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used.
|
||||
|
||||
for (int i = 1; i < slider.NestedHitObjects.Count; i++)
|
||||
{
|
||||
@ -234,7 +239,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
else if (currMovementObj is SliderRepeat)
|
||||
{
|
||||
// For a slider repeat, assume a tighter movement threshold to better assess repeat sliders.
|
||||
requiredMovement = normalised_radius;
|
||||
requiredMovement = NORMALISED_RADIUS;
|
||||
}
|
||||
|
||||
if (currMovementLength > requiredMovement)
|
||||
@ -248,8 +253,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
if (i == slider.NestedHitObjects.Count - 1)
|
||||
slider.LazyEndPosition = currCursorPosition;
|
||||
}
|
||||
|
||||
slider.LazyTravelDistance *= (float)Math.Pow(1 + slider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved.
|
||||
}
|
||||
|
||||
private Vector2 getEndCursorPosition(OsuHitObject hitObject)
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
|
||||
private double currentStrain;
|
||||
|
||||
private double skillMultiplier => 23.25;
|
||||
private double skillMultiplier => 23.55;
|
||||
private double strainDecayBase => 0.15;
|
||||
|
||||
private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModAutopilot;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override double ScoreMultiplier => 0.1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModRepel) };
|
||||
|
||||
public bool PerformFail() => false;
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => FontAwesome.Solid.Magnet;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override string Description => "No need to chase the circles – your cursor is a magnet!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) };
|
||||
|
||||
private IFrameStableClock gameplayClock = null!;
|
||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
private bool rotationTransferred;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private GameplayClock gameplayClock { get; set; }
|
||||
private IGameplayClock gameplayClock { get; set; }
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
|
@ -9,9 +9,9 @@ using System.Runtime.InteropServices;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Batches;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Rendering.Vertices;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
@ -68,8 +68,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ShaderManager shaders)
|
||||
private void load(IRenderer renderer, ShaderManager shaders)
|
||||
{
|
||||
texture ??= renderer.WhitePixel;
|
||||
shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE);
|
||||
}
|
||||
|
||||
@ -79,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
resetTime();
|
||||
}
|
||||
|
||||
private Texture texture = Texture.WhitePixel;
|
||||
private Texture texture;
|
||||
|
||||
public Texture Texture
|
||||
{
|
||||
@ -222,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
private Vector2 size;
|
||||
private Vector2 originPosition;
|
||||
|
||||
private readonly QuadBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
||||
private IVertexBatch<TexturedTrailVertex> vertexBatch;
|
||||
|
||||
public TrailDrawNode(CursorTrail source)
|
||||
: base(source)
|
||||
@ -254,15 +255,17 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
Source.parts.CopyTo(parts, 0);
|
||||
}
|
||||
|
||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||
public override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(vertexAction);
|
||||
base.Draw(renderer);
|
||||
|
||||
vertexBatch ??= renderer.CreateQuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
||||
|
||||
shader.Bind();
|
||||
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
||||
shader.GetUniform<float>("g_FadeExponent").UpdateValue(ref fadeExponent);
|
||||
|
||||
texture.TextureGL.Bind();
|
||||
texture.Bind();
|
||||
|
||||
RectangleF textureRect = texture.GetTextureRect();
|
||||
|
||||
@ -319,7 +322,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
vertexBatch.Dispose();
|
||||
vertexBatch?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
|
@ -9,6 +9,7 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Rendering.Dummy;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
@ -55,7 +56,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestAcceptable()
|
||||
{
|
||||
var context = getContext(new Texture(1920, 1080));
|
||||
var context = getContext(new DummyRenderer().CreateTexture(1920, 1080));
|
||||
|
||||
Assert.That(check.Run(context), Is.Empty);
|
||||
}
|
||||
@ -63,7 +64,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestTooHighResolution()
|
||||
{
|
||||
var context = getContext(new Texture(3840, 2160));
|
||||
var context = getContext(new DummyRenderer().CreateTexture(3840, 2160));
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
@ -74,7 +75,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestLowResolution()
|
||||
{
|
||||
var context = getContext(new Texture(640, 480));
|
||||
var context = getContext(new DummyRenderer().CreateTexture(640, 480));
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
@ -85,7 +86,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestTooLowResolution()
|
||||
{
|
||||
var context = getContext(new Texture(100, 100));
|
||||
var context = getContext(new DummyRenderer().CreateTexture(100, 100));
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
@ -96,7 +97,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestTooUncompressed()
|
||||
{
|
||||
var context = getContext(new Texture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3]));
|
||||
var context = getContext(new DummyRenderer().CreateTexture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3]));
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
@ -107,7 +108,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestStreamClosed()
|
||||
{
|
||||
var background = new Texture(1920, 1080);
|
||||
var background = new DummyRenderer().CreateTexture(1920, 1080);
|
||||
var stream = new Mock<MemoryStream>(new byte[1024 * 1024]);
|
||||
|
||||
var context = getContext(background, stream.Object);
|
||||
|
@ -206,7 +206,7 @@ namespace osu.Game.Tests.Editing
|
||||
}
|
||||
|
||||
private void assertSnapDistance(float expectedDistance, HitObject hitObject = null)
|
||||
=> AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()) == expectedDistance);
|
||||
=> AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()), () => Is.EqualTo(expectedDistance));
|
||||
|
||||
private void assertDurationToDistance(double duration, float expectedDistance)
|
||||
=> AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(new HitObject(), duration) == expectedDistance);
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
});
|
||||
|
||||
AddStep("start clock", () => gameplayClockContainer.Start());
|
||||
AddUntilStep("elapsed greater than zero", () => gameplayClockContainer.GameplayClock.ElapsedFrameTime > 0);
|
||||
AddUntilStep("elapsed greater than zero", () => gameplayClockContainer.ElapsedFrameTime > 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -60,16 +60,16 @@ namespace osu.Game.Tests.Gameplay
|
||||
});
|
||||
|
||||
AddStep("start clock", () => gameplayClockContainer.Start());
|
||||
AddUntilStep("current time greater 2000", () => gameplayClockContainer.GameplayClock.CurrentTime > 2000);
|
||||
AddUntilStep("current time greater 2000", () => gameplayClockContainer.CurrentTime > 2000);
|
||||
|
||||
double timeAtReset = 0;
|
||||
AddStep("reset clock", () =>
|
||||
{
|
||||
timeAtReset = gameplayClockContainer.GameplayClock.CurrentTime;
|
||||
timeAtReset = gameplayClockContainer.CurrentTime;
|
||||
gameplayClockContainer.Reset();
|
||||
});
|
||||
|
||||
AddAssert("current time < time at reset", () => gameplayClockContainer.GameplayClock.CurrentTime < timeAtReset);
|
||||
AddAssert("current time < time at reset", () => gameplayClockContainer.CurrentTime < timeAtReset);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -11,8 +11,10 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Configuration;
|
||||
@ -36,6 +38,9 @@ namespace osu.Game.Tests.Gameplay
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestRetrieveTopLevelSample()
|
||||
{
|
||||
@ -72,7 +77,6 @@ namespace osu.Game.Tests.Gameplay
|
||||
|
||||
Add(gameplayContainer = new MasterGameplayClockContainer(working, 0)
|
||||
{
|
||||
IsPaused = { Value = true },
|
||||
Child = new FrameStabilityContainer
|
||||
{
|
||||
Child = sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1))
|
||||
@ -101,7 +105,6 @@ namespace osu.Game.Tests.Gameplay
|
||||
Add(gameplayContainer = new MasterGameplayClockContainer(working, start_time)
|
||||
{
|
||||
StartTime = start_time,
|
||||
IsPaused = { Value = true },
|
||||
Child = new FrameStabilityContainer
|
||||
{
|
||||
Child = sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1))
|
||||
@ -136,7 +139,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
|
||||
beatmapSkinSourceContainer.Add(sample = new TestDrawableStoryboardSample(new StoryboardSampleInfo("test-sample", 1, 1))
|
||||
{
|
||||
Clock = gameplayContainer.GameplayClock
|
||||
Clock = gameplayContainer
|
||||
});
|
||||
});
|
||||
|
||||
@ -202,6 +205,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
|
||||
#region IResourceStorageProvider
|
||||
|
||||
public IRenderer Renderer => host.Renderer;
|
||||
public AudioManager AudioManager => Audio;
|
||||
public IResourceStore<byte[]> Files => null;
|
||||
public new IResourceStore<byte[]> Resources => base.Resources;
|
||||
|
@ -36,6 +36,23 @@ namespace osu.Game.Tests.NonVisual
|
||||
Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAudioEqualityCaseSensitivity()
|
||||
{
|
||||
var beatmapSetA = TestResources.CreateTestBeatmapSetInfo(1);
|
||||
var beatmapSetB = TestResources.CreateTestBeatmapSetInfo(1);
|
||||
|
||||
// empty by default so let's set it..
|
||||
beatmapSetA.Beatmaps.First().Metadata.AudioFile = "audio.mp3";
|
||||
beatmapSetB.Beatmaps.First().Metadata.AudioFile = "audio.mp3";
|
||||
|
||||
addAudioFile(beatmapSetA, "abc", "AuDiO.mP3");
|
||||
addAudioFile(beatmapSetB, "abc", "audio.mp3");
|
||||
|
||||
Assert.AreNotEqual(beatmapSetA, beatmapSetB);
|
||||
Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAudioEqualitySameHash()
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Timing;
|
||||
@ -30,7 +31,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
public List<Bindable<double>> MutableNonGameplayAdjustments { get; } = new List<Bindable<double>>();
|
||||
|
||||
public override IEnumerable<Bindable<double>> NonGameplayAdjustments => MutableNonGameplayAdjustments;
|
||||
public override IEnumerable<double> NonGameplayAdjustments => MutableNonGameplayAdjustments.Select(b => b.Value);
|
||||
|
||||
public TestGameplayClock(IFrameBasedClock underlyingClock)
|
||||
: base(underlyingClock)
|
||||
|
@ -11,7 +11,7 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
@ -27,6 +27,9 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
||||
private const string animation_name = "animation";
|
||||
private const int frame_count = 6;
|
||||
|
||||
[Resolved]
|
||||
private IRenderer renderer { get; set; }
|
||||
|
||||
[Cached(typeof(IAnimationTimeReference))]
|
||||
private TestAnimationTimeReference animationTimeReference = new TestAnimationTimeReference();
|
||||
|
||||
@ -35,9 +38,12 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
||||
[Test]
|
||||
public void TestAnimationTimeReferenceChange()
|
||||
{
|
||||
ISkin skin = new TestSkin();
|
||||
AddStep("get animation", () =>
|
||||
{
|
||||
ISkin skin = new TestSkin(renderer);
|
||||
Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false));
|
||||
});
|
||||
|
||||
AddStep("get animation", () => Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false)));
|
||||
AddAssert("frame count correct", () => animation.FrameCount == frame_count);
|
||||
assertPlaybackPosition(0);
|
||||
|
||||
@ -55,9 +61,16 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
||||
{
|
||||
private static readonly string[] lookup_names = Enumerable.Range(0, frame_count).Select(frame => $"{animation_name}-{frame}").ToArray();
|
||||
|
||||
private readonly IRenderer renderer;
|
||||
|
||||
public TestSkin(IRenderer renderer)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||
{
|
||||
return lookup_names.Contains(componentName) ? Texture.WhitePixel : null;
|
||||
return lookup_names.Contains(componentName) ? renderer.WhitePixel : null;
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
||||
|
@ -11,6 +11,8 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Rendering.Dummy;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Game.Database;
|
||||
@ -141,6 +143,7 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
||||
this.textureStore = textureStore;
|
||||
}
|
||||
|
||||
public IRenderer Renderer => new DummyRenderer();
|
||||
public AudioManager AudioManager => null;
|
||||
public IResourceStore<byte[]> Files => null;
|
||||
public IResourceStore<byte[]> Resources => null;
|
||||
|
@ -6,6 +6,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -148,6 +149,16 @@ namespace osu.Game.Tests.Online
|
||||
Assert.That(apiMod.Settings["speed_change"], Is.EqualTo(1.01d));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSerialisedModSettingPresence()
|
||||
{
|
||||
var mod = new TestMod();
|
||||
|
||||
mod.TestSetting.Value = mod.TestSetting.Default;
|
||||
JObject serialised = JObject.Parse(JsonConvert.SerializeObject(new APIMod(mod)));
|
||||
Assert.False(serialised.ContainsKey("settings"));
|
||||
}
|
||||
|
||||
private class TestRuleset : Ruleset
|
||||
{
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[]
|
||||
|
@ -128,6 +128,8 @@ namespace osu.Game.Tests.Resources
|
||||
|
||||
var rulesetInfo = getRuleset();
|
||||
|
||||
string hash = Guid.NewGuid().ToString().ComputeMD5Hash();
|
||||
|
||||
yield return new BeatmapInfo
|
||||
{
|
||||
OnlineID = beatmapId,
|
||||
@ -136,7 +138,8 @@ namespace osu.Game.Tests.Resources
|
||||
Length = length,
|
||||
BeatmapSet = beatmapSet,
|
||||
BPM = bpm,
|
||||
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
|
||||
Hash = hash,
|
||||
MD5Hash = hash,
|
||||
Ruleset = rulesetInfo,
|
||||
Metadata = metadata.DeepClone(),
|
||||
Difficulty = new BeatmapDifficulty
|
||||
|
@ -15,11 +15,12 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.UI;
|
||||
@ -77,9 +78,9 @@ namespace osu.Game.Tests.Rulesets
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
|
||||
dependencies.CacheAs<TextureStore>(ParentTextureStore = new TestTextureStore());
|
||||
dependencies.CacheAs<TextureStore>(ParentTextureStore = new TestTextureStore(parent.Get<GameHost>().Renderer));
|
||||
dependencies.CacheAs<ISampleStore>(ParentSampleStore = new TestSampleStore());
|
||||
dependencies.CacheAs<ShaderManager>(ParentShaderManager = new TestShaderManager());
|
||||
dependencies.CacheAs<ShaderManager>(ParentShaderManager = new TestShaderManager(parent.Get<GameHost>().Renderer));
|
||||
|
||||
return new DrawableRulesetDependencies(new OsuRuleset(), dependencies);
|
||||
}
|
||||
@ -95,6 +96,11 @@ namespace osu.Game.Tests.Rulesets
|
||||
|
||||
private class TestTextureStore : TextureStore
|
||||
{
|
||||
public TestTextureStore(IRenderer renderer)
|
||||
: base(renderer)
|
||||
{
|
||||
}
|
||||
|
||||
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) => null;
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
@ -148,8 +154,8 @@ namespace osu.Game.Tests.Rulesets
|
||||
|
||||
private class TestShaderManager : ShaderManager
|
||||
{
|
||||
public TestShaderManager()
|
||||
: base(new ResourceStore<byte[]>())
|
||||
public TestShaderManager(IRenderer renderer)
|
||||
: base(renderer, new ResourceStore<byte[]>())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Game.Audio;
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
|
@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
|
@ -6,10 +6,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
@ -21,6 +22,9 @@ namespace osu.Game.Tests.Skins
|
||||
[HeadlessTest]
|
||||
public class TestSceneSkinProvidingContainer : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private IRenderer renderer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the first inserted skin after resetting (via source change)
|
||||
/// is always prioritised over others when providing the same resource.
|
||||
@ -35,7 +39,7 @@ namespace osu.Game.Tests.Skins
|
||||
{
|
||||
var sources = new List<TestSkin>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
sources.Add(new TestSkin());
|
||||
sources.Add(new TestSkin(renderer));
|
||||
|
||||
mostPrioritisedSource = sources.First();
|
||||
|
||||
@ -76,12 +80,19 @@ namespace osu.Game.Tests.Skins
|
||||
{
|
||||
public const string TEXTURE_NAME = "virtual-texture";
|
||||
|
||||
private readonly IRenderer renderer;
|
||||
|
||||
public TestSkin(IRenderer renderer)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new System.NotImplementedException();
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||
{
|
||||
if (componentName == TEXTURE_NAME)
|
||||
return Texture.WhitePixel;
|
||||
return renderer.WhitePixel;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Rendering.Dummy;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Testing;
|
||||
@ -55,6 +55,7 @@ namespace osu.Game.Tests.Skins
|
||||
lookedUpFileNames = new List<string>();
|
||||
mockResourceProvider = new Mock<IStorageResourceProvider>();
|
||||
mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio);
|
||||
mockResourceProvider.Setup(m => m.Renderer).Returns(new DummyRenderer());
|
||||
mockResourceStore = new Mock<IResourceStore<byte[]>>();
|
||||
mockResourceStore.Setup(r => r.Get(It.IsAny<string>()))
|
||||
.Callback<string>(n => lookedUpFileNames.Add(n))
|
||||
|
@ -10,6 +10,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -43,6 +44,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IRenderer renderer { get; set; }
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
@ -245,7 +249,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
Id = API.LocalUser.Value.Id + 1,
|
||||
});
|
||||
|
||||
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(Audio);
|
||||
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(renderer, Audio);
|
||||
private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio);
|
||||
|
||||
private class TestBackgroundScreenDefault : BackgroundScreenDefault
|
||||
@ -274,12 +278,15 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private class UniqueBackgroundTestWorkingBeatmap : TestWorkingBeatmap
|
||||
{
|
||||
public UniqueBackgroundTestWorkingBeatmap(AudioManager audioManager)
|
||||
private readonly IRenderer renderer;
|
||||
|
||||
public UniqueBackgroundTestWorkingBeatmap(IRenderer renderer, AudioManager audioManager)
|
||||
: base(new Beatmap(), null, audioManager)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
protected override Texture GetBackground() => new Texture(1, 1);
|
||||
protected override Texture GetBackground() => renderer.CreateTexture(1, 1);
|
||||
}
|
||||
|
||||
private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap
|
||||
|
@ -10,7 +10,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
@ -28,11 +28,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
[Resolved]
|
||||
private SessionStatics statics { get; set; }
|
||||
|
||||
[Cached(typeof(LargeTextureStore))]
|
||||
private LookupLoggingTextureStore textureStore = new LookupLoggingTextureStore();
|
||||
|
||||
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
||||
|
||||
private LookupLoggingTextureStore textureStore;
|
||||
private SeasonalBackgroundLoader backgroundLoader;
|
||||
private Container backgroundContainer;
|
||||
|
||||
@ -45,15 +43,32 @@ namespace osu.Game.Tests.Visual.Background
|
||||
"Backgrounds/bg3"
|
||||
};
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
|
||||
textureStore = new LookupLoggingTextureStore(dependencies.Get<IRenderer>());
|
||||
dependencies.CacheAs(typeof(LargeTextureStore), textureStore);
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(LargeTextureStore wrappedStore)
|
||||
{
|
||||
textureStore.AddStore(wrappedStore);
|
||||
|
||||
Add(backgroundContainer = new Container
|
||||
Child = new DependencyProvidingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
});
|
||||
CachedDependencies = new (Type, object)[]
|
||||
{
|
||||
(typeof(LargeTextureStore), textureStore)
|
||||
},
|
||||
Child = backgroundContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
@ -193,6 +208,11 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
public List<string> PerformedLookups { get; } = new List<string>();
|
||||
|
||||
public LookupLoggingTextureStore(IRenderer renderer)
|
||||
: base(renderer)
|
||||
{
|
||||
}
|
||||
|
||||
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||
{
|
||||
PerformedLookups.Add(name);
|
||||
|
@ -200,10 +200,12 @@ namespace osu.Game.Tests.Visual.Collections
|
||||
AddStep("click confirmation", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType<PopupDialogButton>().First());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
assertCollectionCount(0);
|
||||
|
||||
AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -190,7 +190,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
AddAssert("track stopped", () => !track.IsRunning);
|
||||
}
|
||||
|
||||
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null);
|
||||
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(CreateAPIBeatmapSet());
|
||||
|
||||
private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack()
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -59,15 +57,15 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
AddStep("reset clock", () => Clock.Seek(0));
|
||||
|
||||
AddStep("start clock", Clock.Start);
|
||||
AddStep("start clock", () => Clock.Start());
|
||||
AddAssert("clock running", () => Clock.IsRunning);
|
||||
|
||||
AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250));
|
||||
AddUntilStep("clock stops", () => !Clock.IsRunning);
|
||||
|
||||
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
AddUntilStep("clock stopped at end", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength));
|
||||
|
||||
AddStep("start clock again", Clock.Start);
|
||||
AddStep("start clock again", () => Clock.Start());
|
||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||
}
|
||||
|
||||
@ -76,32 +74,32 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
AddStep("reset clock", () => Clock.Seek(0));
|
||||
|
||||
AddStep("stop clock", Clock.Stop);
|
||||
AddStep("stop clock", () => Clock.Stop());
|
||||
AddAssert("clock stopped", () => !Clock.IsRunning);
|
||||
|
||||
AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength));
|
||||
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
AddAssert("clock stopped at end", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength));
|
||||
|
||||
AddStep("start clock again", Clock.Start);
|
||||
AddStep("start clock again", () => Clock.Start());
|
||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClampWhenSeekOutsideBeatmapBounds()
|
||||
{
|
||||
AddStep("stop clock", Clock.Stop);
|
||||
AddStep("stop clock", () => Clock.Stop());
|
||||
|
||||
AddStep("seek before start time", () => Clock.Seek(-1000));
|
||||
AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0);
|
||||
AddAssert("time is clamped to 0", () => Clock.CurrentTime, () => Is.EqualTo(0));
|
||||
|
||||
AddStep("seek beyond track length", () => Clock.Seek(Clock.TrackLength + 1000));
|
||||
AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
AddAssert("time is clamped to track length", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength));
|
||||
|
||||
AddStep("seek smoothly before start time", () => Clock.SeekSmoothlyTo(-1000));
|
||||
AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0);
|
||||
AddUntilStep("time is clamped to 0", () => Clock.CurrentTime, () => Is.EqualTo(0));
|
||||
|
||||
AddStep("seek smoothly beyond track length", () => Clock.SeekSmoothlyTo(Clock.TrackLength + 1000));
|
||||
AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
AddUntilStep("time is clamped to track length", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -60,17 +60,17 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
// Forwards
|
||||
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
AddStep("Seek(33)", () => Clock.Seek(33));
|
||||
AddAssert("Time = 33", () => Clock.CurrentTime == 33);
|
||||
checkTime(33);
|
||||
AddStep("Seek(89)", () => Clock.Seek(89));
|
||||
AddAssert("Time = 89", () => Clock.CurrentTime == 89);
|
||||
checkTime(89);
|
||||
|
||||
// Backwards
|
||||
AddStep("Seek(25)", () => Clock.Seek(25));
|
||||
AddAssert("Time = 25", () => Clock.CurrentTime == 25);
|
||||
checkTime(25);
|
||||
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -83,19 +83,19 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
reset();
|
||||
|
||||
AddStep("Seek(0), Snap", () => Clock.SeekSnapped(0));
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
AddStep("Seek(50), Snap", () => Clock.SeekSnapped(50));
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("Seek(100), Snap", () => Clock.SeekSnapped(100));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("Seek(175), Snap", () => Clock.SeekSnapped(175));
|
||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||
checkTime(175);
|
||||
AddStep("Seek(350), Snap", () => Clock.SeekSnapped(350));
|
||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||
checkTime(350);
|
||||
AddStep("Seek(400), Snap", () => Clock.SeekSnapped(400));
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("Seek(450), Snap", () => Clock.SeekSnapped(450));
|
||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||
checkTime(450);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -108,17 +108,17 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
reset();
|
||||
|
||||
AddStep("Seek(24), Snap", () => Clock.SeekSnapped(24));
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
AddStep("Seek(26), Snap", () => Clock.SeekSnapped(26));
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("Seek(150), Snap", () => Clock.SeekSnapped(150));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("Seek(170), Snap", () => Clock.SeekSnapped(170));
|
||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||
checkTime(175);
|
||||
AddStep("Seek(274), Snap", () => Clock.SeekSnapped(274));
|
||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||
checkTime(175);
|
||||
AddStep("Seek(276), Snap", () => Clock.SeekSnapped(276));
|
||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||
checkTime(350);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -130,15 +130,15 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
reset();
|
||||
|
||||
AddStep("SeekForward", () => Clock.SeekForward());
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("SeekForward", () => Clock.SeekForward());
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("SeekForward", () => Clock.SeekForward());
|
||||
AddAssert("Time = 200", () => Clock.CurrentTime == 200);
|
||||
checkTime(200);
|
||||
AddStep("SeekForward", () => Clock.SeekForward());
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("SeekForward", () => Clock.SeekForward());
|
||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||
checkTime(450);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -150,17 +150,17 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
reset();
|
||||
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||
checkTime(175);
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||
checkTime(350);
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||
checkTime(450);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -174,28 +174,28 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
AddStep("Seek(49)", () => Clock.Seek(49));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("Seek(49.999)", () => Clock.Seek(49.999));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("Seek(99)", () => Clock.Seek(99));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("Seek(99.999)", () => Clock.Seek(99.999));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 150);
|
||||
checkTime(150);
|
||||
AddStep("Seek(174)", () => Clock.Seek(174));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||
checkTime(175);
|
||||
AddStep("Seek(349)", () => Clock.Seek(349));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||
checkTime(350);
|
||||
AddStep("Seek(399)", () => Clock.Seek(399));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("Seek(449)", () => Clock.Seek(449));
|
||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||
checkTime(450);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -208,15 +208,15 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
AddStep("Seek(450)", () => Clock.Seek(450));
|
||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||
checkTime(350);
|
||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||
AddAssert("Time = 150", () => Clock.CurrentTime == 150);
|
||||
checkTime(150);
|
||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -229,17 +229,17 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
AddStep("Seek(450)", () => Clock.Seek(450));
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||
checkTime(350);
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||
checkTime(175);
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||
checkTime(100);
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||
checkTime(50);
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -253,16 +253,16 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
AddStep("Seek(451)", () => Clock.Seek(451));
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||
checkTime(450);
|
||||
AddStep("Seek(450.999)", () => Clock.Seek(450.999));
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||
checkTime(450);
|
||||
AddStep("Seek(401)", () => Clock.Seek(401));
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
AddStep("Seek(401.999)", () => Clock.Seek(401.999));
|
||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||
checkTime(400);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -297,9 +297,11 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddAssert("Time < lastTime", () => Clock.CurrentTime < lastTime);
|
||||
}
|
||||
|
||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||
checkTime(0);
|
||||
}
|
||||
|
||||
private void checkTime(double expectedTime) => AddAssert($"Current time is {expectedTime}", () => Clock.CurrentTime, () => Is.EqualTo(expectedTime));
|
||||
|
||||
private void reset()
|
||||
{
|
||||
AddStep("Reset", () => Clock.Seek(0));
|
||||
|
@ -4,7 +4,6 @@
|
||||
#nullable disable
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets;
|
||||
@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
private void pressAndCheckTime(Key key, double expectedTime)
|
||||
{
|
||||
AddStep($"press {key}", () => InputManager.Key(key));
|
||||
AddUntilStep($"time is {expectedTime}", () => Precision.AlmostEquals(expectedTime, EditorClock.CurrentTime, 1));
|
||||
AddUntilStep($"time is {expectedTime}", () => EditorClock.CurrentTime, () => Is.EqualTo(expectedTime).Within(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
(typeof(ScoreProcessor), actualComponentsContainer.Dependencies.Get<ScoreProcessor>()),
|
||||
(typeof(HealthProcessor), actualComponentsContainer.Dependencies.Get<HealthProcessor>()),
|
||||
(typeof(GameplayState), actualComponentsContainer.Dependencies.Get<GameplayState>()),
|
||||
(typeof(GameplayClock), actualComponentsContainer.Dependencies.Get<GameplayClock>())
|
||||
(typeof(IGameplayClock), actualComponentsContainer.Dependencies.Get<IGameplayClock>())
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -137,13 +137,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private void seekManualTo(double time) => AddStep($"seek manual clock to {time}", () => manualClock.CurrentTime = time);
|
||||
|
||||
private void confirmSeek(double time) => AddUntilStep($"wait for seek to {time}", () => consumer.Clock.CurrentTime == time);
|
||||
private void confirmSeek(double time) => AddUntilStep($"wait for seek to {time}", () => consumer.Clock.CurrentTime, () => Is.EqualTo(time));
|
||||
|
||||
private void checkFrameCount(int frames) =>
|
||||
AddAssert($"elapsed frames is {frames}", () => consumer.ElapsedFrames == frames);
|
||||
AddAssert($"elapsed frames is {frames}", () => consumer.ElapsedFrames, () => Is.EqualTo(frames));
|
||||
|
||||
private void checkRate(double rate) =>
|
||||
AddAssert($"clock rate is {rate}", () => consumer.Clock.Rate == rate);
|
||||
AddAssert($"clock rate is {rate}", () => consumer.Clock.Rate, () => Is.EqualTo(rate));
|
||||
|
||||
public class ClockConsumingChild : CompositeDrawable
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@ -21,22 +19,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestAllSamplesStopDuringSeek()
|
||||
{
|
||||
DrawableSlider slider = null;
|
||||
PoolableSkinnableSample[] samples = null;
|
||||
ISamplePlaybackDisabler sampleDisabler = null;
|
||||
DrawableSlider? slider = null;
|
||||
PoolableSkinnableSample[] samples = null!;
|
||||
ISamplePlaybackDisabler sampleDisabler = null!;
|
||||
|
||||
AddUntilStep("get variables", () =>
|
||||
{
|
||||
sampleDisabler = Player;
|
||||
slider = Player.ChildrenOfType<DrawableSlider>().MinBy(s => s.HitObject.StartTime);
|
||||
samples = slider?.ChildrenOfType<PoolableSkinnableSample>().ToArray();
|
||||
samples = slider.ChildrenOfType<PoolableSkinnableSample>().ToArray();
|
||||
|
||||
return slider != null;
|
||||
});
|
||||
|
||||
AddUntilStep("wait for slider sliding then seek", () =>
|
||||
{
|
||||
if (!slider.Tracking.Value)
|
||||
if (slider?.Tracking.Value != true)
|
||||
return false;
|
||||
|
||||
if (!samples.Any(s => s.Playing))
|
||||
|
@ -38,8 +38,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Cached]
|
||||
private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset());
|
||||
|
||||
[Cached]
|
||||
private readonly GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||
[Cached(typeof(IGameplayClock))]
|
||||
private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||
|
||||
// best way to check without exposing.
|
||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||
|
@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime;
|
||||
|
||||
public double GameplayClockTime => GameplayClockContainer.GameplayClock.CurrentTime;
|
||||
public double GameplayClockTime => GameplayClockContainer.CurrentTime;
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
if (!FirstFrameClockTime.HasValue)
|
||||
{
|
||||
FirstFrameClockTime = GameplayClockContainer.GameplayClock.CurrentTime;
|
||||
FirstFrameClockTime = GameplayClockContainer.CurrentTime;
|
||||
AddInternal(new OsuSpriteText
|
||||
{
|
||||
Text = $"GameplayStartTime: {DrawableRuleset.GameplayStartTime} "
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
base.SetUpSteps();
|
||||
|
||||
AddUntilStep("gameplay has started",
|
||||
() => Player.GameplayClockContainer.GameplayClock.CurrentTime > Player.DrawableRuleset.GameplayStartTime);
|
||||
() => Player.GameplayClockContainer.CurrentTime > Player.DrawableRuleset.GameplayStartTime);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -313,7 +313,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("pause again", () =>
|
||||
{
|
||||
Player.Pause();
|
||||
return !Player.GameplayClockContainer.GameplayClock.IsRunning;
|
||||
return !Player.GameplayClockContainer.IsRunning;
|
||||
});
|
||||
|
||||
AddAssert("loop is playing", () => getLoop().IsPlaying);
|
||||
@ -378,7 +378,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("pause overlay " + (isShown ? "shown" : "hidden"), () => Player.PauseOverlayVisible == isShown);
|
||||
|
||||
private void confirmClockRunning(bool isRunning) =>
|
||||
AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.GameplayClock.IsRunning == isRunning);
|
||||
AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.IsRunning == isRunning);
|
||||
|
||||
protected override bool AllowFail => true;
|
||||
|
||||
|
@ -29,8 +29,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Cached]
|
||||
private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset());
|
||||
|
||||
[Cached]
|
||||
private readonly GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||
[Cached(typeof(IGameplayClock))]
|
||||
private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
|
@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Audio;
|
||||
|
@ -36,8 +36,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Cached]
|
||||
private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset());
|
||||
|
||||
[Cached]
|
||||
private readonly GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||
[Cached(typeof(IGameplayClock))]
|
||||
private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||
|
||||
private IEnumerable<HUDOverlay> hudOverlays => CreatedDrawables.OfType<HUDOverlay>();
|
||||
|
||||
|
@ -13,7 +13,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
|
@ -6,6 +6,7 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
@ -22,7 +23,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
private double increment;
|
||||
|
||||
private GameplayClockContainer gameplayClockContainer;
|
||||
private GameplayClock gameplayClock;
|
||||
private IFrameBasedClock gameplayClock;
|
||||
|
||||
private const double skip_time = 6000;
|
||||
|
||||
@ -51,7 +52,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
};
|
||||
|
||||
gameplayClockContainer.Start();
|
||||
gameplayClock = gameplayClockContainer.GameplayClock;
|
||||
gameplayClock = gameplayClockContainer;
|
||||
});
|
||||
|
||||
[Test]
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time));
|
||||
|
||||
Dependencies.CacheAs(gameplayClockContainer.GameplayClock);
|
||||
Dependencies.CacheAs<IGameplayClock>(gameplayClockContainer);
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
|
@ -363,7 +363,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
private Player player => Stack.CurrentScreen as Player;
|
||||
|
||||
private double currentFrameStableTime
|
||||
=> player.ChildrenOfType<FrameStabilityContainer>().First().FrameStableClock.CurrentTime;
|
||||
=> player.ChildrenOfType<FrameStabilityContainer>().First().CurrentTime;
|
||||
|
||||
private void waitForPlayer() => AddUntilStep("wait for player", () => (Stack.CurrentScreen as Player)?.IsLoaded == true);
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestStoryboardNoSkipOutro()
|
||||
{
|
||||
CreateTest();
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
|
||||
AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("wait for fail overlay", () => Player.FailOverlay.State.Value == Visibility.Visible);
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
AddStep("set ShowResults = false", () => showResults = false);
|
||||
});
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration);
|
||||
AddWaitStep("wait", 10);
|
||||
AddAssert("no score shown", () => !Player.IsScoreShown);
|
||||
}
|
||||
@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestStoryboardEndsBeforeCompletion()
|
||||
{
|
||||
CreateTest(() => AddStep("set storyboard duration to .1s", () => currentStoryboardDuration = 100));
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
||||
}
|
||||
@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("skip overlay content not visible", () => fadeContainer().State == Visibility.Hidden);
|
||||
|
||||
AddUntilStep("skip overlay content becomes visible", () => fadeContainer().State == Visibility.Visible);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration);
|
||||
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
87
osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs
Normal file
87
osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs
Normal file
@ -0,0 +1,87 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays.Toolbar;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneToolbarUserButton : OsuManualInputManagerTestScene
|
||||
{
|
||||
public TestSceneToolbarUserButton()
|
||||
{
|
||||
Container mainContainer;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
mainContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = Toolbar.HEIGHT,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.DarkRed,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 2,
|
||||
},
|
||||
new ToolbarUserButton(),
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.DarkRed,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 2,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
AddSliderStep("scale", 0.5, 4, 1, scale => mainContainer.Scale = new Vector2((float)scale));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoginLogout()
|
||||
{
|
||||
AddStep("Log out", () => ((DummyAPIAccess)API).Logout());
|
||||
AddStep("Log in", () => ((DummyAPIAccess)API).Login("wang", "jang"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStates()
|
||||
{
|
||||
AddStep("Log in", () => ((DummyAPIAccess)API).Login("wang", "jang"));
|
||||
|
||||
foreach (var state in Enum.GetValues<APIState>())
|
||||
{
|
||||
AddStep($"Change state to {state}", () => ((DummyAPIAccess)API).SetState(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -432,8 +432,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
var user = playingUsers.Single(u => u.UserID == userId);
|
||||
|
||||
OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull());
|
||||
SpectatorClient.SendEndPlay(userId);
|
||||
OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull());
|
||||
|
||||
playingUsers.Remove(user);
|
||||
});
|
||||
@ -451,7 +451,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
private void checkPaused(int userId, bool state)
|
||||
=> AddUntilStep($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType<GameplayClockContainer>().First().GameplayClock.IsRunning != state);
|
||||
=> AddUntilStep($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType<GameplayClockContainer>().First().IsRunning != state);
|
||||
|
||||
private void checkPausedInstant(int userId, bool state)
|
||||
{
|
||||
|
@ -671,7 +671,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
for (double i = 1000; i < TestResources.QUICK_BEATMAP_LENGTH; i += 1000)
|
||||
{
|
||||
double time = i;
|
||||
AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType<GameplayClockContainer>().SingleOrDefault()?.GameplayClock.CurrentTime > time);
|
||||
AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType<GameplayClockContainer>().SingleOrDefault()?.CurrentTime > time);
|
||||
}
|
||||
|
||||
AddUntilStep("wait for results", () => multiplayerComponents.CurrentScreen is ResultsScreen);
|
||||
|
@ -83,6 +83,20 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetApprove,
|
||||
Approval = BeatmapApproval.Approved,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetApprove,
|
||||
Approval = BeatmapApproval.Loved,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetApprove,
|
||||
@ -90,6 +104,13 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetApprove,
|
||||
Approval = BeatmapApproval.Ranked,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetDelete,
|
||||
|
@ -11,9 +11,11 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
@ -35,16 +37,27 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
[Cached(typeof(IDialogOverlay))]
|
||||
private readonly DialogOverlay dialogOverlay = new DialogOverlay();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||
Dependencies.Cache(Realm);
|
||||
|
||||
base.Content.Add(content = new PopoverContainer
|
||||
base.Content.AddRange(new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(30),
|
||||
new OsuContextMenuContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = content = new PopoverContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(30),
|
||||
}
|
||||
},
|
||||
dialogOverlay
|
||||
});
|
||||
}
|
||||
|
||||
@ -121,6 +134,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
public void TestSoftDeleteSupport()
|
||||
{
|
||||
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
||||
AddStep("clear mods", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
AddStep("create content", () => Child = new ModPresetColumn
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@ -140,9 +154,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
foreach (var preset in r.All<ModPreset>())
|
||||
preset.DeletePending = true;
|
||||
}));
|
||||
AddUntilStep("no panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 0);
|
||||
AddUntilStep("no panels visible", () => !this.ChildrenOfType<ModPresetPanel>().Any());
|
||||
|
||||
AddStep("undelete preset", () => Realm.Write(r =>
|
||||
AddStep("select mods from first preset", () => SelectedMods.Value = new Mod[] { new OsuModDoubleTime(), new OsuModHardRock() });
|
||||
|
||||
AddStep("undelete presets", () => Realm.Write(r =>
|
||||
{
|
||||
foreach (var preset in r.All<ModPreset>())
|
||||
preset.DeletePending = false;
|
||||
@ -205,6 +221,46 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("popover closed", () => !this.ChildrenOfType<OsuPopover>().Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeleteFlow()
|
||||
{
|
||||
ModPresetColumn modPresetColumn = null!;
|
||||
|
||||
AddStep("create content", () => Child = modPresetColumn = new ModPresetColumn
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
AddUntilStep("items loaded", () => modPresetColumn.IsLoaded && modPresetColumn.ItemsLoaded);
|
||||
AddStep("right click first panel", () =>
|
||||
{
|
||||
var panel = this.ChildrenOfType<ModPresetPanel>().First();
|
||||
InputManager.MoveMouseTo(panel);
|
||||
InputManager.Click(MouseButton.Right);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for context menu", () => this.ChildrenOfType<OsuContextMenu>().Any());
|
||||
AddStep("click delete", () =>
|
||||
{
|
||||
var deleteItem = this.ChildrenOfType<DrawableOsuMenuItem>().Single();
|
||||
InputManager.MoveMouseTo(deleteItem);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for dialog", () => dialogOverlay.CurrentDialog is DeleteModPresetDialog);
|
||||
AddStep("hold confirm", () =>
|
||||
{
|
||||
var confirmButton = this.ChildrenOfType<PopupDialogDangerousButton>().Single();
|
||||
InputManager.MoveMouseTo(confirmButton);
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
AddUntilStep("wait for dialog to close", () => dialogOverlay.CurrentDialog == null);
|
||||
AddStep("release mouse", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
AddUntilStep("preset deletion occurred", () => this.ChildrenOfType<ModPresetPanel>().Count() == 2);
|
||||
AddAssert("preset soft-deleted", () => Realm.Run(r => r.All<ModPreset>().Count(preset => preset.DeletePending) == 1));
|
||||
}
|
||||
|
||||
private ICollection<ModPreset> createTestPresets() => new[]
|
||||
{
|
||||
new ModPreset
|
||||
|
@ -1,12 +1,15 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
@ -23,6 +26,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("reset selected mods", () => SelectedMods.SetDefault());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVariousModPresets()
|
||||
{
|
||||
@ -37,6 +46,78 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPresetSelectionStateAfterExternalModChanges()
|
||||
{
|
||||
ModPresetPanel? panel = null;
|
||||
|
||||
AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 0.5f
|
||||
});
|
||||
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("set mods to HR", () => SelectedMods.Value = new[] { new OsuModHardRock() });
|
||||
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("set mods to DT", () => SelectedMods.Value = new[] { new OsuModDoubleTime() });
|
||||
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||
AddAssert("panel is active", () => panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("set mods to HR+customised DT", () => SelectedMods.Value = new Mod[]
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime
|
||||
{
|
||||
SpeedChange = { Value = 1.25 }
|
||||
}
|
||||
});
|
||||
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||
AddAssert("panel is active", () => panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("customise mod in place", () => SelectedMods.Value.OfType<OsuModDoubleTime>().Single().SpeedChange.Value = 1.33);
|
||||
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||
|
||||
AddStep("set mods to HD+HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHidden(), new OsuModHardRock(), new OsuModDoubleTime() });
|
||||
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestActivatingPresetTogglesIncludedMods()
|
||||
{
|
||||
ModPresetPanel? panel = null;
|
||||
|
||||
AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 0.5f
|
||||
});
|
||||
|
||||
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||
|
||||
AddStep("deactivate panel", () => panel.AsNonNull().TriggerClick());
|
||||
assertSelectedModsEquivalentTo(Array.Empty<Mod>());
|
||||
|
||||
AddStep("set different mod", () => SelectedMods.Value = new[] { new OsuModHidden() });
|
||||
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||
|
||||
AddStep("set customised mod", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } });
|
||||
}
|
||||
|
||||
private void assertSelectedModsEquivalentTo(IEnumerable<Mod> mods)
|
||||
=> AddAssert("selected mods changed correctly", () => new HashSet<Mod>(SelectedMods.Value).SetEquals(mods));
|
||||
|
||||
private static IEnumerable<ModPreset> createTestPresets() => new[]
|
||||
{
|
||||
new ModPreset
|
||||
|
@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddUntilStep("any column dimmed", () => this.ChildrenOfType<ModColumn>().Any(column => !column.Active.Value));
|
||||
|
||||
ModColumn lastColumn = null;
|
||||
ModSelectColumn lastColumn = null;
|
||||
|
||||
AddAssert("last column dimmed", () => !this.ChildrenOfType<ModColumn>().Last().Active.Value);
|
||||
AddStep("request scroll to last column", () =>
|
||||
|
@ -1,18 +1,20 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Music;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -21,13 +23,25 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
private readonly BindableList<Live<BeatmapSetInfo>> beatmapSets = new BindableList<Live<BeatmapSetInfo>>();
|
||||
protected override bool UseFreshStoragePerRun => true;
|
||||
|
||||
private PlaylistOverlay playlistOverlay;
|
||||
private PlaylistOverlay playlistOverlay = null!;
|
||||
|
||||
private Live<BeatmapSetInfo> first;
|
||||
private BeatmapManager beatmapManager = null!;
|
||||
|
||||
private const int item_count = 100;
|
||||
private const int item_count = 20;
|
||||
|
||||
private List<BeatmapSetInfo> beatmapSets => beatmapManager.GetAllUsableBeatmapSets();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
Dependencies.Cache(new RealmRulesetStore(Realm));
|
||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default));
|
||||
Dependencies.Cache(Realm);
|
||||
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
@ -46,16 +60,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
}
|
||||
};
|
||||
|
||||
beatmapSets.Clear();
|
||||
|
||||
for (int i = 0; i < item_count; i++)
|
||||
{
|
||||
beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo().ToLiveUnmanaged());
|
||||
beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo());
|
||||
}
|
||||
|
||||
first = beatmapSets.First();
|
||||
|
||||
playlistOverlay.BeatmapSets.BindTo(beatmapSets);
|
||||
beatmapSets.First().ToLive(Realm);
|
||||
});
|
||||
|
||||
[Test]
|
||||
@ -70,9 +80,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddUntilStep("wait for animations to complete", () => !playlistOverlay.Transforms.Any());
|
||||
|
||||
PlaylistItem firstItem = null!;
|
||||
|
||||
AddStep("hold 1st item handle", () =>
|
||||
{
|
||||
var handle = this.ChildrenOfType<OsuRearrangeableListItem<Live<BeatmapSetInfo>>.PlaylistItemHandle>().First();
|
||||
firstItem = this.ChildrenOfType<PlaylistItem>().First();
|
||||
var handle = firstItem.ChildrenOfType<PlaylistItem.PlaylistItemHandle>().First();
|
||||
|
||||
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
@ -83,7 +97,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.BottomLeft);
|
||||
});
|
||||
|
||||
AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first));
|
||||
AddAssert("first is moved", () => playlistOverlay.ChildrenOfType<Playlist>().Single().Items.ElementAt(4).Value.Equals(firstItem.Model.Value));
|
||||
|
||||
AddStep("release handle", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
}
|
||||
@ -101,6 +115,68 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
() => playlistOverlay.ChildrenOfType<PlaylistItem>()
|
||||
.Where(item => item.MatchingFilter)
|
||||
.All(item => item.FilterTerms.Any(term => term.ToString().Contains("10"))));
|
||||
|
||||
AddStep("Import new non-matching beatmap", () =>
|
||||
{
|
||||
var testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo(1);
|
||||
testBeatmapSetInfo.Beatmaps.Single().Metadata.Title = "no guid";
|
||||
beatmapManager.Import(testBeatmapSetInfo);
|
||||
});
|
||||
|
||||
AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh()));
|
||||
|
||||
AddAssert("results filtered correctly",
|
||||
() => playlistOverlay.ChildrenOfType<PlaylistItem>()
|
||||
.Where(item => item.MatchingFilter)
|
||||
.All(item => item.FilterTerms.Any(term => term.ToString().Contains("10"))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCollectionFiltering()
|
||||
{
|
||||
NowPlayingCollectionDropdown collectionDropdown() => playlistOverlay.ChildrenOfType<NowPlayingCollectionDropdown>().Single();
|
||||
|
||||
AddStep("Add collection", () =>
|
||||
{
|
||||
Dependencies.Get<RealmAccess>().Write(r =>
|
||||
{
|
||||
r.RemoveAll<BeatmapCollection>();
|
||||
r.Add(new BeatmapCollection("wang"));
|
||||
});
|
||||
});
|
||||
|
||||
AddUntilStep("wait for dropdown to have new collection", () => collectionDropdown().Items.Count() == 2);
|
||||
|
||||
AddStep("Filter to collection", () =>
|
||||
{
|
||||
collectionDropdown().Current.Value = collectionDropdown().Items.Last();
|
||||
});
|
||||
|
||||
AddUntilStep("No items present", () => !playlistOverlay.ChildrenOfType<PlaylistItem>().Any(i => i.MatchingFilter));
|
||||
|
||||
AddStep("Import new non-matching beatmap", () =>
|
||||
{
|
||||
beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo(1));
|
||||
});
|
||||
|
||||
AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh()));
|
||||
|
||||
AddUntilStep("No items matching", () => !playlistOverlay.ChildrenOfType<PlaylistItem>().Any(i => i.MatchingFilter));
|
||||
|
||||
BeatmapSetInfo collectionAddedBeatmapSet = null!;
|
||||
|
||||
AddStep("Import new matching beatmap", () =>
|
||||
{
|
||||
collectionAddedBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1);
|
||||
|
||||
beatmapManager.Import(collectionAddedBeatmapSet);
|
||||
Realm.Write(r => r.All<BeatmapCollection>().First().BeatmapMD5Hashes.Add(collectionAddedBeatmapSet.Beatmaps.First().MD5Hash));
|
||||
});
|
||||
|
||||
AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh()));
|
||||
|
||||
AddUntilStep("Only matching item",
|
||||
() => playlistOverlay.ChildrenOfType<PlaylistItem>().Where(i => i.MatchingFilter).Select(i => i.Model.ID), () => Is.EquivalentTo(new[] { collectionAddedBeatmapSet.ID }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,8 +199,8 @@ namespace osu.Game.Beatmaps
|
||||
Debug.Assert(x.BeatmapSet != null);
|
||||
Debug.Assert(y.BeatmapSet != null);
|
||||
|
||||
string? fileHashX = x.BeatmapSet.Files.FirstOrDefault(f => f.Filename == getFilename(x.Metadata))?.File.Hash;
|
||||
string? fileHashY = y.BeatmapSet.Files.FirstOrDefault(f => f.Filename == getFilename(y.Metadata))?.File.Hash;
|
||||
string? fileHashX = x.BeatmapSet.GetFile(getFilename(x.Metadata))?.File.Hash;
|
||||
string? fileHashY = y.BeatmapSet.GetFile(getFilename(y.Metadata))?.File.Hash;
|
||||
|
||||
return fileHashX == fileHashY;
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Linq;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
|
@ -300,7 +300,7 @@ namespace osu.Game.Beatmaps
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity.
|
||||
var existingFileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase));
|
||||
var existingFileInfo = beatmapInfo.Path != null ? setInfo.GetFile(beatmapInfo.Path) : null;
|
||||
string targetFilename = createBeatmapFilenameFromMetadata(beatmapInfo);
|
||||
|
||||
// ensure that two difficulties from the set don't point at the same beatmap file.
|
||||
|
@ -84,13 +84,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
||||
/// The path returned is relative to the user file storage.
|
||||
/// </summary>
|
||||
/// <param name="filename">The name of the file to get the storage path of.</param>
|
||||
public string? GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.File.GetStoragePath();
|
||||
|
||||
public bool Equals(BeatmapSetInfo? other)
|
||||
{
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
33
osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs
Normal file
33
osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Models;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public static class BeatmapSetInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
||||
/// The path returned is relative to the user file storage.
|
||||
/// The lookup is case insensitive.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to operate on.</param>
|
||||
/// <param name="filename">The name of the file to get the storage path of.</param>
|
||||
public static string? GetPathForFile(this IHasRealmFiles model, string filename) => model.GetFile(filename)?.File.GetStoragePath();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file usage for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
||||
/// The path returned is relative to the user file storage.
|
||||
/// The lookup is case insensitive.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to operate on.</param>
|
||||
/// <param name="filename">The name of the file to get the storage path of.</param>
|
||||
public static RealmNamedFileUsage? GetFile(this IHasRealmFiles model, string filename) =>
|
||||
model.Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Rendering.Dummy;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Lists;
|
||||
@ -56,7 +58,7 @@ namespace osu.Game.Beatmaps
|
||||
this.resources = resources;
|
||||
this.host = host;
|
||||
this.files = files;
|
||||
largeTextureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(files));
|
||||
largeTextureStore = new LargeTextureStore(host?.Renderer ?? new DummyRenderer(), host?.CreateTextureLoaderStore(files));
|
||||
this.trackStore = trackStore;
|
||||
}
|
||||
|
||||
@ -110,6 +112,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore;
|
||||
ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
|
||||
IRenderer IStorageResourceProvider.Renderer => host?.Renderer ?? new DummyRenderer();
|
||||
AudioManager IStorageResourceProvider.AudioManager => audioManager;
|
||||
RealmAccess IStorageResourceProvider.RealmAccess => null;
|
||||
IResourceStore<byte[]> IStorageResourceProvider.Files => files;
|
||||
|
@ -3,33 +3,17 @@
|
||||
|
||||
using System;
|
||||
using Humanizer;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Collections
|
||||
{
|
||||
public class DeleteCollectionDialog : PopupDialog
|
||||
public class DeleteCollectionDialog : DeleteConfirmationDialog
|
||||
{
|
||||
public DeleteCollectionDialog(Live<BeatmapCollection> collection, Action deleteAction)
|
||||
{
|
||||
HeaderText = "Confirm deletion of";
|
||||
BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})");
|
||||
|
||||
Icon = FontAwesome.Regular.TrashAlt;
|
||||
|
||||
Buttons = new PopupDialogButton[]
|
||||
{
|
||||
new PopupDialogOkButton
|
||||
{
|
||||
Text = @"Yes. Go for it.",
|
||||
Action = deleteAction
|
||||
},
|
||||
new PopupDialogCancelButton
|
||||
{
|
||||
Text = @"No! Abort mission!",
|
||||
},
|
||||
};
|
||||
DeleteAction = deleteAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,20 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum BackgroundSource
|
||||
{
|
||||
[LocalisableDescription(typeof(SkinSettingsStrings), nameof(SkinSettingsStrings.SkinSectionHeader))]
|
||||
Skin,
|
||||
|
||||
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.BeatmapHeader))]
|
||||
Beatmap,
|
||||
|
||||
[Description("Beatmap (with storyboard / video)")]
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.BeatmapWithStoryboard))]
|
||||
BeatmapWithStoryboard,
|
||||
}
|
||||
}
|
||||
|
@ -3,17 +3,20 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum DiscordRichPresenceMode
|
||||
{
|
||||
[LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.DiscordPresenceOff))]
|
||||
Off,
|
||||
|
||||
[Description("Hide identifiable information")]
|
||||
[LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.HideIdentifiableInformation))]
|
||||
Limited,
|
||||
|
||||
[LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.DiscordPresenceFull))]
|
||||
Full
|
||||
}
|
||||
}
|
||||
|
@ -3,17 +3,20 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum HUDVisibilityMode
|
||||
{
|
||||
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.NeverShowHUD))]
|
||||
Never,
|
||||
|
||||
[Description("Hide during gameplay")]
|
||||
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.HideDuringGameplay))]
|
||||
HideDuringGameplay,
|
||||
|
||||
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.AlwaysShowHUD))]
|
||||
Always
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,17 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum RandomSelectAlgorithm
|
||||
{
|
||||
[Description("Never repeat")]
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.NeverRepeat))]
|
||||
RandomPermutation,
|
||||
|
||||
[Description("True Random")]
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.TrueRandom))]
|
||||
Random
|
||||
}
|
||||
}
|
||||
|
@ -3,17 +3,23 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum ScalingMode
|
||||
{
|
||||
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScalingOff))]
|
||||
Off,
|
||||
|
||||
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverything))]
|
||||
Everything,
|
||||
|
||||
[Description("Excluding overlays")]
|
||||
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverythingExcludingOverlays))]
|
||||
ExcludeOverlays,
|
||||
|
||||
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleGameplay))]
|
||||
Gameplay,
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,17 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum ScreenshotFormat
|
||||
{
|
||||
[Description("JPG (web-friendly)")]
|
||||
[LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.Jpg))]
|
||||
Jpg = 1,
|
||||
|
||||
[Description("PNG (lossless)")]
|
||||
[LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.Png))]
|
||||
Png = 2
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum SeasonalBackgroundMode
|
||||
@ -10,16 +13,19 @@ namespace osu.Game.Configuration
|
||||
/// <summary>
|
||||
/// Seasonal backgrounds are shown regardless of season, if at all available.
|
||||
/// </summary>
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.AlwaysSeasonalBackground))]
|
||||
Always,
|
||||
|
||||
/// <summary>
|
||||
/// Seasonal backgrounds are shown only during their corresponding season.
|
||||
/// </summary>
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.SometimesSeasonalBackground))]
|
||||
Sometimes,
|
||||
|
||||
/// <summary>
|
||||
/// Seasonal backgrounds are never shown.
|
||||
/// </summary>
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.NeverSeasonalBackground))]
|
||||
Never
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Models;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@ -11,8 +12,16 @@ namespace osu.Game.Database
|
||||
/// </summary>
|
||||
public interface IHasRealmFiles
|
||||
{
|
||||
/// <summary>
|
||||
/// Available files in this model, with locally filenames.
|
||||
/// When performing lookups, consider using <see cref="BeatmapSetInfoExtensions.GetFile"/> or <see cref="BeatmapSetInfoExtensions.GetPathForFile"/> to do case-insensitive lookups.
|
||||
/// </summary>
|
||||
IList<RealmNamedFileUsage> Files { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A combined hash representing the model, based on the files it contains.
|
||||
/// Implementation specific.
|
||||
/// </summary>
|
||||
string Hash { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
@ -27,27 +25,30 @@ namespace osu.Game.Database
|
||||
public class LegacyImportManager : Component
|
||||
{
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
private SkinManager skins { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
private BeatmapManager beatmaps { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private ScoreManager scores { get; set; }
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private OsuGame game { get; set; }
|
||||
private ScoreManager scores { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private IDialogOverlay dialogOverlay { get; set; }
|
||||
private OsuGame? game { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RealmAccess realmAccess { get; set; }
|
||||
private IDialogOverlay dialogOverlay { get; set; } = null!;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private DesktopGameHost desktopGameHost { get; set; }
|
||||
[Resolved]
|
||||
private RealmAccess realmAccess { get; set; } = null!;
|
||||
|
||||
private StableStorage cachedStorage;
|
||||
[Resolved(canBeNull: true)] // canBeNull required while we remain on mono for mobile platforms.
|
||||
private DesktopGameHost? desktopGameHost { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private INotificationOverlay? notifications { get; set; }
|
||||
|
||||
private StableStorage? cachedStorage;
|
||||
|
||||
public bool SupportsImportFromStable => RuntimeInfo.IsDesktop;
|
||||
|
||||
@ -98,6 +99,9 @@ namespace osu.Game.Database
|
||||
stableStorage = GetCurrentStableStorage();
|
||||
}
|
||||
|
||||
if (stableStorage == null)
|
||||
return;
|
||||
|
||||
var importTasks = new List<Task>();
|
||||
|
||||
Task beatmapImportTask = Task.CompletedTask;
|
||||
@ -108,7 +112,14 @@ namespace osu.Game.Database
|
||||
importTasks.Add(new LegacySkinImporter(skins).ImportFromStableAsync(stableStorage));
|
||||
|
||||
if (content.HasFlagFast(StableContent.Collections))
|
||||
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyCollectionImporter(realmAccess).ImportFromStorage(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
||||
{
|
||||
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyCollectionImporter(realmAccess)
|
||||
{
|
||||
// Other legacy importers import via model managers which handle the posting of notifications.
|
||||
// Collections are an exception.
|
||||
PostNotification = n => notifications?.Post(n)
|
||||
}.ImportFromStorage(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
||||
}
|
||||
|
||||
if (content.HasFlagFast(StableContent.Scores))
|
||||
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyScoreImporter(scores).ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
||||
@ -116,7 +127,7 @@ namespace osu.Game.Database
|
||||
await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public StableStorage GetCurrentStableStorage()
|
||||
public StableStorage? GetCurrentStableStorage()
|
||||
{
|
||||
if (cachedStorage != null)
|
||||
return cachedStorage;
|
||||
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
@ -79,7 +80,7 @@ namespace osu.Game.Database
|
||||
/// </summary>
|
||||
public void AddFile(TModel item, Stream contents, string filename, Realm realm)
|
||||
{
|
||||
var existing = item.Files.FirstOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase));
|
||||
var existing = item.GetFile(filename);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using Realms;
|
||||
@ -172,6 +173,11 @@ namespace osu.Game.Database
|
||||
if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal))
|
||||
Filename += realm_extension;
|
||||
|
||||
#if DEBUG
|
||||
if (!DebugUtils.IsNUnitRunning)
|
||||
applyFilenameSchemaSuffix(ref Filename);
|
||||
#endif
|
||||
|
||||
string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}";
|
||||
|
||||
// Attempt to recover a newer database version if available.
|
||||
@ -211,6 +217,51 @@ namespace osu.Game.Database
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some developers may be annoyed if a newer version migration (ie. caused by testing a pull request)
|
||||
/// cause their test database to be unusable with previous versions.
|
||||
/// To get around this, store development databases against their realm version.
|
||||
/// Note that this means changes made on newer realm versions will disappear.
|
||||
/// </summary>
|
||||
private void applyFilenameSchemaSuffix(ref string filename)
|
||||
{
|
||||
string originalFilename = filename;
|
||||
|
||||
filename = getVersionedFilename(schema_version);
|
||||
|
||||
// First check if the current realm version already exists...
|
||||
if (storage.Exists(filename))
|
||||
return;
|
||||
|
||||
// Check for a previous version we can use as a base database to migrate from...
|
||||
for (int i = schema_version - 1; i >= 0; i--)
|
||||
{
|
||||
string previousFilename = getVersionedFilename(i);
|
||||
|
||||
if (storage.Exists(previousFilename))
|
||||
{
|
||||
copyPreviousVersion(previousFilename, filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, check for a non-versioned file exists (aka before this method was added)...
|
||||
if (storage.Exists(originalFilename))
|
||||
copyPreviousVersion(originalFilename, filename);
|
||||
|
||||
void copyPreviousVersion(string previousFilename, string newFilename)
|
||||
{
|
||||
using (var previous = storage.GetStream(previousFilename))
|
||||
using (var current = storage.CreateFileSafely(newFilename))
|
||||
{
|
||||
Logger.Log(@$"Copying previous realm database {previousFilename} to {newFilename} for migration to schema version {schema_version}");
|
||||
previous.CopyTo(current);
|
||||
}
|
||||
}
|
||||
|
||||
string getVersionedFilename(int version) => originalFilename.Replace(realm_extension, $"_{version}{realm_extension}");
|
||||
}
|
||||
|
||||
private void attemptRecoverFromFile(string recoveryFilename)
|
||||
{
|
||||
Logger.Log($@"Performing recovery from {recoveryFilename}", LoggingTarget.Database);
|
||||
@ -292,6 +343,11 @@ namespace osu.Game.Database
|
||||
foreach (var s in pendingDeleteSkins)
|
||||
realm.Remove(s);
|
||||
|
||||
var pendingDeletePresets = realm.All<ModPreset>().Where(s => s.DeletePending);
|
||||
|
||||
foreach (var s in pendingDeletePresets)
|
||||
realm.Remove(s);
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,8 @@ using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Allocation;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.Batches;
|
||||
using osu.Framework.Graphics.OpenGL.Buffers;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Rendering.Vertices;
|
||||
using osu.Framework.Lists;
|
||||
|
||||
namespace osu.Game.Graphics.Backgrounds
|
||||
@ -88,7 +87,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
private Random stableRandom;
|
||||
private IShader shader;
|
||||
private readonly Texture texture;
|
||||
private Texture texture;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new triangle visualisation.
|
||||
@ -98,13 +97,12 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
if (seed != null)
|
||||
stableRandom = new Random(seed.Value);
|
||||
|
||||
texture = Texture.WhitePixel;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ShaderManager shaders)
|
||||
private void load(IRenderer renderer, ShaderManager shaders)
|
||||
{
|
||||
texture = renderer.WhitePixel;
|
||||
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
|
||||
}
|
||||
|
||||
@ -184,8 +182,8 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
private void addTriangles(bool randomY)
|
||||
{
|
||||
// limited by the maximum size of QuadVertexBuffer for safety.
|
||||
const int max_triangles = QuadVertexBuffer<TexturedVertex2D>.MAX_QUADS;
|
||||
// Limited by the maximum size of QuadVertexBuffer for safety.
|
||||
const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2);
|
||||
|
||||
AimCount = (int)Math.Min(max_triangles, (DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio));
|
||||
|
||||
@ -251,7 +249,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
||||
private Vector2 size;
|
||||
|
||||
private QuadBatch<TexturedVertex2D> vertexBatch;
|
||||
private IVertexBatch<TexturedVertex2D> vertexBatch;
|
||||
|
||||
public TrianglesDrawNode(Triangles source)
|
||||
: base(source)
|
||||
@ -270,14 +268,14 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
parts.AddRange(Source.parts);
|
||||
}
|
||||
|
||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||
public override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(vertexAction);
|
||||
base.Draw(renderer);
|
||||
|
||||
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
|
||||
{
|
||||
vertexBatch?.Dispose();
|
||||
vertexBatch = new QuadBatch<TexturedVertex2D>(Source.AimCount, 1);
|
||||
vertexBatch = renderer.CreateQuadBatch<TexturedVertex2D>(Source.AimCount, 1);
|
||||
}
|
||||
|
||||
shader.Bind();
|
||||
@ -297,7 +295,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||
colourInfo.ApplyChild(particle.Colour);
|
||||
|
||||
DrawTriangle(
|
||||
renderer.DrawTriangle(
|
||||
texture,
|
||||
triangle,
|
||||
colourInfo,
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Rendering.Vertices;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
@ -6,8 +6,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Utils;
|
||||
@ -89,7 +89,7 @@ namespace osu.Game.Graphics
|
||||
currentTime = source.Time.Current;
|
||||
}
|
||||
|
||||
protected override void Blit(Action<TexturedVertex2D> vertexAction)
|
||||
protected override void Blit(IRenderer renderer)
|
||||
{
|
||||
double time = currentTime - startTime;
|
||||
|
||||
@ -112,9 +112,9 @@ namespace osu.Game.Graphics
|
||||
Vector2Extensions.Transform(rect.BottomRight, DrawInfo.Matrix)
|
||||
);
|
||||
|
||||
DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction,
|
||||
new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
||||
null, TextureCoords);
|
||||
renderer.DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha),
|
||||
inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
||||
textureCoords: TextureCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@ using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Utils;
|
||||
@ -107,7 +107,7 @@ namespace osu.Game.Graphics
|
||||
sourceSize = Source.DrawSize;
|
||||
}
|
||||
|
||||
protected override void Blit(Action<TexturedVertex2D> vertexAction)
|
||||
protected override void Blit(IRenderer renderer)
|
||||
{
|
||||
foreach (var p in particles)
|
||||
{
|
||||
@ -136,9 +136,9 @@ namespace osu.Game.Graphics
|
||||
transformPosition(rect.BottomRight, rect.Centre, angle)
|
||||
);
|
||||
|
||||
DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction,
|
||||
new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
||||
null, TextureCoords);
|
||||
renderer.DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha),
|
||||
inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
||||
textureCoords: TextureCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,9 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
|
||||
@ -57,11 +56,11 @@ namespace osu.Game.Graphics.Sprites
|
||||
progress = source.animationProgress;
|
||||
}
|
||||
|
||||
protected override void Blit(Action<TexturedVertex2D> vertexAction)
|
||||
protected override void Blit(IRenderer renderer)
|
||||
{
|
||||
Shader.GetUniform<float>("progress").UpdateValue(ref progress);
|
||||
GetAppropriateShader(renderer).GetUniform<float>("progress").UpdateValue(ref progress);
|
||||
|
||||
base.Blit(vertexAction);
|
||||
base.Blit(renderer);
|
||||
}
|
||||
|
||||
protected override bool CanDrawOpaqueInterior => false;
|
||||
|
@ -167,6 +167,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// If the game goes into a suspended state (ie. debugger attached or backgrounded on a mobile device)
|
||||
// we want to ignore really long periods of no processing.
|
||||
if (updateClock.ElapsedFrameTime > 10000)
|
||||
return;
|
||||
|
||||
mainContent.Width = Math.Max(mainContent.Width, counters.DrawWidth);
|
||||
|
||||
// Handle the case where the window has become inactive or the user changed the
|
||||
@ -177,15 +182,15 @@ namespace osu.Game.Graphics.UserInterface
|
||||
// use elapsed frame time rather then FramesPerSecond to better catch stutter frames.
|
||||
bool hasDrawSpike = displayedFpsCount > (1000 / spike_time_ms) && drawClock.ElapsedFrameTime > spike_time_ms;
|
||||
|
||||
// note that we use an elapsed time here of 1 intentionally.
|
||||
// this weights all updates equally. if we passed in the elapsed time, longer frames would be weighted incorrectly lower.
|
||||
displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : 100, 1);
|
||||
const float damp_time = 100;
|
||||
|
||||
displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : damp_time, updateClock.ElapsedFrameTime);
|
||||
|
||||
if (hasDrawSpike)
|
||||
// show spike time using raw elapsed value, to account for `FramesPerSecond` being so averaged spike frames don't show.
|
||||
displayedFpsCount = 1000 / drawClock.ElapsedFrameTime;
|
||||
else
|
||||
displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, 100, Time.Elapsed);
|
||||
displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, damp_time, Time.Elapsed);
|
||||
|
||||
if (Time.Current - lastUpdate > min_time_between_updates)
|
||||
{
|
||||
@ -203,7 +208,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
if (hasSignificantChanges)
|
||||
requestDisplay();
|
||||
else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000)
|
||||
else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000 && !IsHovered)
|
||||
{
|
||||
mainContent.FadeTo(0, 300, Easing.OutQuint);
|
||||
isDisplayed = false;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user