mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 00:23:59 +09:00
Merge branch 'master' into remove-gamefield-test
This commit is contained in:
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Edit.Screens.Compose;
|
using osu.Game.Screens.Edit.Screens.Compose;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
@ -13,24 +12,15 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestCaseEditorCompose : OsuTestCase
|
public class TestCaseEditorCompose : EditorClockTestCase
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Compose) };
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Compose) };
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
|
||||||
=> dependencies = new DependencyContainer(parent);
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase osuGame)
|
private void load(OsuGameBase osuGame)
|
||||||
{
|
{
|
||||||
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
|
||||||
dependencies.CacheAs<IAdjustableClock>(clock);
|
|
||||||
dependencies.CacheAs<IFrameBasedClock>(clock);
|
|
||||||
|
|
||||||
var compose = new Compose();
|
var compose = new Compose();
|
||||||
compose.Beatmap.BindTo(osuGame.Beatmap);
|
compose.Beatmap.BindTo(osuGame.Beatmap);
|
||||||
|
|
||||||
|
@ -3,52 +3,35 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Osu;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Screens.Compose;
|
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseEditorSeekSnapping : OsuTestCase
|
public class TestCaseEditorSeekSnapping : EditorClockTestCase
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(HitObjectComposer) };
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(HitObjectComposer) };
|
||||||
|
|
||||||
private Track track;
|
public TestCaseEditorSeekSnapping()
|
||||||
private HitObjectComposer composer;
|
{
|
||||||
|
BeatDivisor.Value = 4;
|
||||||
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(4);
|
}
|
||||||
|
|
||||||
private DecoupleableInterpolatingFramedClock clock;
|
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
|
||||||
=> dependencies = new DependencyContainer(parent);
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase osuGame)
|
private void load(OsuGameBase osuGame)
|
||||||
{
|
{
|
||||||
clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
|
||||||
dependencies.CacheAs<IAdjustableClock>(clock);
|
|
||||||
dependencies.CacheAs<IFrameBasedClock>(clock);
|
|
||||||
dependencies.Cache(beatDivisor);
|
|
||||||
|
|
||||||
var testBeatmap = new Beatmap
|
var testBeatmap = new Beatmap
|
||||||
{
|
{
|
||||||
ControlPointInfo = new ControlPointInfo
|
ControlPointInfo = new ControlPointInfo
|
||||||
@ -71,22 +54,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
};
|
};
|
||||||
|
|
||||||
osuGame.Beatmap.Value = new TestWorkingBeatmap(testBeatmap);
|
osuGame.Beatmap.Value = new TestWorkingBeatmap(testBeatmap);
|
||||||
track = osuGame.Beatmap.Value.Track;
|
|
||||||
|
|
||||||
Child = new GridContainer
|
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[] { composer = new TestHitObjectComposer(new OsuRuleset()) },
|
|
||||||
new Drawable[] { new TimingPointVisualiser(testBeatmap, track) { Clock = clock } },
|
|
||||||
},
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.Distributed),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
testSeekNoSnapping();
|
testSeekNoSnapping();
|
||||||
testSeekSnappingOnBeat();
|
testSeekSnappingOnBeat();
|
||||||
@ -107,18 +76,18 @@ namespace osu.Game.Tests.Visual
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
// Forwards
|
// Forwards
|
||||||
AddStep("Seek(0)", () => composer.SeekTo(0));
|
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
AddStep("Seek(33)", () => composer.SeekTo(33));
|
AddStep("Seek(33)", () => Clock.Seek(33));
|
||||||
AddAssert("Time = 33", () => clock.CurrentTime == 33);
|
AddAssert("Time = 33", () => Clock.CurrentTime == 33);
|
||||||
AddStep("Seek(89)", () => composer.SeekTo(89));
|
AddStep("Seek(89)", () => Clock.Seek(89));
|
||||||
AddAssert("Time = 89", () => clock.CurrentTime == 89);
|
AddAssert("Time = 89", () => Clock.CurrentTime == 89);
|
||||||
|
|
||||||
// Backwards
|
// Backwards
|
||||||
AddStep("Seek(25)", () => composer.SeekTo(25));
|
AddStep("Seek(25)", () => Clock.Seek(25));
|
||||||
AddAssert("Time = 25", () => clock.CurrentTime == 25);
|
AddAssert("Time = 25", () => Clock.CurrentTime == 25);
|
||||||
AddStep("Seek(0)", () => composer.SeekTo(0));
|
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -129,20 +98,20 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(0), Snap", () => composer.SeekTo(0, true));
|
AddStep("Seek(0), Snap", () => Clock.SeekSnapped(0));
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
AddStep("Seek(50), Snap", () => composer.SeekTo(50, true));
|
AddStep("Seek(50), Snap", () => Clock.SeekSnapped(50));
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("Seek(100), Snap", () => composer.SeekTo(100, true));
|
AddStep("Seek(100), Snap", () => Clock.SeekSnapped(100));
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("Seek(175), Snap", () => composer.SeekTo(175, true));
|
AddStep("Seek(175), Snap", () => Clock.SeekSnapped(175));
|
||||||
AddAssert("Time = 175", () => clock.CurrentTime == 175);
|
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||||
AddStep("Seek(350), Snap", () => composer.SeekTo(350, true));
|
AddStep("Seek(350), Snap", () => Clock.SeekSnapped(350));
|
||||||
AddAssert("Time = 350", () => clock.CurrentTime == 350);
|
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||||
AddStep("Seek(400), Snap", () => composer.SeekTo(400, true));
|
AddStep("Seek(400), Snap", () => Clock.SeekSnapped(400));
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
AddStep("Seek(450), Snap", () => composer.SeekTo(450, true));
|
AddStep("Seek(450), Snap", () => Clock.SeekSnapped(450));
|
||||||
AddAssert("Time = 450", () => clock.CurrentTime == 450);
|
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -154,18 +123,18 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(24), Snap", () => composer.SeekTo(24, true));
|
AddStep("Seek(24), Snap", () => Clock.SeekSnapped(24));
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
AddStep("Seek(26), Snap", () => composer.SeekTo(26, true));
|
AddStep("Seek(26), Snap", () => Clock.SeekSnapped(26));
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("Seek(150), Snap", () => composer.SeekTo(150, true));
|
AddStep("Seek(150), Snap", () => Clock.SeekSnapped(150));
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("Seek(170), Snap", () => composer.SeekTo(170, true));
|
AddStep("Seek(170), Snap", () => Clock.SeekSnapped(170));
|
||||||
AddAssert("Time = 175", () => clock.CurrentTime == 175);
|
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||||
AddStep("Seek(274), Snap", () => composer.SeekTo(274, true));
|
AddStep("Seek(274), Snap", () => Clock.SeekSnapped(274));
|
||||||
AddAssert("Time = 175", () => clock.CurrentTime == 175);
|
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||||
AddStep("Seek(276), Snap", () => composer.SeekTo(276, true));
|
AddStep("Seek(276), Snap", () => Clock.SeekSnapped(276));
|
||||||
AddAssert("Time = 350", () => clock.CurrentTime == 350);
|
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -175,16 +144,16 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("SeekForward", () => composer.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("SeekForward", () => composer.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("SeekForward", () => composer.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 200", () => clock.CurrentTime == 200);
|
AddAssert("Time = 200", () => Clock.CurrentTime == 200);
|
||||||
AddStep("SeekForward", () => composer.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
AddStep("SeekForward", () => composer.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 450", () => clock.CurrentTime == 450);
|
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -194,18 +163,18 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 175", () => clock.CurrentTime == 175);
|
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 350", () => clock.CurrentTime == 350);
|
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 450", () => clock.CurrentTime == 450);
|
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -216,30 +185,30 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(49)", () => composer.SeekTo(49));
|
AddStep("Seek(49)", () => Clock.Seek(49));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("Seek(49.999)", () => composer.SeekTo(49.999));
|
AddStep("Seek(49.999)", () => Clock.Seek(49.999));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("Seek(99)", () => composer.SeekTo(99));
|
AddStep("Seek(99)", () => Clock.Seek(99));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("Seek(99.999)", () => composer.SeekTo(99.999));
|
AddStep("Seek(99.999)", () => Clock.Seek(99.999));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("Seek(174)", () => composer.SeekTo(174));
|
AddStep("Seek(174)", () => Clock.Seek(174));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 175", () => clock.CurrentTime == 175);
|
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||||
AddStep("Seek(349)", () => composer.SeekTo(349));
|
AddStep("Seek(349)", () => Clock.Seek(349));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 350", () => clock.CurrentTime == 350);
|
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||||
AddStep("Seek(399)", () => composer.SeekTo(399));
|
AddStep("Seek(399)", () => Clock.Seek(399));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
AddStep("Seek(449)", () => composer.SeekTo(449));
|
AddStep("Seek(449)", () => Clock.Seek(449));
|
||||||
AddStep("SeekForward, Snap", () => composer.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 450", () => clock.CurrentTime == 450);
|
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -249,19 +218,19 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(450)", () => composer.SeekTo(450));
|
AddStep("Seek(450)", () => Clock.Seek(450));
|
||||||
AddStep("SeekBackward", () => composer.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 425", () => clock.CurrentTime == 425);
|
AddAssert("Time = 425", () => Clock.CurrentTime == 425);
|
||||||
AddStep("SeekBackward", () => composer.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 375", () => clock.CurrentTime == 375);
|
AddAssert("Time = 375", () => Clock.CurrentTime == 375);
|
||||||
AddStep("SeekBackward", () => composer.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 325", () => clock.CurrentTime == 325);
|
AddAssert("Time = 325", () => Clock.CurrentTime == 325);
|
||||||
AddStep("SeekBackward", () => composer.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 125", () => clock.CurrentTime == 125);
|
AddAssert("Time = 125", () => Clock.CurrentTime == 125);
|
||||||
AddStep("SeekBackward", () => composer.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 25", () => clock.CurrentTime == 25);
|
AddAssert("Time = 25", () => Clock.CurrentTime == 25);
|
||||||
AddStep("SeekBackward", () => composer.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -271,19 +240,19 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(450)", () => composer.SeekTo(450));
|
AddStep("Seek(450)", () => Clock.Seek(450));
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 350", () => clock.CurrentTime == 350);
|
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 175", () => clock.CurrentTime == 175);
|
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 100", () => clock.CurrentTime == 100);
|
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 50", () => clock.CurrentTime == 50);
|
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -294,18 +263,18 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(451)", () => composer.SeekTo(451));
|
AddStep("Seek(451)", () => Clock.Seek(451));
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 450", () => clock.CurrentTime == 450);
|
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||||
AddStep("Seek(450.999)", () => composer.SeekTo(450.999));
|
AddStep("Seek(450.999)", () => Clock.Seek(450.999));
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 450", () => clock.CurrentTime == 450);
|
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
||||||
AddStep("Seek(401)", () => composer.SeekTo(401));
|
AddStep("Seek(401)", () => Clock.Seek(401));
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
AddStep("Seek(401.999)", () => composer.SeekTo(401.999));
|
AddStep("Seek(401.999)", () => Clock.Seek(401.999));
|
||||||
AddStep("SeekBackward, Snap", () => composer.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 400", () => clock.CurrentTime == 400);
|
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -317,34 +286,34 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
double lastTime = 0;
|
double lastTime = 0;
|
||||||
|
|
||||||
AddStep("Seek(0)", () => composer.SeekTo(0));
|
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
AddStep("SeekForward, Snap", () =>
|
AddStep("SeekForward, Snap", () =>
|
||||||
{
|
{
|
||||||
lastTime = clock.CurrentTime;
|
lastTime = Clock.CurrentTime;
|
||||||
composer.SeekForward(true);
|
Clock.SeekForward(true);
|
||||||
});
|
});
|
||||||
AddAssert("Time > lastTime", () => clock.CurrentTime > lastTime);
|
AddAssert("Time > lastTime", () => Clock.CurrentTime > lastTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
AddStep("SeekBackward, Snap", () =>
|
AddStep("SeekBackward, Snap", () =>
|
||||||
{
|
{
|
||||||
lastTime = clock.CurrentTime;
|
lastTime = Clock.CurrentTime;
|
||||||
composer.SeekBackward(true);
|
Clock.SeekBackward(true);
|
||||||
});
|
});
|
||||||
AddAssert("Time < lastTime", () => clock.CurrentTime < lastTime);
|
AddAssert("Time < lastTime", () => Clock.CurrentTime < lastTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddAssert("Time = 0", () => clock.CurrentTime == 0);
|
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset()
|
private void reset()
|
||||||
{
|
{
|
||||||
AddStep("Reset", () => composer.SeekTo(0));
|
AddStep("Reset", () => Clock.Seek(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestHitObjectComposer : HitObjectComposer
|
private class TestHitObjectComposer : HitObjectComposer
|
||||||
@ -359,13 +328,13 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
private class TimingPointVisualiser : CompositeDrawable
|
private class TimingPointVisualiser : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Track track;
|
private readonly double length;
|
||||||
|
|
||||||
private readonly Drawable tracker;
|
private readonly Drawable tracker;
|
||||||
|
|
||||||
public TimingPointVisualiser(Beatmap beatmap, Track track)
|
public TimingPointVisualiser(Beatmap beatmap, double length)
|
||||||
{
|
{
|
||||||
this.track = track;
|
this.length = length;
|
||||||
|
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
@ -417,7 +386,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
for (int i = 0; i < timingPoints.Count; i++)
|
for (int i = 0; i < timingPoints.Count; i++)
|
||||||
{
|
{
|
||||||
TimingControlPoint next = i == timingPoints.Count - 1 ? null : timingPoints[i + 1];
|
TimingControlPoint next = i == timingPoints.Count - 1 ? null : timingPoints[i + 1];
|
||||||
timelineContainer.Add(new TimingPointTimeline(timingPoints[i], next?.Time ?? beatmap.HitObjects.Last().StartTime, track.Length));
|
timelineContainer.Add(new TimingPointTimeline(timingPoints[i], next?.Time ?? length, length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +394,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
tracker.X = (float)(Time.Current / track.Length);
|
tracker.X = (float)(Time.Current / length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TimingPointTimeline : CompositeDrawable
|
private class TimingPointTimeline : CompositeDrawable
|
||||||
|
@ -6,36 +6,22 @@ using System.Collections.Generic;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestCaseEditorSummaryTimeline : OsuTestCase
|
public class TestCaseEditorSummaryTimeline : EditorClockTestCase
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) };
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) };
|
||||||
|
|
||||||
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
|
||||||
=> dependencies = new DependencyContainer(parent);
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(OsuGameBase osuGame)
|
||||||
{
|
{
|
||||||
beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
|
||||||
dependencies.CacheAs<IAdjustableClock>(clock);
|
|
||||||
dependencies.CacheAs<IFrameBasedClock>(clock);
|
|
||||||
|
|
||||||
SummaryTimeline summaryTimeline;
|
SummaryTimeline summaryTimeline;
|
||||||
Add(summaryTimeline = new SummaryTimeline
|
Add(summaryTimeline = new SummaryTimeline
|
||||||
@ -45,7 +31,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
Size = new Vector2(500, 50)
|
Size = new Vector2(500, 50)
|
||||||
});
|
});
|
||||||
|
|
||||||
summaryTimeline.Beatmap.BindTo(beatmap);
|
summaryTimeline.Beatmap.BindTo(osuGame.Beatmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,11 +35,13 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when a new <see cref="TModel"/> becomes available in the database.
|
/// Fired when a new <see cref="TModel"/> becomes available in the database.
|
||||||
|
/// This is not guaranteed to run on the update thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<TModel> ItemAdded;
|
public event Action<TModel> ItemAdded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when a <see cref="TModel"/> is removed from the database.
|
/// Fired when a <see cref="TModel"/> is removed from the database.
|
||||||
|
/// This is not guaranteed to run on the update thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<TModel> ItemRemoved;
|
public event Action<TModel> ItemRemoved;
|
||||||
|
|
||||||
|
@ -37,13 +37,7 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public Bindable<User> LocalUser { get; } = new Bindable<User>(createGuestUser());
|
public Bindable<User> LocalUser { get; } = new Bindable<User>(createGuestUser());
|
||||||
|
|
||||||
public string Token
|
protected bool HasLogin => authentication.Token.Value != null || !string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password);
|
||||||
{
|
|
||||||
get { return authentication.Token?.ToString(); }
|
|
||||||
set { authentication.Token = string.IsNullOrEmpty(value) ? null : OAuthToken.Parse(value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool HasLogin => Token != null || !string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password);
|
|
||||||
|
|
||||||
private readonly CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
private readonly CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
@ -57,11 +51,15 @@ namespace osu.Game.Online.API
|
|||||||
log = Logger.GetLogger(LoggingTarget.Network);
|
log = Logger.GetLogger(LoggingTarget.Network);
|
||||||
|
|
||||||
ProvidedUsername = config.Get<string>(OsuSetting.Username);
|
ProvidedUsername = config.Get<string>(OsuSetting.Username);
|
||||||
Token = config.Get<string>(OsuSetting.Token);
|
|
||||||
|
authentication.TokenString = config.Get<string>(OsuSetting.Token);
|
||||||
|
authentication.Token.ValueChanged += onTokenChanged;
|
||||||
|
|
||||||
Task.Factory.StartNew(run, cancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
Task.Factory.StartNew(run, cancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onTokenChanged(OAuthToken token) => config.Set(OsuSetting.Token, config.Get<bool>(OsuSetting.SavePassword) ? authentication.TokenString : string.Empty);
|
||||||
|
|
||||||
private readonly List<IOnlineComponent> components = new List<IOnlineComponent>();
|
private readonly List<IOnlineComponent> components = new List<IOnlineComponent>();
|
||||||
|
|
||||||
internal new void Schedule(Action action) => base.Schedule(action);
|
internal new void Schedule(Action action) => base.Schedule(action);
|
||||||
@ -306,9 +304,6 @@ namespace osu.Game.Online.API
|
|||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
config.Set(OsuSetting.Token, config.Get<bool>(OsuSetting.SavePassword) ? Token : string.Empty);
|
|
||||||
config.Save();
|
|
||||||
|
|
||||||
flushQueue();
|
flushQueue();
|
||||||
cancellationToken.Cancel();
|
cancellationToken.Cancel();
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
|
|
||||||
namespace osu.Game.Online.API
|
namespace osu.Game.Online.API
|
||||||
@ -12,7 +13,13 @@ namespace osu.Game.Online.API
|
|||||||
private readonly string clientSecret;
|
private readonly string clientSecret;
|
||||||
private readonly string endpoint;
|
private readonly string endpoint;
|
||||||
|
|
||||||
public OAuthToken Token;
|
public readonly Bindable<OAuthToken> Token = new Bindable<OAuthToken>();
|
||||||
|
|
||||||
|
public string TokenString
|
||||||
|
{
|
||||||
|
get => Token.Value?.ToString();
|
||||||
|
set => Token.Value = string.IsNullOrEmpty(value) ? null : OAuthToken.Parse(value);
|
||||||
|
}
|
||||||
|
|
||||||
internal OAuth(string clientId, string clientSecret, string endpoint)
|
internal OAuth(string clientId, string clientSecret, string endpoint)
|
||||||
{
|
{
|
||||||
@ -47,7 +54,7 @@ namespace osu.Game.Online.API
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token = req.ResponseObject;
|
Token.Value = req.ResponseObject;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,14 +73,14 @@ namespace osu.Game.Online.API
|
|||||||
{
|
{
|
||||||
req.Perform();
|
req.Perform();
|
||||||
|
|
||||||
Token = req.ResponseObject;
|
Token.Value = req.ResponseObject;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
//todo: potentially only kill the refresh token on certain exception types.
|
//todo: potentially only kill the refresh token on certain exception types.
|
||||||
Token = null;
|
Token.Value = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,15 +102,15 @@ namespace osu.Game.Online.API
|
|||||||
if (accessTokenValid) return true;
|
if (accessTokenValid) return true;
|
||||||
|
|
||||||
// if not, let's try using our refresh token to request a new access token.
|
// if not, let's try using our refresh token to request a new access token.
|
||||||
if (!string.IsNullOrEmpty(Token?.RefreshToken))
|
if (!string.IsNullOrEmpty(Token.Value?.RefreshToken))
|
||||||
// ReSharper disable once PossibleNullReferenceException
|
// ReSharper disable once PossibleNullReferenceException
|
||||||
AuthenticateWithRefresh(Token.RefreshToken);
|
AuthenticateWithRefresh(Token.Value.RefreshToken);
|
||||||
|
|
||||||
return accessTokenValid;
|
return accessTokenValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool accessTokenValid => Token?.IsValid ?? false;
|
private bool accessTokenValid => Token.Value?.IsValid ?? false;
|
||||||
|
|
||||||
internal bool HasValidAccessToken => RequestAccessToken() != null;
|
internal bool HasValidAccessToken => RequestAccessToken() != null;
|
||||||
|
|
||||||
@ -111,12 +118,12 @@ namespace osu.Game.Online.API
|
|||||||
{
|
{
|
||||||
if (!ensureAccessToken()) return null;
|
if (!ensureAccessToken()) return null;
|
||||||
|
|
||||||
return Token.AccessToken;
|
return Token.Value.AccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Clear()
|
internal void Clear()
|
||||||
{
|
{
|
||||||
Token = null;
|
Token.Value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessTokenRequestRefresh : AccessTokenRequest
|
private class AccessTokenRequestRefresh : AccessTokenRequest
|
||||||
|
@ -36,6 +36,10 @@ using osu.Game.Overlays.Volume;
|
|||||||
|
|
||||||
namespace osu.Game
|
namespace osu.Game
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
||||||
|
/// for initial components that are generally retrieved via DI.
|
||||||
|
/// </summary>
|
||||||
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>
|
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public Toolbar Toolbar;
|
public Toolbar Toolbar;
|
||||||
|
@ -34,6 +34,11 @@ using osu.Game.Skinning;
|
|||||||
|
|
||||||
namespace osu.Game
|
namespace osu.Game
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The most basic <see cref="Game"/> that can be used to host osu! components and systems.
|
||||||
|
/// Unlike <see cref="OsuGame"/>, this class will not load any kind of UI, allowing it to be used
|
||||||
|
/// for provide dependencies to test cases without interfering with them.
|
||||||
|
/// </summary>
|
||||||
public class OsuGameBase : Framework.Game, ICanAcceptFiles
|
public class OsuGameBase : Framework.Game, ICanAcceptFiles
|
||||||
{
|
{
|
||||||
protected OsuConfigManager LocalConfig;
|
protected OsuConfigManager LocalConfig;
|
||||||
|
@ -246,11 +246,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
if (beatmaps != null) beatmaps.ItemAdded -= handleBeatmapAdd;
|
if (beatmaps != null) beatmaps.ItemAdded -= handleBeatmapAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBeatmapAdd(BeatmapSetInfo beatmap)
|
private void handleBeatmapAdd(BeatmapSetInfo beatmap) => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (beatmap.OnlineBeatmapSetID == BeatmapSet?.OnlineBeatmapSetID)
|
if (beatmap.OnlineBeatmapSetID == BeatmapSet?.OnlineBeatmapSetID)
|
||||||
downloadButtonsContainer.FadeOut(transition_duration);
|
downloadButtonsContainer.FadeOut(transition_duration);
|
||||||
}
|
});
|
||||||
|
|
||||||
private void download(bool noVideo)
|
private void download(bool noVideo)
|
||||||
{
|
{
|
||||||
|
@ -188,12 +188,12 @@ namespace osu.Game.Overlays
|
|||||||
beatmaps.ItemAdded += setAdded;
|
beatmaps.ItemAdded += setAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAdded(BeatmapSetInfo set)
|
private void setAdded(BeatmapSetInfo set) => Schedule(() =>
|
||||||
{
|
{
|
||||||
// if a new map was imported, we should remove it from search results (download completed etc.)
|
// if a new map was imported, we should remove it from search results (download completed etc.)
|
||||||
panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire();
|
panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire();
|
||||||
BeatmapSets = BeatmapSets?.Where(b => b.OnlineBeatmapSetID != set.OnlineBeatmapSetID);
|
BeatmapSets = BeatmapSets?.Where(b => b.OnlineBeatmapSetID != set.OnlineBeatmapSetID);
|
||||||
}
|
});
|
||||||
|
|
||||||
private void updateResultCounts()
|
private void updateResultCounts()
|
||||||
{
|
{
|
||||||
@ -323,6 +323,14 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;
|
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (beatmaps != null)
|
||||||
|
beatmaps.ItemAdded -= setAdded;
|
||||||
|
}
|
||||||
|
|
||||||
public class ResultCounts
|
public class ResultCounts
|
||||||
{
|
{
|
||||||
public readonly int Artists;
|
public readonly int Artists;
|
||||||
|
@ -74,8 +74,8 @@ namespace osu.Game.Overlays.Music
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
beatmaps.ItemAdded += list.AddBeatmapSet;
|
beatmaps.ItemAdded += handleBeatmapAdded;
|
||||||
beatmaps.ItemRemoved += list.RemoveBeatmapSet;
|
beatmaps.ItemRemoved += handleBeatmapRemoved;
|
||||||
|
|
||||||
list.BeatmapSets = beatmaps.GetAllUsableBeatmapSets();
|
list.BeatmapSets = beatmaps.GetAllUsableBeatmapSets();
|
||||||
|
|
||||||
@ -95,6 +95,9 @@ namespace osu.Game.Overlays.Music
|
|||||||
beatmapBacking.TriggerChange();
|
beatmapBacking.TriggerChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleBeatmapAdded(BeatmapSetInfo setInfo) => Schedule(() => list.AddBeatmapSet(setInfo));
|
||||||
|
private void handleBeatmapRemoved(BeatmapSetInfo setInfo) => Schedule(() => list.RemoveBeatmapSet(setInfo));
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
filter.Search.HoldFocus = true;
|
filter.Search.HoldFocus = true;
|
||||||
@ -153,6 +156,17 @@ namespace osu.Game.Overlays.Music
|
|||||||
|
|
||||||
track.Restart();
|
track.Restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (beatmaps != null)
|
||||||
|
{
|
||||||
|
beatmaps.ItemAdded -= handleBeatmapAdded;
|
||||||
|
beatmaps.ItemRemoved -= handleBeatmapRemoved;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: placeholder
|
//todo: placeholder
|
||||||
|
@ -21,9 +21,13 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
|
|
||||||
public override FontAwesome Icon => FontAwesome.fa_paint_brush;
|
public override FontAwesome Icon => FontAwesome.fa_paint_brush;
|
||||||
|
|
||||||
|
private SkinManager skins;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config, SkinManager skins)
|
private void load(OsuConfigManager config, SkinManager skins)
|
||||||
{
|
{
|
||||||
|
this.skins = skins;
|
||||||
|
|
||||||
FlowContent.Spacing = new Vector2(0, 5);
|
FlowContent.Spacing = new Vector2(0, 5);
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -47,15 +51,29 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
|
skins.ItemAdded += onItemsChanged;
|
||||||
skins.ItemAdded += _ => reloadSkins();
|
skins.ItemRemoved += onItemsChanged;
|
||||||
skins.ItemRemoved += _ => reloadSkins();
|
|
||||||
|
|
||||||
reloadSkins();
|
reloadSkins();
|
||||||
|
|
||||||
skinDropdown.Bindable = config.GetBindable<int>(OsuSetting.Skin);
|
skinDropdown.Bindable = config.GetBindable<int>(OsuSetting.Skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
|
||||||
|
|
||||||
|
private void onItemsChanged(SkinInfo _) => Schedule(reloadSkins);
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (skins != null)
|
||||||
|
{
|
||||||
|
skins.ItemAdded -= onItemsChanged;
|
||||||
|
skins.ItemRemoved -= onItemsChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SizeSlider : OsuSliderBar<double>
|
private class SizeSlider : OsuSliderBar<double>
|
||||||
{
|
{
|
||||||
public override string TooltipText => Current.Value.ToString(@"0.##x");
|
public override string TooltipText => Current.Value.ToString(@"0.##x");
|
||||||
|
@ -4,20 +4,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Edit.Screens.Compose;
|
|
||||||
using osu.Game.Screens.Edit.Screens.Compose.Layers;
|
using osu.Game.Screens.Edit.Screens.Compose.Layers;
|
||||||
using osu.Game.Screens.Edit.Screens.Compose.RadioButtons;
|
using osu.Game.Screens.Edit.Screens.Compose.RadioButtons;
|
||||||
|
|
||||||
@ -33,9 +29,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
private readonly List<Container> layerContainers = new List<Container>();
|
private readonly List<Container> layerContainers = new List<Container>();
|
||||||
|
|
||||||
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||||
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
|
|
||||||
|
|
||||||
private IAdjustableClock adjustableClock;
|
|
||||||
|
|
||||||
protected HitObjectComposer(Ruleset ruleset)
|
protected HitObjectComposer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
@ -44,14 +37,9 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader]
|
||||||
private void load([NotNull] OsuGameBase osuGame, [NotNull] IAdjustableClock adjustableClock, [NotNull] IFrameBasedClock framedClock, [CanBeNull] BindableBeatDivisor beatDivisor)
|
private void load(OsuGameBase osuGame, IFrameBasedClock framedClock)
|
||||||
{
|
{
|
||||||
this.adjustableClock = adjustableClock;
|
|
||||||
|
|
||||||
if (beatDivisor != null)
|
|
||||||
this.beatDivisor.BindTo(beatDivisor);
|
|
||||||
|
|
||||||
beatmap.BindTo(osuGame.Beatmap);
|
beatmap.BindTo(osuGame.Beatmap);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -135,106 +123,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnWheel(InputState state)
|
|
||||||
{
|
|
||||||
if (state.Mouse.WheelDelta > 0)
|
|
||||||
SeekBackward(true);
|
|
||||||
else
|
|
||||||
SeekForward(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Seeks the current time one beat-snapped beat-length backwards.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="snapped">Whether to snap to the closest beat.</param>
|
|
||||||
public void SeekBackward(bool snapped = false) => seek(-1, snapped);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Seeks the current time one beat-snapped beat-length forwards.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="snapped">Whether to snap to the closest beat.</param>
|
|
||||||
public void SeekForward(bool snapped = false) => seek(1, snapped);
|
|
||||||
|
|
||||||
private void seek(int direction, bool snapped)
|
|
||||||
{
|
|
||||||
var cpi = beatmap.Value.Beatmap.ControlPointInfo;
|
|
||||||
|
|
||||||
var timingPoint = cpi.TimingPointAt(adjustableClock.CurrentTime);
|
|
||||||
if (direction < 0 && timingPoint.Time == adjustableClock.CurrentTime)
|
|
||||||
{
|
|
||||||
// When going backwards and we're at the boundary of two timing points, we compute the seek distance with the timing point which we are seeking into
|
|
||||||
int activeIndex = cpi.TimingPoints.IndexOf(timingPoint);
|
|
||||||
while (activeIndex > 0 && adjustableClock.CurrentTime == timingPoint.Time)
|
|
||||||
timingPoint = cpi.TimingPoints[--activeIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
double seekAmount = timingPoint.BeatLength / beatDivisor;
|
|
||||||
double seekTime = adjustableClock.CurrentTime + seekAmount * direction;
|
|
||||||
|
|
||||||
if (!snapped || cpi.TimingPoints.Count == 0)
|
|
||||||
{
|
|
||||||
adjustableClock.Seek(seekTime);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We will be snapping to beats within timingPoint
|
|
||||||
seekTime -= timingPoint.Time;
|
|
||||||
|
|
||||||
// Determine the index from timingPoint of the closest beat to seekTime, accounting for scrolling direction
|
|
||||||
int closestBeat;
|
|
||||||
if (direction > 0)
|
|
||||||
closestBeat = (int)Math.Floor(seekTime / seekAmount);
|
|
||||||
else
|
|
||||||
closestBeat = (int)Math.Ceiling(seekTime / seekAmount);
|
|
||||||
|
|
||||||
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
|
||||||
|
|
||||||
// Due to the rounding above, we may end up on the current beat. This will effectively cause 0 seeking to happen, but we don't want this.
|
|
||||||
// Instead, we'll go to the next beat in the direction when this is the case
|
|
||||||
if (Precision.AlmostEquals(adjustableClock.CurrentTime, seekTime))
|
|
||||||
{
|
|
||||||
closestBeat += direction > 0 ? 1 : -1;
|
|
||||||
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seekTime < timingPoint.Time && timingPoint != cpi.TimingPoints.First())
|
|
||||||
seekTime = timingPoint.Time;
|
|
||||||
|
|
||||||
var nextTimingPoint = cpi.TimingPoints.FirstOrDefault(t => t.Time > timingPoint.Time);
|
|
||||||
if (seekTime > nextTimingPoint?.Time)
|
|
||||||
seekTime = nextTimingPoint.Time;
|
|
||||||
|
|
||||||
adjustableClock.Seek(seekTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SeekTo(double seekTime, bool snapped = false)
|
|
||||||
{
|
|
||||||
if (!snapped)
|
|
||||||
{
|
|
||||||
adjustableClock.Seek(seekTime);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var timingPoint = beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(seekTime);
|
|
||||||
double beatSnapLength = timingPoint.BeatLength / beatDivisor;
|
|
||||||
|
|
||||||
// We will be snapping to beats within the timing point
|
|
||||||
seekTime -= timingPoint.Time;
|
|
||||||
|
|
||||||
// Determine the index from the current timing point of the closest beat to seekTime
|
|
||||||
int closestBeat = (int)Math.Round(seekTime / beatSnapLength);
|
|
||||||
seekTime = timingPoint.Time + closestBeat * beatSnapLength;
|
|
||||||
|
|
||||||
// Depending on beatSnapLength, we may snap to a beat that is beyond timingPoint's end time, but we want to instead snap to
|
|
||||||
// the next timing point's start time
|
|
||||||
var nextTimingPoint = beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.FirstOrDefault(t => t.Time > timingPoint.Time);
|
|
||||||
if (seekTime > nextTimingPoint?.Time)
|
|
||||||
seekTime = nextTimingPoint.Time;
|
|
||||||
|
|
||||||
adjustableClock.Seek(seekTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool;
|
private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool;
|
||||||
|
|
||||||
protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true);
|
protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true);
|
||||||
|
@ -55,11 +55,9 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
|||||||
if (Beatmap.Value.Track.Length == double.PositiveInfinity) return;
|
if (Beatmap.Value.Track.Length == double.PositiveInfinity) return;
|
||||||
|
|
||||||
float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
|
float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
|
||||||
seekTo(markerPos / DrawWidth * Beatmap.Value.Track.Length);
|
adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekTo(double time) => adjustableClock.Seek(time);
|
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Screens.Edit.Menus;
|
|||||||
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Screens.Edit.Screens;
|
using osu.Game.Screens.Edit.Screens;
|
||||||
@ -32,6 +33,10 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private EditorScreen currentScreen;
|
private EditorScreen currentScreen;
|
||||||
|
|
||||||
|
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
|
||||||
|
|
||||||
|
private EditorClock clock;
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
@ -42,11 +47,12 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
// TODO: should probably be done at a RulesetContainer level to share logic with Player.
|
// TODO: should probably be done at a RulesetContainer level to share logic with Player.
|
||||||
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock();
|
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock();
|
||||||
var adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
clock = new EditorClock(Beatmap.Value.Beatmap.ControlPointInfo, beatDivisor) { IsCoupled = false };
|
||||||
adjustableClock.ChangeSource(sourceClock);
|
clock.ChangeSource(sourceClock);
|
||||||
|
|
||||||
dependencies.CacheAs<IAdjustableClock>(adjustableClock);
|
dependencies.CacheAs<IFrameBasedClock>(clock);
|
||||||
dependencies.CacheAs<IFrameBasedClock>(adjustableClock);
|
dependencies.CacheAs<IAdjustableClock>(clock);
|
||||||
|
dependencies.Cache(beatDivisor);
|
||||||
|
|
||||||
EditorMenuBar menuBar;
|
EditorMenuBar menuBar;
|
||||||
TimeInfoContainer timeInfo;
|
TimeInfoContainer timeInfo;
|
||||||
@ -147,7 +153,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
menuBar.Mode.ValueChanged += onModeChanged;
|
menuBar.Mode.ValueChanged += onModeChanged;
|
||||||
|
|
||||||
bottomBackground.Colour = colours.Gray2;
|
bottomBackground.Colour = colours.Gray2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void exportBeatmap()
|
private void exportBeatmap()
|
||||||
@ -176,6 +181,15 @@ namespace osu.Game.Screens.Edit
|
|||||||
screenContainer.Add(currentScreen);
|
screenContainer.Add(currentScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnWheel(InputState state)
|
||||||
|
{
|
||||||
|
if (state.Mouse.WheelDelta > 0)
|
||||||
|
clock.SeekBackward(true);
|
||||||
|
else
|
||||||
|
clock.SeekForward(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnResuming(Screen last)
|
protected override void OnResuming(Screen last)
|
||||||
{
|
{
|
||||||
Beatmap.Value.Track?.Stop();
|
Beatmap.Value.Track?.Stop();
|
||||||
|
117
osu.Game/Screens/Edit/EditorClock.cs
Normal file
117
osu.Game/Screens/Edit/EditorClock.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Screens.Edit.Screens.Compose;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor.
|
||||||
|
/// </summary>
|
||||||
|
public class EditorClock : DecoupleableInterpolatingFramedClock
|
||||||
|
{
|
||||||
|
public ControlPointInfo ControlPointInfo;
|
||||||
|
|
||||||
|
private readonly BindableBeatDivisor beatDivisor;
|
||||||
|
|
||||||
|
public EditorClock(ControlPointInfo controlPointInfo, BindableBeatDivisor beatDivisor)
|
||||||
|
{
|
||||||
|
this.beatDivisor = beatDivisor;
|
||||||
|
|
||||||
|
ControlPointInfo = controlPointInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seek to the closest snappable beat from a time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">The raw position which should be seeked around.</param>
|
||||||
|
/// <returns>Whether the seek could be performed.</returns>
|
||||||
|
public bool SeekSnapped(double position)
|
||||||
|
{
|
||||||
|
var timingPoint = ControlPointInfo.TimingPointAt(position);
|
||||||
|
double beatSnapLength = timingPoint.BeatLength / beatDivisor;
|
||||||
|
|
||||||
|
// We will be snapping to beats within the timing point
|
||||||
|
position -= timingPoint.Time;
|
||||||
|
|
||||||
|
// Determine the index from the current timing point of the closest beat to position
|
||||||
|
int closestBeat = (int)Math.Round(position / beatSnapLength);
|
||||||
|
position = timingPoint.Time + closestBeat * beatSnapLength;
|
||||||
|
|
||||||
|
// Depending on beatSnapLength, we may snap to a beat that is beyond timingPoint's end time, but we want to instead snap to
|
||||||
|
// the next timing point's start time
|
||||||
|
var nextTimingPoint = ControlPointInfo.TimingPoints.FirstOrDefault(t => t.Time > timingPoint.Time);
|
||||||
|
if (position > nextTimingPoint?.Time)
|
||||||
|
position = nextTimingPoint.Time;
|
||||||
|
|
||||||
|
return Seek(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seeks backwards by one beat length.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="snapped">Whether to snap to the closest beat after seeking.</param>
|
||||||
|
public void SeekBackward(bool snapped = false) => seek(-1, snapped);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seeks forwards by one beat length.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="snapped">Whether to snap to the closest beat after seeking.</param>
|
||||||
|
public void SeekForward(bool snapped = false) => seek(1, snapped);
|
||||||
|
|
||||||
|
private void seek(int direction, bool snapped)
|
||||||
|
{
|
||||||
|
var timingPoint = ControlPointInfo.TimingPointAt(CurrentTime);
|
||||||
|
if (direction < 0 && timingPoint.Time == CurrentTime)
|
||||||
|
{
|
||||||
|
// When going backwards and we're at the boundary of two timing points, we compute the seek distance with the timing point which we are seeking into
|
||||||
|
int activeIndex = ControlPointInfo.TimingPoints.IndexOf(timingPoint);
|
||||||
|
while (activeIndex > 0 && CurrentTime == timingPoint.Time)
|
||||||
|
timingPoint = ControlPointInfo.TimingPoints[--activeIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
double seekAmount = timingPoint.BeatLength / beatDivisor;
|
||||||
|
double seekTime = CurrentTime + seekAmount * direction;
|
||||||
|
|
||||||
|
if (!snapped || ControlPointInfo.TimingPoints.Count == 0)
|
||||||
|
{
|
||||||
|
Seek(seekTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will be snapping to beats within timingPoint
|
||||||
|
seekTime -= timingPoint.Time;
|
||||||
|
|
||||||
|
// Determine the index from timingPoint of the closest beat to seekTime, accounting for scrolling direction
|
||||||
|
int closestBeat;
|
||||||
|
if (direction > 0)
|
||||||
|
closestBeat = (int)Math.Floor(seekTime / seekAmount);
|
||||||
|
else
|
||||||
|
closestBeat = (int)Math.Ceiling(seekTime / seekAmount);
|
||||||
|
|
||||||
|
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
||||||
|
|
||||||
|
// Due to the rounding above, we may end up on the current beat. This will effectively cause 0 seeking to happen, but we don't want this.
|
||||||
|
// Instead, we'll go to the next beat in the direction when this is the case
|
||||||
|
if (Precision.AlmostEquals(CurrentTime, seekTime))
|
||||||
|
{
|
||||||
|
closestBeat += direction > 0 ? 1 : -1;
|
||||||
|
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seekTime < timingPoint.Time && timingPoint != ControlPointInfo.TimingPoints.First())
|
||||||
|
seekTime = timingPoint.Time;
|
||||||
|
|
||||||
|
var nextTimingPoint = ControlPointInfo.TimingPoints.FirstOrDefault(t => t.Time > timingPoint.Time);
|
||||||
|
if (seekTime > nextTimingPoint?.Time)
|
||||||
|
seekTime = nextTimingPoint.Time;
|
||||||
|
|
||||||
|
Seek(seekTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
@ -21,15 +22,11 @@ namespace osu.Game.Screens.Edit.Screens.Compose
|
|||||||
|
|
||||||
private Container composerContainer;
|
private Container composerContainer;
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load([CanBeNull] BindableBeatDivisor beatDivisor)
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
|
||||||
=> dependencies = new DependencyContainer(parent);
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
dependencies.Cache(beatDivisor);
|
if (beatDivisor != null)
|
||||||
|
this.beatDivisor.BindTo(beatDivisor);
|
||||||
|
|
||||||
ScrollableTimeline timeline;
|
ScrollableTimeline timeline;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
79
osu.Game/Tests/Visual/EditorClockTestCase.cs
Normal file
79
osu.Game/Tests/Visual/EditorClockTestCase.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Screens.Compose;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a clock, beat-divisor, and scrolling capability for test cases of editor components that
|
||||||
|
/// are preferrably tested within the presence of a clock and seek controls.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class EditorClockTestCase : OsuTestCase
|
||||||
|
{
|
||||||
|
protected readonly BindableBeatDivisor BeatDivisor = new BindableBeatDivisor();
|
||||||
|
protected readonly EditorClock Clock;
|
||||||
|
|
||||||
|
private DependencyContainer dependencies;
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
=> dependencies = new DependencyContainer(parent);
|
||||||
|
|
||||||
|
private OsuGameBase osuGame;
|
||||||
|
|
||||||
|
protected EditorClockTestCase()
|
||||||
|
{
|
||||||
|
Clock = new EditorClock(new ControlPointInfo(), BeatDivisor) { IsCoupled = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGameBase osuGame)
|
||||||
|
{
|
||||||
|
this.osuGame = osuGame;
|
||||||
|
|
||||||
|
dependencies.Cache(BeatDivisor);
|
||||||
|
dependencies.CacheAs<IFrameBasedClock>(Clock);
|
||||||
|
dependencies.CacheAs<IAdjustableClock>(Clock);
|
||||||
|
|
||||||
|
osuGame.Beatmap.ValueChanged += beatmapChanged;
|
||||||
|
beatmapChanged(osuGame.Beatmap.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void beatmapChanged(WorkingBeatmap working)
|
||||||
|
{
|
||||||
|
Clock.ControlPointInfo = working.Beatmap.ControlPointInfo;
|
||||||
|
Clock.ChangeSource((IAdjustableClock)working.Track ?? new StopwatchClock());
|
||||||
|
Clock.ProcessFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Clock.ProcessFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnWheel(InputState state)
|
||||||
|
{
|
||||||
|
if (state.Mouse.WheelDelta > 0)
|
||||||
|
Clock.SeekBackward(true);
|
||||||
|
else
|
||||||
|
Clock.SeekForward(true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
osuGame.Beatmap.ValueChanged -= beatmapChanged;
|
||||||
|
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user