mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 21:02:54 +08:00
Merge branch 'master' into score-encoding-cleanup
This commit is contained in:
commit
fc25e24397
@ -10,6 +10,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
@ -179,5 +180,33 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
updateDistanceSnapGrid();
|
||||
}
|
||||
|
||||
private void updateDistanceSnapGrid()
|
||||
{
|
||||
if (DistanceSnapProvider.DistanceSnapToggle.Value != TernaryState.True)
|
||||
{
|
||||
distanceSnapGrid.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceHitObject = getDistanceSnapGridSourceHitObject();
|
||||
|
||||
if (sourceHitObject == null)
|
||||
{
|
||||
distanceSnapGrid.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
distanceSnapGrid.Show();
|
||||
distanceSnapGrid.StartTime = sourceHitObject.GetEndTime();
|
||||
distanceSnapGrid.StartX = sourceHitObject.EffectiveX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,42 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
private readonly List<JudgementResult> judgementResults = new List<JudgementResult>();
|
||||
|
||||
[TestCase(30, 0)]
|
||||
[TestCase(30, 1)]
|
||||
[TestCase(40, 0)]
|
||||
[TestCase(40, 1)]
|
||||
[TestCase(50, 1)]
|
||||
[TestCase(60, 1)]
|
||||
[TestCase(70, 1)]
|
||||
[TestCase(80, 1)]
|
||||
[TestCase(80, 0)]
|
||||
[TestCase(80, 10)]
|
||||
[TestCase(90, 1)]
|
||||
[Ignore("headless test doesn't run at high enough precision for this to always enter a tracking state in time.")]
|
||||
public void TestVeryShortSliderMissHead(float sliderLength, int repeatCount)
|
||||
{
|
||||
performTest(new List<ReplayFrame>
|
||||
{
|
||||
new OsuReplayFrame { Position = new Vector2(50, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start - 10 },
|
||||
new OsuReplayFrame { Position = new Vector2(50, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start + 2000 },
|
||||
}, new Slider
|
||||
{
|
||||
StartTime = time_slider_start,
|
||||
Position = new Vector2(0, 0),
|
||||
SliderVelocityMultiplier = 10f,
|
||||
RepeatCount = repeatCount,
|
||||
Path = new SliderPath(PathType.Linear, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(sliderLength, 0),
|
||||
}),
|
||||
}, 240, 1);
|
||||
|
||||
AddAssert("Head judgement is first", () => judgementResults[0].HitObject is SliderHeadCircle);
|
||||
AddAssert("Tail judgement is second last", () => judgementResults[^2].HitObject is SliderTailCircle);
|
||||
AddAssert("Slider judgement is last", () => judgementResults[^1].HitObject is Slider);
|
||||
}
|
||||
|
||||
// Making these too short causes breakage from frames not being processed fast enough.
|
||||
// To keep things simple, these tests are crafted to always be >16ms length.
|
||||
// If sliders shorter than this are ever used in gameplay it will probably break things and we can revisit.
|
||||
@ -76,6 +112,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
assertAllMaxJudgements();
|
||||
|
||||
AddAssert("Head judgement is first", () => judgementResults.First().HitObject is SliderHeadCircle);
|
||||
|
||||
// Even if the last tick is hit early, the slider should always execute its final judgement at its endtime.
|
||||
// If not, hitsounds will not play on time.
|
||||
AddAssert("Judgement offset is zero", () => judgementResults.Last().TimeOffset == 0);
|
||||
@ -121,6 +159,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
else
|
||||
AddAssert("Tracking dropped", assertMidSliderJudgementFail);
|
||||
|
||||
AddAssert("Head judgement is first", () => judgementResults.First().HitObject is SliderHeadCircle);
|
||||
|
||||
// Even if the last tick is hit early, the slider should always execute its final judgement at its endtime.
|
||||
// If not, hitsounds will not play on time.
|
||||
AddAssert("Judgement offset is zero", () => judgementResults.Last().TimeOffset == 0);
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override LocalisableString Description => "Burn the notes into your memory.";
|
||||
|
||||
//Alters the transforms of the approach circles, breaking the effects of these mods.
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModApproachDifferent) };
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModApproachDifferent), typeof(OsuModTransform) }).ToArray();
|
||||
|
||||
public override ModType Type => ModType.Fun;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
@ -21,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "Everything rotates. EVERYTHING.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle), typeof(OsuModMagnetised), typeof(OsuModRepel) };
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModWiggle), typeof(OsuModMagnetised), typeof(OsuModRepel), typeof(OsuModFreezeFrame) }).ToArray();
|
||||
|
||||
private float theta;
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -15,9 +14,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
public new SliderHeadCircle HitObject => (SliderHeadCircle)base.HitObject;
|
||||
|
||||
[CanBeNull]
|
||||
public Slider Slider => DrawableSlider?.HitObject;
|
||||
|
||||
public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject;
|
||||
|
||||
public override bool DisplayResult => HitObject?.JudgeAsNormalHitCircle ?? base.DisplayResult;
|
||||
|
@ -17,7 +17,7 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
public partial class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking
|
||||
public partial class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking, IRequireTracking
|
||||
{
|
||||
public new SliderRepeat HitObject => (SliderRepeat)base.HitObject;
|
||||
|
||||
@ -36,6 +36,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
public bool Tracking { get; set; }
|
||||
|
||||
public DrawableSliderRepeat()
|
||||
: base(null)
|
||||
{
|
||||
@ -85,8 +87,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (HitObject.StartTime <= Time.Current)
|
||||
ApplyResult(r => r.Type = DrawableSlider.Tracking.Value ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||
// shared implementation with DrawableSliderTick.
|
||||
if (timeOffset >= 0)
|
||||
{
|
||||
// Attempt to preserve correct ordering of judgements as best we can by forcing
|
||||
// an un-judged head to be missed when the user has clearly skipped it.
|
||||
//
|
||||
// This check is applied to all nested slider objects apart from the head (ticks, repeats, tail).
|
||||
if (Tracking && !DrawableSlider.HeadCircle.Judged)
|
||||
DrawableSlider.HeadCircle.MissForcefully();
|
||||
|
||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
|
@ -4,6 +4,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -129,16 +130,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
if (userTriggered)
|
||||
return;
|
||||
|
||||
// Ensure the tail can only activate after all previous ticks already have.
|
||||
// Ensure the tail can only activate after all previous ticks/repeats already have.
|
||||
//
|
||||
// This covers the edge case where the lenience may allow the tail to activate before
|
||||
// the last tick, changing ordering of score/combo awarding.
|
||||
if (DrawableSlider.NestedHitObjects.Count > 1 && !DrawableSlider.NestedHitObjects[^2].Judged)
|
||||
var lastTick = DrawableSlider.NestedHitObjects.LastOrDefault(o => o.HitObject is SliderTick || o.HitObject is SliderRepeat);
|
||||
if (lastTick?.Judged == false)
|
||||
return;
|
||||
|
||||
if (timeOffset < SliderEventGenerator.TAIL_LENIENCY)
|
||||
return;
|
||||
|
||||
// Attempt to preserve correct ordering of judgements as best we can by forcing
|
||||
// an un-judged head to be missed when the user has clearly skipped it.
|
||||
//
|
||||
// This check is applied to all nested slider objects apart from the head (ticks, repeats, tail).
|
||||
if (Tracking && !DrawableSlider.HeadCircle.Judged)
|
||||
DrawableSlider.HeadCircle.MissForcefully();
|
||||
|
||||
// The player needs to have engaged in tracking at any point after the tail leniency cutoff.
|
||||
// An actual tick miss should only occur if reaching the tick itself.
|
||||
if (timeOffset >= SliderEventGenerator.TAIL_LENIENCY && Tracking)
|
||||
if (Tracking)
|
||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||
else if (timeOffset > 0)
|
||||
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||
|
@ -75,9 +75,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
// shared implementation with DrawableSliderRepeat.
|
||||
if (timeOffset >= 0)
|
||||
{
|
||||
// Attempt to preserve correct ordering of judgements as best we can by forcing
|
||||
// an un-judged head to be missed when the user has clearly skipped it.
|
||||
//
|
||||
// This check is applied to all nested slider objects apart from the head (ticks, repeats, tail).
|
||||
if (Tracking && !DrawableSlider.HeadCircle.Judged)
|
||||
DrawableSlider.HeadCircle.MissForcefully();
|
||||
|
||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
|
@ -108,6 +108,28 @@ namespace osu.Game.Tests.Gameplay
|
||||
AddAssert("gameplay clock time = 10000", () => gameplayClockContainer.CurrentTime, () => Is.EqualTo(10000).Within(10f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStopUsingBeatmapClock()
|
||||
{
|
||||
ClockBackedTestWorkingBeatmap working = null;
|
||||
MasterGameplayClockContainer gameplayClockContainer = null;
|
||||
BindableDouble frequencyAdjustment = new BindableDouble(2);
|
||||
|
||||
AddStep("create container", () =>
|
||||
{
|
||||
working = new ClockBackedTestWorkingBeatmap(new OsuRuleset().RulesetInfo, new FramedClock(new ManualClock()), Audio);
|
||||
Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0);
|
||||
|
||||
gameplayClockContainer.Reset(startClock: true);
|
||||
});
|
||||
|
||||
AddStep("apply frequency adjustment", () => gameplayClockContainer.AdjustmentsFromMods.AddAdjustment(AdjustableProperty.Frequency, frequencyAdjustment));
|
||||
AddAssert("track frequency changed", () => working.Track.AggregateFrequency.Value, () => Is.EqualTo(2));
|
||||
|
||||
AddStep("stop using beatmap clock", () => gameplayClockContainer.StopUsingBeatmapClock());
|
||||
AddAssert("frequency adjustment unapplied", () => working.Track.AggregateFrequency.Value, () => Is.EqualTo(1));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
localConfig?.Dispose();
|
||||
|
@ -7,6 +7,7 @@ using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -16,6 +17,7 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
@ -34,6 +36,7 @@ using osu.Game.Screens.OnlinePlay.Playlists;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Screens.Select.Options;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
@ -165,6 +168,41 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
ConfirmAtMainMenu();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSongSelectScrollHandling()
|
||||
{
|
||||
TestPlaySongSelect songSelect = null;
|
||||
double scrollPosition = 0;
|
||||
|
||||
AddStep("set game volume to max", () => Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.VolumeUniversal, 1d));
|
||||
AddUntilStep("wait for volume overlay to hide", () => Game.ChildrenOfType<VolumeOverlay>().Single().State.Value, () => Is.EqualTo(Visibility.Hidden));
|
||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
||||
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||
|
||||
AddStep("store scroll position", () => scrollPosition = getCarouselScrollPosition());
|
||||
|
||||
AddStep("move to left side", () => InputManager.MoveMouseTo(
|
||||
songSelect.ChildrenOfType<Screens.Select.SongSelect.LeftSideInteractionContainer>().Single().ScreenSpaceDrawQuad.TopLeft + new Vector2(1)));
|
||||
AddStep("scroll down", () => InputManager.ScrollVerticalBy(-1));
|
||||
AddAssert("carousel didn't move", getCarouselScrollPosition, () => Is.EqualTo(scrollPosition));
|
||||
|
||||
AddRepeatStep("alt-scroll down", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.AltLeft);
|
||||
InputManager.ScrollVerticalBy(-1);
|
||||
InputManager.ReleaseKey(Key.AltLeft);
|
||||
}, 5);
|
||||
AddAssert("game volume decreased", () => Game.Dependencies.Get<FrameworkConfigManager>().Get<double>(FrameworkSetting.VolumeUniversal), () => Is.LessThan(1));
|
||||
|
||||
AddStep("move to carousel", () => InputManager.MoveMouseTo(songSelect.ChildrenOfType<BeatmapCarousel>().Single()));
|
||||
AddStep("scroll down", () => InputManager.ScrollVerticalBy(-1));
|
||||
AddAssert("carousel moved", getCarouselScrollPosition, () => Is.Not.EqualTo(scrollPosition));
|
||||
|
||||
double getCarouselScrollPosition() => Game.ChildrenOfType<UserTrackingScrollContainer<DrawableCarouselItem>>().Single().Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This tests that the F1 key will open the mod select overlay, and not be handled / blocked by the music controller (which has the same default binding
|
||||
/// but should be handled *after* song select).
|
||||
|
@ -18,26 +18,24 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider { get; set; } = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
private readonly BindableDouble current = new BindableDouble(5)
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 0,
|
||||
MaxValue = 15
|
||||
};
|
||||
|
||||
private RoundedSliderBar<double> slider = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
Child = slider = new RoundedSliderBar<double>
|
||||
AddStep("create slider", () => Child = slider = new RoundedSliderBar<double>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Current = current,
|
||||
Current = new BindableDouble(5)
|
||||
{
|
||||
Precision = 0.1,
|
||||
MinValue = 0,
|
||||
MaxValue = 15
|
||||
},
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.4f
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -55,5 +53,22 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddAssert("slider is default", () => slider.Current.IsDefault);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNubDoubleClickOnDisabledSliderDoesNothing()
|
||||
{
|
||||
AddStep("set slider to 1", () => slider.Current.Value = 1);
|
||||
AddStep("disable slider", () => slider.Current.Disabled = true);
|
||||
|
||||
AddStep("move mouse to nub", () => InputManager.MoveMouseTo(slider.ChildrenOfType<Nub>().Single()));
|
||||
|
||||
AddStep("double click nub", () =>
|
||||
{
|
||||
InputManager.Click(MouseButton.Left);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("slider is still at 1", () => slider.Current.Value, () => Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,26 +18,24 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider { get; set; } = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
private readonly BindableDouble current = new BindableDouble(5)
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 0,
|
||||
MaxValue = 15
|
||||
};
|
||||
|
||||
private ShearedSliderBar<double> slider = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
Child = slider = new ShearedSliderBar<double>
|
||||
AddStep("create slider", () => Child = slider = new ShearedSliderBar<double>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Current = current,
|
||||
Current = new BindableDouble(5)
|
||||
{
|
||||
Precision = 0.1,
|
||||
MinValue = 0,
|
||||
MaxValue = 15
|
||||
},
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.4f
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -55,5 +53,22 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddAssert("slider is default", () => slider.Current.IsDefault);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNubDoubleClickOnDisabledSliderDoesNothing()
|
||||
{
|
||||
AddStep("set slider to 1", () => slider.Current.Value = 1);
|
||||
AddStep("disable slider", () => slider.Current.Disabled = true);
|
||||
|
||||
AddStep("move mouse to nub", () => InputManager.MoveMouseTo(slider.ChildrenOfType<ShearedNub>().Single()));
|
||||
|
||||
AddStep("double click nub", () =>
|
||||
{
|
||||
InputManager.Click(MouseButton.Left);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("slider is still at 1", () => slider.Current.Value, () => Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public partial class DateTextBox : SettingsTextBox
|
||||
{
|
||||
private readonly BindableWithCurrent<DateTimeOffset> current = new BindableWithCurrent<DateTimeOffset>();
|
||||
private readonly BindableWithCurrent<DateTimeOffset> current = new BindableWithCurrent<DateTimeOffset>(DateTimeOffset.Now);
|
||||
|
||||
public new Bindable<DateTimeOffset>? Current
|
||||
{
|
||||
|
@ -98,7 +98,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativePositionAxes = Axes.X,
|
||||
Current = { Value = true },
|
||||
OnDoubleClicked = () => Current.SetDefault(),
|
||||
OnDoubleClicked = () =>
|
||||
{
|
||||
if (!Current.Disabled)
|
||||
Current.SetDefault();
|
||||
},
|
||||
},
|
||||
},
|
||||
hoverClickSounds = new HoverClickSounds()
|
||||
|
@ -101,7 +101,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativePositionAxes = Axes.X,
|
||||
Current = { Value = true },
|
||||
OnDoubleClicked = () => Current.SetDefault(),
|
||||
OnDoubleClicked = () =>
|
||||
{
|
||||
if (!Current.Disabled)
|
||||
Current.SetDefault();
|
||||
},
|
||||
},
|
||||
},
|
||||
hoverClickSounds = new HoverClickSounds()
|
||||
|
@ -149,6 +149,7 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene),
|
||||
new KeyBinding(InputKey.ExtraMouseButton2, GlobalAction.SkipCutscene),
|
||||
new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.R }, GlobalAction.QuickRetry),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Tilde }, GlobalAction.QuickExit),
|
||||
new KeyBinding(new[] { InputKey.F3 }, GlobalAction.DecreaseScrollSpeed),
|
||||
new KeyBinding(new[] { InputKey.F4 }, GlobalAction.IncreaseScrollSpeed),
|
||||
|
@ -98,12 +98,6 @@ namespace osu.Game.Rulesets.Edit
|
||||
}
|
||||
});
|
||||
|
||||
if (DistanceSpacingMultiplier.Disabled)
|
||||
{
|
||||
distanceSpacingSlider.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
DistanceSpacingMultiplier.Value = editorBeatmap.BeatmapInfo.DistanceSpacing;
|
||||
DistanceSpacingMultiplier.BindValueChanged(multiplier =>
|
||||
{
|
||||
@ -116,6 +110,8 @@ namespace osu.Game.Rulesets.Edit
|
||||
editorBeatmap.BeatmapInfo.DistanceSpacing = multiplier.NewValue;
|
||||
}, true);
|
||||
|
||||
DistanceSpacingMultiplier.BindDisabledChanged(disabled => distanceSpacingSlider.Alpha = disabled ? 0 : 1, true);
|
||||
|
||||
// Manual binding to handle enabling distance spacing when the slider is interacted with.
|
||||
distanceSpacingSlider.Current.BindValueChanged(spacing =>
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private readonly WorkingBeatmap beatmap;
|
||||
|
||||
private readonly Track track;
|
||||
private Track track;
|
||||
|
||||
private readonly double skipTargetTime;
|
||||
|
||||
@ -145,7 +145,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected override void StartGameplayClock()
|
||||
{
|
||||
addSourceClockAdjustments();
|
||||
addAdjustmentsToTrack();
|
||||
|
||||
base.StartGameplayClock();
|
||||
|
||||
@ -186,20 +186,20 @@ namespace osu.Game.Screens.Play
|
||||
/// </summary>
|
||||
public void StopUsingBeatmapClock()
|
||||
{
|
||||
removeSourceClockAdjustments();
|
||||
removeAdjustmentsFromTrack();
|
||||
|
||||
var virtualTrack = new TrackVirtual(beatmap.Track.Length);
|
||||
virtualTrack.Seek(CurrentTime);
|
||||
track = new TrackVirtual(beatmap.Track.Length);
|
||||
track.Seek(CurrentTime);
|
||||
if (IsRunning)
|
||||
virtualTrack.Start();
|
||||
ChangeSource(virtualTrack);
|
||||
track.Start();
|
||||
ChangeSource(track);
|
||||
|
||||
addSourceClockAdjustments();
|
||||
addAdjustmentsToTrack();
|
||||
}
|
||||
|
||||
private bool speedAdjustmentsApplied;
|
||||
|
||||
private void addSourceClockAdjustments()
|
||||
private void addAdjustmentsToTrack()
|
||||
{
|
||||
if (speedAdjustmentsApplied)
|
||||
return;
|
||||
@ -213,7 +213,7 @@ namespace osu.Game.Screens.Play
|
||||
speedAdjustmentsApplied = true;
|
||||
}
|
||||
|
||||
private void removeSourceClockAdjustments()
|
||||
private void removeAdjustmentsFromTrack()
|
||||
{
|
||||
if (!speedAdjustmentsApplied)
|
||||
return;
|
||||
@ -228,7 +228,7 @@ namespace osu.Game.Screens.Play
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
removeSourceClockAdjustments();
|
||||
removeAdjustmentsFromTrack();
|
||||
}
|
||||
|
||||
ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo;
|
||||
|
@ -1019,7 +1019,7 @@ namespace osu.Game.Screens.Select
|
||||
/// <summary>
|
||||
/// Handles mouse interactions required when moving away from the carousel.
|
||||
/// </summary>
|
||||
private partial class LeftSideInteractionContainer : Container
|
||||
internal partial class LeftSideInteractionContainer : Container
|
||||
{
|
||||
private readonly Action? resetCarouselPosition;
|
||||
|
||||
@ -1028,7 +1028,10 @@ namespace osu.Game.Screens.Select
|
||||
this.resetCarouselPosition = resetCarouselPosition;
|
||||
}
|
||||
|
||||
protected override bool OnScroll(ScrollEvent e) => true;
|
||||
// we want to block plain scrolls on the left side so that they don't scroll the carousel,
|
||||
// but also we *don't* want to handle scrolls when they're combined with keyboard modifiers
|
||||
// as those will usually correspond to other interactions like adjusting volume.
|
||||
protected override bool OnScroll(ScrollEvent e) => !e.ControlPressed && !e.AltPressed && !e.ShiftPressed && !e.SuperPressed;
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e) => true;
|
||||
|
||||
|
@ -39,7 +39,8 @@
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2023.1012.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.1023.0" />
|
||||
<PackageReference Include="Sentry" Version="3.40.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.34.1" />
|
||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||
<PackageReference Include="SharpCompress" Version="0.33.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.6" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user