mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 23:22:55 +08:00
Merge branch 'master' into editor-scrolling-playfield-support
This commit is contained in:
commit
b5de30ef3d
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.519.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.525.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Threading;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
@ -14,13 +15,13 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
createBananas();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
createBananas(cancellationToken);
|
||||
}
|
||||
|
||||
private void createBananas()
|
||||
private void createBananas(CancellationToken cancellationToken)
|
||||
{
|
||||
double spacing = Duration;
|
||||
while (spacing > 100)
|
||||
@ -31,6 +32,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
for (double i = StartTime; i <= EndTime; i += spacing)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
AddNested(new Banana
|
||||
{
|
||||
Samples = Samples,
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
@ -45,9 +46,9 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
|
||||
var dropletSamples = Samples.Select(s => new HitSampleInfo
|
||||
{
|
||||
@ -58,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
SliderEventDescriptor? lastEvent = null;
|
||||
|
||||
foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset))
|
||||
foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken))
|
||||
{
|
||||
// generate tiny droplets since the last point
|
||||
if (lastEvent != null)
|
||||
@ -73,6 +74,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
for (double t = timeBetweenTiny; t < sinceLastTick; t += timeBetweenTiny)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
AddNested(new TinyDroplet
|
||||
{
|
||||
StartTime = t + lastEvent.Value.Time,
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
@ -91,11 +92,11 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate;
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
|
||||
createTicks();
|
||||
createTicks(cancellationToken);
|
||||
|
||||
AddNested(Head = new Note
|
||||
{
|
||||
@ -112,13 +113,15 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
});
|
||||
}
|
||||
|
||||
private void createTicks()
|
||||
private void createTicks(CancellationToken cancellationToken)
|
||||
{
|
||||
if (tickSpacing == 0)
|
||||
return;
|
||||
|
||||
for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
AddNested(new HoldNoteTick
|
||||
{
|
||||
StartTime = t,
|
||||
|
@ -118,7 +118,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
var objects = selectedHitObjects.ToList();
|
||||
|
||||
if (objects.Count == 0)
|
||||
return createGrid(h => h.StartTime <= EditorClock.CurrentTime);
|
||||
// use accurate time value to give more instantaneous feedback to the user.
|
||||
return createGrid(h => h.StartTime <= EditorClock.CurrentTimeAccurate);
|
||||
|
||||
double minTime = objects.Min(h => h.StartTime);
|
||||
return createGrid(h => h.StartTime < minTime, objects.Count + 1);
|
||||
|
@ -6,6 +6,7 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -133,12 +134,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
TickDistance = scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier;
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
|
||||
foreach (var e in
|
||||
SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset))
|
||||
SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken))
|
||||
{
|
||||
switch (e.Type)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
@ -73,17 +74,17 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
overallDifficulty = difficulty.OverallDifficulty;
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
createTicks();
|
||||
createTicks(cancellationToken);
|
||||
|
||||
RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty);
|
||||
RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty);
|
||||
|
||||
base.CreateNestedHitObjects();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
}
|
||||
|
||||
private void createTicks()
|
||||
private void createTicks(CancellationToken cancellationToken)
|
||||
{
|
||||
if (tickSpacing == 0)
|
||||
return;
|
||||
@ -92,6 +93,8 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
|
||||
for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
AddNested(new DrumRollTick
|
||||
{
|
||||
FirstTick = first,
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -29,12 +30,15 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
set => throw new NotSupportedException($"{nameof(Swell)} cannot be a strong hitobject.");
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
|
||||
for (int i = 0; i < RequiredHits; i++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
AddNested(new SwellTick());
|
||||
}
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new TaikoSwellJudgement();
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Threading;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -32,9 +33,9 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// </summary>
|
||||
public virtual bool IsStrong { get; set; }
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
|
||||
if (IsStrong)
|
||||
AddNested(new StrongHitObject { StartTime = this.GetEndTime() });
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
[Test]
|
||||
public void TestSingleSpan()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null).ToArray();
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null, default).ToArray();
|
||||
|
||||
Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head));
|
||||
Assert.That(events[0].Time, Is.EqualTo(start_time));
|
||||
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
[Test]
|
||||
public void TestRepeat()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null).ToArray();
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null, default).ToArray();
|
||||
|
||||
Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head));
|
||||
Assert.That(events[0].Time, Is.EqualTo(start_time));
|
||||
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
[Test]
|
||||
public void TestNonEvenTicks()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null).ToArray();
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null, default).ToArray();
|
||||
|
||||
Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head));
|
||||
Assert.That(events[0].Time, Is.EqualTo(start_time));
|
||||
@ -85,7 +85,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
[Test]
|
||||
public void TestLegacyLastTickOffset()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100).ToArray();
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100, default).ToArray();
|
||||
|
||||
Assert.That(events[2].Type, Is.EqualTo(SliderEventType.LegacyLastTick));
|
||||
Assert.That(events[2].Time, Is.EqualTo(900));
|
||||
@ -97,7 +97,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
const double velocity = 5;
|
||||
const double min_distance = velocity * 10;
|
||||
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0).ToArray();
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0, default).ToArray();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
/// Check if <see cref="PlayerLoader"/> properly triggers the visual settings preview when a user hovers over the visual settings panel.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PlayerLoaderSettingsHoverTest()
|
||||
public void TestPlayerLoaderSettingsHover()
|
||||
{
|
||||
setupUserSettings();
|
||||
AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new LoadBlockingTestPlayer { BlockLoad = true })));
|
||||
@ -79,11 +79,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
InputManager.MoveMouseTo(playerLoader.ScreenPos);
|
||||
InputManager.MoveMouseTo(playerLoader.VisualSettingsPos);
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -92,20 +90,19 @@ namespace osu.Game.Tests.Visual.Background
|
||||
/// We need to check that in this scenario, the dim and blur is still properly applied after entering player.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PlayerLoaderTransitionTest()
|
||||
public void TestPlayerLoaderTransition()
|
||||
{
|
||||
performFullSetup();
|
||||
AddStep("Trigger hover event", () => playerLoader.TriggerOnHover());
|
||||
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure the background is fully invisible (Alpha == 0) when the background should be disabled by the storyboard.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void StoryboardBackgroundVisibilityTest()
|
||||
public void TestStoryboardBackgroundVisibility()
|
||||
{
|
||||
performFullSetup();
|
||||
createFakeStoryboard();
|
||||
@ -114,52 +111,46 @@ namespace osu.Game.Tests.Visual.Background
|
||||
player.ReplacesBackground.Value = true;
|
||||
player.StoryboardEnabled.Value = true;
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
|
||||
AddUntilStep("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
|
||||
AddStep("Disable Storyboard", () =>
|
||||
{
|
||||
player.ReplacesBackground.Value = false;
|
||||
player.StoryboardEnabled.Value = false;
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
|
||||
AddUntilStep("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When exiting player, the screen that it suspends/exits to needs to have a fully visible (Alpha == 1) background.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void StoryboardTransitionTest()
|
||||
public void TestStoryboardTransition()
|
||||
{
|
||||
performFullSetup();
|
||||
createFakeStoryboard();
|
||||
AddStep("Exit to song select", () => player.Exit());
|
||||
waitForDim();
|
||||
AddAssert("Background is visible", () => songSelect.IsBackgroundVisible());
|
||||
AddUntilStep("Background is visible", () => songSelect.IsBackgroundVisible());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure <see cref="UserDimContainer"/> is properly accepting user-defined visual changes for a background.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void DisableUserDimBackgroundTest()
|
||||
public void TestDisableUserDimBackground()
|
||||
{
|
||||
performFullSetup();
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Enable user dim", () => songSelect.DimEnabled.Value = false);
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled());
|
||||
AddStep("Disable user dim", () => songSelect.DimEnabled.Value = true);
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure <see cref="UserDimContainer"/> is properly accepting user-defined visual changes for a storyboard.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void DisableUserDimStoryboardTest()
|
||||
public void TestDisableUserDimStoryboard()
|
||||
{
|
||||
performFullSetup();
|
||||
createFakeStoryboard();
|
||||
@ -170,41 +161,36 @@ namespace osu.Game.Tests.Visual.Background
|
||||
});
|
||||
AddStep("Enable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = true);
|
||||
AddStep("Set dim level to 1", () => songSelect.DimLevel.Value = 1f);
|
||||
waitForDim();
|
||||
AddAssert("Storyboard is invisible", () => !player.IsStoryboardVisible);
|
||||
AddUntilStep("Storyboard is invisible", () => !player.IsStoryboardVisible);
|
||||
AddStep("Disable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = false);
|
||||
waitForDim();
|
||||
AddAssert("Storyboard is visible", () => player.IsStoryboardVisible);
|
||||
AddUntilStep("Storyboard is visible", () => player.IsStoryboardVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the visual settings container retains dim and blur when pausing
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PauseTest()
|
||||
public void TestPause()
|
||||
{
|
||||
performFullSetup(true);
|
||||
AddStep("Pause", () => player.Pause());
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Unpause", () => player.Resume());
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the visual settings container removes user dim when suspending <see cref="Player"/> for <see cref="ResultsScreen"/>
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TransitionTest()
|
||||
public void TestTransition()
|
||||
{
|
||||
performFullSetup();
|
||||
FadeAccessibleResults results = null;
|
||||
AddStep("Transition to Results", () => player.Push(results =
|
||||
new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } })));
|
||||
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed, original background retained", () =>
|
||||
AddUntilStep("Screen is undimmed, original background retained", () =>
|
||||
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect());
|
||||
}
|
||||
|
||||
@ -212,32 +198,27 @@ namespace osu.Game.Tests.Visual.Background
|
||||
/// Check if background gets undimmed and unblurred when leaving <see cref="Player"/> for <see cref="PlaySongSelect"/>
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TransitionOutTest()
|
||||
public void TestTransitionOut()
|
||||
{
|
||||
performFullSetup();
|
||||
AddStep("Exit to song select", () => player.Exit());
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if hovering on the visual settings dialogue after resuming from player still previews the background dim.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ResumeFromPlayerTest()
|
||||
public void TestResumeFromPlayer()
|
||||
{
|
||||
performFullSetup();
|
||||
AddStep("Move mouse to Visual Settings", () => InputManager.MoveMouseTo(playerLoader.VisualSettingsPos));
|
||||
AddStep("Resume PlayerLoader", () => player.Restart());
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
}
|
||||
|
||||
private void waitForDim() => AddWaitStep("Wait for dim", 5);
|
||||
|
||||
private void createFakeStoryboard() => AddStep("Create storyboard", () =>
|
||||
{
|
||||
player.StoryboardEnabled.Value = false;
|
||||
|
@ -129,12 +129,19 @@ namespace osu.Game.Beatmaps
|
||||
processor?.PreProcess();
|
||||
|
||||
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
|
||||
foreach (var obj in converted.HitObjects)
|
||||
try
|
||||
{
|
||||
if (cancellationSource.IsCancellationRequested)
|
||||
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||
foreach (var obj in converted.HitObjects)
|
||||
{
|
||||
if (cancellationSource.IsCancellationRequested)
|
||||
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||
|
||||
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
|
||||
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty, cancellationSource.Token);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||
}
|
||||
|
||||
foreach (var mod in mods.OfType<IApplicableToHitObject>())
|
||||
|
@ -69,7 +69,7 @@ namespace osu.Game.IO
|
||||
|
||||
public override void DeleteDatabase(string name) => UnderlyingStorage.DeleteDatabase(MutatePath(name));
|
||||
|
||||
public override void OpenInNativeExplorer() => UnderlyingStorage.OpenInNativeExplorer();
|
||||
public override void OpenPathInNativeExplorer(string path) => UnderlyingStorage.OpenPathInNativeExplorer(MutatePath(path));
|
||||
|
||||
public override Storage GetStorageForDirectory(string path)
|
||||
{
|
||||
|
@ -52,8 +52,6 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
private readonly List<Container> layerContainers = new List<Container>();
|
||||
|
||||
private InputManager inputManager;
|
||||
|
||||
private RadioButtonCollection toolboxCollection;
|
||||
@ -83,17 +81,6 @@ namespace osu.Game.Rulesets.Edit
|
||||
return;
|
||||
}
|
||||
|
||||
var layerBelowRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[]
|
||||
{
|
||||
LayerBelowRuleset,
|
||||
new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }
|
||||
});
|
||||
|
||||
var layerAboveRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChild(BlueprintContainer = CreateBlueprintContainer());
|
||||
|
||||
layerContainers.Add(layerBelowRuleset);
|
||||
layerContainers.Add(layerAboveRuleset);
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -117,9 +104,16 @@ namespace osu.Game.Rulesets.Edit
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
layerBelowRuleset,
|
||||
// layers below playfield
|
||||
drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[]
|
||||
{
|
||||
LayerBelowRuleset,
|
||||
new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }
|
||||
}),
|
||||
drawableRulesetWrapper,
|
||||
layerAboveRuleset
|
||||
// layers above playfield
|
||||
drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer()
|
||||
.WithChild(BlueprintContainer = CreateBlueprintContainer())
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -163,19 +157,6 @@ namespace osu.Game.Rulesets.Edit
|
||||
inputManager = GetContainingInputManager();
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
layerContainers.ForEach(l =>
|
||||
{
|
||||
l.Anchor = drawableRulesetWrapper.Playfield.Anchor;
|
||||
l.Origin = drawableRulesetWrapper.Playfield.Origin;
|
||||
l.Position = drawableRulesetWrapper.Playfield.Position;
|
||||
l.Size = drawableRulesetWrapper.Playfield.Size;
|
||||
});
|
||||
}
|
||||
|
||||
private void selectionChanged(object sender, NotifyCollectionChangedEventArgs changedArgs)
|
||||
{
|
||||
if (EditorBeatmap.SelectedHitObjects.Any())
|
||||
@ -219,7 +200,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
EditorBeatmap.Add(hitObject);
|
||||
|
||||
if (EditorClock.CurrentTime < hitObject.StartTime)
|
||||
EditorClock.Seek(hitObject.StartTime);
|
||||
EditorClock.SeekTo(hitObject.StartTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -94,7 +95,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,BeatmapDifficulty)"/>,
|
||||
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,BeatmapDifficulty, CancellationToken)"/>,
|
||||
/// refreshing <see cref="Objects.HitObject.NestedHitObjects"/> and parameters for the <see cref="HitObject"/>.
|
||||
/// </summary>
|
||||
protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.Value.Beatmap.ControlPointInfo, beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty);
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Bindables;
|
||||
@ -99,7 +100,8 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// </summary>
|
||||
/// <param name="controlPointInfo">The control points.</param>
|
||||
/// <param name="difficulty">The difficulty settings to use.</param>
|
||||
public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
@ -108,7 +110,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
|
||||
nestedHitObjects.Clear();
|
||||
|
||||
CreateNestedHitObjects();
|
||||
CreateNestedHitObjects(cancellationToken);
|
||||
|
||||
if (this is IHasComboInformation hasCombo)
|
||||
{
|
||||
@ -122,7 +124,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
||||
|
||||
foreach (var h in nestedHitObjects)
|
||||
h.ApplyDefaults(controlPointInfo, difficulty);
|
||||
h.ApplyDefaults(controlPointInfo, difficulty, cancellationToken);
|
||||
|
||||
DefaultsApplied?.Invoke(this);
|
||||
}
|
||||
@ -136,6 +138,14 @@ namespace osu.Game.Rulesets.Objects
|
||||
HitWindows?.SetDifficulty(difficulty.OverallDifficulty);
|
||||
}
|
||||
|
||||
protected virtual void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
// ReSharper disable once MethodSupportsCancellation (https://youtrack.jetbrains.com/issue/RIDER-44520)
|
||||
#pragma warning disable 618
|
||||
CreateNestedHitObjects();
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
protected virtual void CreateNestedHitObjects()
|
||||
{
|
||||
}
|
||||
|
@ -4,13 +4,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public static class SliderEventGenerator
|
||||
{
|
||||
[Obsolete("Use the overload with cancellation support instead.")] // can be removed 20201115
|
||||
public static IEnumerable<SliderEventDescriptor> Generate(double startTime, double spanDuration, double velocity, double tickDistance, double totalDistance, int spanCount,
|
||||
double? legacyLastTickOffset)
|
||||
{
|
||||
return Generate(startTime, spanDuration, velocity, tickDistance, totalDistance, spanCount, legacyLastTickOffset, default);
|
||||
}
|
||||
|
||||
// ReSharper disable once MethodOverloadWithOptionalParameter
|
||||
public static IEnumerable<SliderEventDescriptor> Generate(double startTime, double spanDuration, double velocity, double tickDistance, double totalDistance, int spanCount,
|
||||
double? legacyLastTickOffset, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// A very lenient maximum length of a slider for ticks to be generated.
|
||||
// This exists for edge cases such as /b/1573664 where the beatmap has been edited by the user, and should never be reached in normal usage.
|
||||
@ -37,7 +46,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
var spanStartTime = startTime + span * spanDuration;
|
||||
var reversed = span % 2 == 1;
|
||||
|
||||
var ticks = generateTicks(span, spanStartTime, spanDuration, reversed, length, tickDistance, minDistanceFromEnd);
|
||||
var ticks = generateTicks(span, spanStartTime, spanDuration, reversed, length, tickDistance, minDistanceFromEnd, cancellationToken);
|
||||
|
||||
if (reversed)
|
||||
{
|
||||
@ -108,12 +117,15 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// <param name="length">The length of the path.</param>
|
||||
/// <param name="tickDistance">The distance between each tick.</param>
|
||||
/// <param name="minDistanceFromEnd">The distance from the end of the path at which ticks are not allowed to be added.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A <see cref="SliderEventDescriptor"/> for each tick. If <paramref name="reversed"/> is true, the ticks will be returned in reverse-StartTime order.</returns>
|
||||
private static IEnumerable<SliderEventDescriptor> generateTicks(int spanIndex, double spanStartTime, double spanDuration, bool reversed, double length, double tickDistance,
|
||||
double minDistanceFromEnd)
|
||||
double minDistanceFromEnd, CancellationToken cancellationToken = default)
|
||||
{
|
||||
for (var d = tickDistance; d <= length; d += tickDistance)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (d >= length - minDistanceFromEnd)
|
||||
break;
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
return;
|
||||
|
||||
float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
|
||||
editorClock.Seek(markerPos / DrawWidth * editorClock.TrackLength);
|
||||
editorClock.SeekTo(markerPos / DrawWidth * editorClock.TrackLength);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
if (clickedBlueprint == null)
|
||||
return false;
|
||||
|
||||
editorClock?.Seek(clickedBlueprint.HitObject.StartTime);
|
||||
editorClock?.SeekTo(clickedBlueprint.HitObject.StartTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -244,14 +244,21 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
#region Context Menu
|
||||
|
||||
public virtual MenuItem[] ContextMenuItems
|
||||
public MenuItem[] ContextMenuItems
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!selectedBlueprints.Any(b => b.IsHovered))
|
||||
return Array.Empty<MenuItem>();
|
||||
|
||||
var items = new List<MenuItem>
|
||||
var items = new List<MenuItem>();
|
||||
|
||||
items.AddRange(GetContextMenuItemsForSelection(selectedBlueprints));
|
||||
|
||||
if (selectedBlueprints.Count == 1)
|
||||
items.AddRange(selectedBlueprints[0].ContextMenuItems);
|
||||
|
||||
items.AddRange(new[]
|
||||
{
|
||||
new OsuMenuItem("Sound")
|
||||
{
|
||||
@ -263,15 +270,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
}
|
||||
},
|
||||
new OsuMenuItem("Delete", MenuItemType.Destructive, deleteSelected),
|
||||
};
|
||||
|
||||
if (selectedBlueprints.Count == 1)
|
||||
items.AddRange(selectedBlueprints[0].ContextMenuItems);
|
||||
});
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide context menu items relevant to current selection. Calling base is not required.
|
||||
/// </summary>
|
||||
/// <param name="selection">The current selection.</param>
|
||||
/// <returns>The relevant menu items.</returns>
|
||||
protected virtual IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint> selection)
|
||||
=> Enumerable.Empty<MenuItem>();
|
||||
|
||||
private MenuItem createHitSampleMenuItem(string name, string sampleName)
|
||||
{
|
||||
return new TernaryStateMenuItem(name, MenuItemType.Standard, setHitSampleState)
|
||||
|
@ -84,6 +84,7 @@ namespace osu.Game.Screens.Edit
|
||||
clock.ChangeSource(sourceClock);
|
||||
|
||||
dependencies.CacheAs(clock);
|
||||
AddInternal(clock);
|
||||
|
||||
// todo: remove caching of this and consume via editorBeatmap?
|
||||
dependencies.Cache(beatDivisor);
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -13,7 +15,7 @@ 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 class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock
|
||||
{
|
||||
public readonly double TrackLength;
|
||||
|
||||
@ -21,12 +23,11 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
private readonly BindableBeatDivisor beatDivisor;
|
||||
|
||||
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
|
||||
{
|
||||
this.beatDivisor = beatDivisor;
|
||||
private readonly DecoupleableInterpolatingFramedClock underlyingClock;
|
||||
|
||||
ControlPointInfo = beatmap.Beatmap.ControlPointInfo;
|
||||
TrackLength = beatmap.Track.Length;
|
||||
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
|
||||
: this(beatmap.Beatmap.ControlPointInfo, beatmap.Track.Length, beatDivisor)
|
||||
{
|
||||
}
|
||||
|
||||
public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor)
|
||||
@ -35,6 +36,8 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
ControlPointInfo = controlPointInfo;
|
||||
TrackLength = trackLength;
|
||||
|
||||
underlyingClock = new DecoupleableInterpolatingFramedClock();
|
||||
}
|
||||
|
||||
public EditorClock()
|
||||
@ -84,20 +87,22 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
private void seek(int direction, bool snapped, double amount = 1)
|
||||
{
|
||||
double current = CurrentTimeAccurate;
|
||||
|
||||
if (amount <= 0) throw new ArgumentException("Value should be greater than zero", nameof(amount));
|
||||
|
||||
var timingPoint = ControlPointInfo.TimingPointAt(CurrentTime);
|
||||
var timingPoint = ControlPointInfo.TimingPointAt(current);
|
||||
|
||||
if (direction < 0 && timingPoint.Time == CurrentTime)
|
||||
if (direction < 0 && timingPoint.Time == current)
|
||||
// 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
|
||||
timingPoint = ControlPointInfo.TimingPointAt(CurrentTime - 1);
|
||||
timingPoint = ControlPointInfo.TimingPointAt(current - 1);
|
||||
|
||||
double seekAmount = timingPoint.BeatLength / beatDivisor.Value * amount;
|
||||
double seekTime = CurrentTime + seekAmount * direction;
|
||||
double seekTime = current + seekAmount * direction;
|
||||
|
||||
if (!snapped || ControlPointInfo.TimingPoints.Count == 0)
|
||||
{
|
||||
Seek(seekTime);
|
||||
SeekTo(seekTime);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -115,7 +120,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
// 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))
|
||||
if (Precision.AlmostEquals(current, seekTime))
|
||||
{
|
||||
closestBeat += direction > 0 ? 1 : -1;
|
||||
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
||||
@ -130,7 +135,97 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
// Ensure the sought point is within the boundaries
|
||||
seekTime = Math.Clamp(seekTime, 0, TrackLength);
|
||||
Seek(seekTime);
|
||||
SeekTo(seekTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current time of this clock, include any active transform seeks performed via <see cref="SeekTo"/>.
|
||||
/// </summary>
|
||||
public double CurrentTimeAccurate =>
|
||||
Transforms.OfType<TransformSeek>().FirstOrDefault()?.EndValue ?? CurrentTime;
|
||||
|
||||
public double CurrentTime => underlyingClock.CurrentTime;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ClearTransforms();
|
||||
underlyingClock.Reset();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
ClearTransforms();
|
||||
underlyingClock.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
underlyingClock.Stop();
|
||||
}
|
||||
|
||||
public bool Seek(double position)
|
||||
{
|
||||
ClearTransforms();
|
||||
return underlyingClock.Seek(position);
|
||||
}
|
||||
|
||||
public void ResetSpeedAdjustments() => underlyingClock.ResetSpeedAdjustments();
|
||||
|
||||
double IAdjustableClock.Rate
|
||||
{
|
||||
get => underlyingClock.Rate;
|
||||
set => underlyingClock.Rate = value;
|
||||
}
|
||||
|
||||
double IClock.Rate => underlyingClock.Rate;
|
||||
|
||||
public bool IsRunning => underlyingClock.IsRunning;
|
||||
|
||||
public void ProcessFrame() => underlyingClock.ProcessFrame();
|
||||
|
||||
public double ElapsedFrameTime => underlyingClock.ElapsedFrameTime;
|
||||
|
||||
public double FramesPerSecond => underlyingClock.FramesPerSecond;
|
||||
|
||||
public FrameTimeInfo TimeInfo => underlyingClock.TimeInfo;
|
||||
|
||||
public void ChangeSource(IClock source) => underlyingClock.ChangeSource(source);
|
||||
|
||||
public IClock Source => underlyingClock.Source;
|
||||
|
||||
public bool IsCoupled
|
||||
{
|
||||
get => underlyingClock.IsCoupled;
|
||||
set => underlyingClock.IsCoupled = value;
|
||||
}
|
||||
|
||||
private const double transform_time = 300;
|
||||
|
||||
public void SeekTo(double seekDestination)
|
||||
{
|
||||
if (IsRunning)
|
||||
Seek(seekDestination);
|
||||
else
|
||||
transformSeekTo(seekDestination, transform_time, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void transformSeekTo(double seek, double duration = 0, Easing easing = Easing.None)
|
||||
=> this.TransformTo(this.PopulateTransform(new TransformSeek(), seek, duration, easing));
|
||||
|
||||
private double currentTime
|
||||
{
|
||||
get => underlyingClock.CurrentTime;
|
||||
set => underlyingClock.Seek(value);
|
||||
}
|
||||
|
||||
private class TransformSeek : Transform<double, EditorClock>
|
||||
{
|
||||
public override string TargetMember => nameof(currentTime);
|
||||
|
||||
protected override void Apply(EditorClock clock, double time) =>
|
||||
clock.currentTime = Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
|
||||
|
||||
protected override void ReadIntoStartValue(EditorClock clock) => StartValue = clock.currentTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
selectedGroup.BindValueChanged(selected =>
|
||||
{
|
||||
if (selected.NewValue != null)
|
||||
clock.Seek(selected.NewValue.Time);
|
||||
clock.SeekTo(selected.NewValue.Time);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.519.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.525.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||
<PackageReference Include="Sentry" Version="2.1.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.519.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.525.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||
</ItemGroup>
|
||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||
@ -80,7 +80,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.519.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.525.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user