mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 17:43:05 +08:00
Merge branch 'master' into fix-exported-replay-overwrite
This commit is contained in:
commit
cb64919947
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1130.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1204.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Rulesets.Catch.Mods;
|
using osu.Game.Rulesets.Catch.Mods;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
@ -55,6 +57,21 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameCursorHidden()
|
||||||
|
{
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new CatchModRelax(),
|
||||||
|
Autoplay = false,
|
||||||
|
PassCondition = () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<DrawableCatchRuleset>().Single());
|
||||||
|
return this.ChildrenOfType<MenuCursorContainer>().Single().State.Value == Visibility.Hidden;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private bool passCondition()
|
private bool passCondition()
|
||||||
{
|
{
|
||||||
var playfield = this.ChildrenOfType<CatchPlayfield>().Single();
|
var playfield = this.ChildrenOfType<CatchPlayfield>().Single();
|
||||||
|
@ -3,13 +3,16 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -49,6 +52,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
this.difficulty = difficulty;
|
this.difficulty = difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override GameplayCursorContainer CreateCursor()
|
||||||
|
{
|
||||||
|
if (Mods != null && Mods.Any(m => m is ModRelax))
|
||||||
|
return new CatchRelaxCursorContainer();
|
||||||
|
|
||||||
|
return base.CreateCursor();
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
15
osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs
Normal file
15
osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
|
{
|
||||||
|
public partial class CatchRelaxCursorContainer : GameplayCursorContainer
|
||||||
|
{
|
||||||
|
// Just hide the cursor in relax.
|
||||||
|
// The main goal here is to show that we have a cursor so the game never shows the global one.
|
||||||
|
protected override Drawable CreateCursor() => Empty();
|
||||||
|
}
|
||||||
|
}
|
@ -90,6 +90,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
public override bool CursorInPlacementArea => false;
|
public override bool CursorInPlacementArea => false;
|
||||||
|
|
||||||
public TestHitObjectComposer(Playfield playfield)
|
public TestHitObjectComposer(Playfield playfield)
|
||||||
|
: base(new ManiaRuleset())
|
||||||
{
|
{
|
||||||
Playfield = playfield;
|
Playfield = playfield;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -22,6 +24,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
|||||||
|
|
||||||
private bool isPlacingEnd;
|
private bool isPlacingEnd;
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
[CanBeNull]
|
||||||
|
private IBeatSnapProvider beatSnapProvider { get; set; }
|
||||||
|
|
||||||
public SpinnerPlacementBlueprint()
|
public SpinnerPlacementBlueprint()
|
||||||
: base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 })
|
: base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 })
|
||||||
{
|
{
|
||||||
@ -33,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (isPlacingEnd)
|
if (isPlacingEnd)
|
||||||
HitObject.EndTime = Math.Max(HitObject.StartTime, EditorClock.CurrentTime);
|
updateEndTimeFromCurrent();
|
||||||
|
|
||||||
piece.UpdateFrom(HitObject);
|
piece.UpdateFrom(HitObject);
|
||||||
}
|
}
|
||||||
@ -45,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
|||||||
if (e.Button != MouseButton.Right)
|
if (e.Button != MouseButton.Right)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
HitObject.EndTime = EditorClock.CurrentTime;
|
updateEndTimeFromCurrent();
|
||||||
EndPlacement(true);
|
EndPlacement(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -61,5 +67,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateEndTimeFromCurrent()
|
||||||
|
{
|
||||||
|
HitObject.EndTime = beatSnapProvider == null
|
||||||
|
? Math.Max(HitObject.StartTime, EditorClock.CurrentTime)
|
||||||
|
: Math.Max(HitObject.StartTime + beatSnapProvider.GetBeatLengthAtTime(HitObject.StartTime), beatSnapProvider.SnapTime(EditorClock.CurrentTime));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
@ -196,8 +195,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
private IEnumerable<double> generateBeats(IBeatmap beatmap, IReadOnlyCollection<OsuHitObject> originalHitObjects)
|
private IEnumerable<double> generateBeats(IBeatmap beatmap, IReadOnlyCollection<OsuHitObject> originalHitObjects)
|
||||||
{
|
{
|
||||||
double startTime = originalHitObjects.First().StartTime;
|
double startTime = beatmap.HitObjects.First().StartTime;
|
||||||
double endTime = originalHitObjects.Last().GetEndTime();
|
double endTime = beatmap.GetLastObjectTime();
|
||||||
|
|
||||||
var beats = beatmap.ControlPointInfo.TimingPoints
|
var beats = beatmap.ControlPointInfo.TimingPoints
|
||||||
// Ignore timing points after endTime
|
// Ignore timing points after endTime
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Taiko.Skinning.Legacy;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
||||||
|
{
|
||||||
|
public partial class TestSceneTaikoKiaiGlow : TaikoSkinnableTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestKiaiGlow()
|
||||||
|
{
|
||||||
|
AddStep("Create kiai glow", () => SetContents(_ => new LegacyKiaiGlow()));
|
||||||
|
AddToggleStep("Toggle kiai mode", setUpBeatmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUpBeatmap(bool withKiai)
|
||||||
|
{
|
||||||
|
var controlPointInfo = new ControlPointInfo();
|
||||||
|
|
||||||
|
controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 });
|
||||||
|
|
||||||
|
if (withKiai)
|
||||||
|
controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true });
|
||||||
|
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(new Beatmap
|
||||||
|
{
|
||||||
|
ControlPointInfo = controlPointInfo
|
||||||
|
});
|
||||||
|
|
||||||
|
Beatmap.Value.Track.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs
Normal file
65
osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
||||||
|
{
|
||||||
|
internal partial class LegacyKiaiGlow : BeatSyncedContainer
|
||||||
|
{
|
||||||
|
private bool isKiaiActive;
|
||||||
|
|
||||||
|
private Sprite sprite = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(ISkinSource skin, HealthProcessor? healthProcessor)
|
||||||
|
{
|
||||||
|
Child = sprite = new Sprite
|
||||||
|
{
|
||||||
|
Texture = skin.GetTexture("taiko-glow"),
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Alpha = 0,
|
||||||
|
Scale = new Vector2(0.7f),
|
||||||
|
Colour = new Colour4(255, 228, 0, 255),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (healthProcessor != null)
|
||||||
|
healthProcessor.NewJudgement += onNewJudgement;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (isKiaiActive)
|
||||||
|
sprite.Alpha = (float)Math.Min(1, sprite.Alpha + Math.Abs(Clock.ElapsedFrameTime) / 100f);
|
||||||
|
else
|
||||||
|
sprite.Alpha = (float)Math.Max(0, sprite.Alpha - Math.Abs(Clock.ElapsedFrameTime) / 600f);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||||
|
{
|
||||||
|
isKiaiActive = effectPoint.KiaiMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onNewJudgement(JudgementResult result)
|
||||||
|
{
|
||||||
|
if (!result.IsHit || !isKiaiActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sprite.ScaleTo(0.85f).Then()
|
||||||
|
.ScaleTo(0.7f, 80, Easing.OutQuad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
private Sprite kiai = null!;
|
private Sprite kiai = null!;
|
||||||
|
|
||||||
private bool kiaiDisplayed;
|
private bool isKiaiActive;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin)
|
private void load(ISkinSource skin)
|
||||||
@ -41,17 +42,19 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (isKiaiActive)
|
||||||
|
kiai.Alpha = (float)Math.Min(1, kiai.Alpha + Math.Abs(Clock.ElapsedFrameTime) / 200f);
|
||||||
|
else
|
||||||
|
kiai.Alpha = (float)Math.Max(0, kiai.Alpha - Math.Abs(Clock.ElapsedFrameTime) / 200f);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||||
{
|
{
|
||||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
isKiaiActive = effectPoint.KiaiMode;
|
||||||
|
|
||||||
if (effectPoint.KiaiMode != kiaiDisplayed)
|
|
||||||
{
|
|
||||||
kiaiDisplayed = effectPoint.KiaiMode;
|
|
||||||
|
|
||||||
kiai.ClearTransforms();
|
|
||||||
kiai.FadeTo(kiaiDisplayed ? 1 : 0, 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
case TaikoSkinComponents.Mascot:
|
case TaikoSkinComponents.Mascot:
|
||||||
return new DrawableTaikoMascot();
|
return new DrawableTaikoMascot();
|
||||||
|
|
||||||
|
case TaikoSkinComponents.KiaiGlow:
|
||||||
|
if (GetTexture("taiko-glow") != null)
|
||||||
|
return new LegacyKiaiGlow();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedSkinComponentException(lookup);
|
throw new UnsupportedSkinComponentException(lookup);
|
||||||
}
|
}
|
||||||
|
@ -21,5 +21,6 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
TaikoExplosionKiai,
|
TaikoExplosionKiai,
|
||||||
Scroller,
|
Scroller,
|
||||||
Mascot,
|
Mascot,
|
||||||
|
KiaiGlow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,10 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
FillMode = FillMode.Fit,
|
FillMode = FillMode.Fit,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
|
new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.KiaiGlow), _ => Empty())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
hitExplosionContainer = new Container<HitExplosion>
|
hitExplosionContainer = new Container<HitExplosion>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
@ -314,6 +314,24 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGetLastObjectTime()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder();
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("mania-last-object-not-latest.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var beatmap = decoder.Decode(stream);
|
||||||
|
|
||||||
|
Assert.That(beatmap.HitObjects.Last().StartTime, Is.EqualTo(2494));
|
||||||
|
Assert.That(beatmap.HitObjects.Last().GetEndTime(), Is.EqualTo(2494));
|
||||||
|
|
||||||
|
Assert.That(beatmap.HitObjects.Max(h => h.GetEndTime()), Is.EqualTo(2582));
|
||||||
|
Assert.That(beatmap.GetLastObjectTime(), Is.EqualTo(2582));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDecodeBeatmapComboOffsetsOsu()
|
public void TestDecodeBeatmapComboOffsetsOsu()
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -137,6 +138,31 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
AddAssert("DHO state is correct", () => dho.State.Value == ArmedState.Miss);
|
AddAssert("DHO state is correct", () => dho.State.Value == ArmedState.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResultSetBeforeLoadComplete()
|
||||||
|
{
|
||||||
|
TestDrawableHitObject dho = null;
|
||||||
|
HitObjectLifetimeEntry lifetimeEntry = null;
|
||||||
|
AddStep("Create lifetime entry", () =>
|
||||||
|
{
|
||||||
|
var hitObject = new HitObject { StartTime = Time.Current };
|
||||||
|
lifetimeEntry = new HitObjectLifetimeEntry(hitObject)
|
||||||
|
{
|
||||||
|
Result = new JudgementResult(hitObject, hitObject.CreateJudgement())
|
||||||
|
{
|
||||||
|
Type = HitResult.Great
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
AddStep("Create DHO and apply entry", () =>
|
||||||
|
{
|
||||||
|
dho = new TestDrawableHitObject();
|
||||||
|
dho.Apply(lifetimeEntry);
|
||||||
|
Child = dho;
|
||||||
|
});
|
||||||
|
AddAssert("DHO state is correct", () => dho.State.Value, () => Is.EqualTo(ArmedState.Hit));
|
||||||
|
}
|
||||||
|
|
||||||
private partial class TestDrawableHitObject : DrawableHitObject
|
private partial class TestDrawableHitObject : DrawableHitObject
|
||||||
{
|
{
|
||||||
public const double INITIAL_LIFETIME_OFFSET = 100;
|
public const double INITIAL_LIFETIME_OFFSET = 100;
|
||||||
|
39
osu.Game.Tests/Resources/mania-last-object-not-latest.osu
Normal file
39
osu.Game.Tests/Resources/mania-last-object-not-latest.osu
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
SampleSet: Normal
|
||||||
|
StackLeniency: 0.7
|
||||||
|
Mode: 3
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
HPDrainRate:3
|
||||||
|
CircleSize:5
|
||||||
|
OverallDifficulty:8
|
||||||
|
ApproachRate:8
|
||||||
|
SliderMultiplier:3.59999990463257
|
||||||
|
SliderTickRate:2
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
24,352.941176470588,4,1,1,100,1,0
|
||||||
|
6376,-50,4,1,1,100,0,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
51,192,24,1,0,0:0:0:0:
|
||||||
|
153,192,200,1,0,0:0:0:0:
|
||||||
|
358,192,376,1,0,0:0:0:0:
|
||||||
|
460,192,553,1,0,0:0:0:0:
|
||||||
|
460,192,729,128,0,1435:0:0:0:0:
|
||||||
|
358,192,906,128,0,1612:0:0:0:0:
|
||||||
|
256,192,1082,128,0,1788:0:0:0:0:
|
||||||
|
153,192,1259,128,0,1965:0:0:0:0:
|
||||||
|
51,192,1435,128,0,2141:0:0:0:0:
|
||||||
|
51,192,2318,1,12,0:0:0:0:
|
||||||
|
153,192,2318,1,4,0:0:0:0:
|
||||||
|
256,192,2318,1,6,0:0:0:0:
|
||||||
|
358,192,2318,1,14,0:0:0:0:
|
||||||
|
460,192,2318,1,0,0:0:0:0:
|
||||||
|
51,192,2494,128,0,2582:0:0:0:0:
|
||||||
|
153,192,2494,128,14,2582:0:0:0:0:
|
||||||
|
256,192,2494,128,6,2582:0:0:0:0:
|
||||||
|
358,192,2494,128,4,2582:0:0:0:0:
|
||||||
|
460,192,2494,1,12,0:0:0:0:0:
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -187,18 +188,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestInputDoesntWorkWhenHUDHidden()
|
public void TestInputDoesntWorkWhenHUDHidden()
|
||||||
{
|
{
|
||||||
SongProgressBar getSongProgress() => hudOverlay.ChildrenOfType<SongProgressBar>().Single();
|
SongProgressBar? getSongProgress() => hudOverlay.ChildrenOfType<SongProgressBar>().SingleOrDefault();
|
||||||
|
|
||||||
bool seeked = false;
|
bool seeked = false;
|
||||||
|
|
||||||
createNew();
|
createNew();
|
||||||
|
|
||||||
|
AddUntilStep("wait for song progress", () => getSongProgress() != null);
|
||||||
|
|
||||||
AddStep("bind seek", () =>
|
AddStep("bind seek", () =>
|
||||||
{
|
{
|
||||||
seeked = false;
|
seeked = false;
|
||||||
|
|
||||||
var progress = getSongProgress();
|
var progress = getSongProgress();
|
||||||
|
|
||||||
|
Debug.Assert(progress != null);
|
||||||
|
|
||||||
progress.ShowHandle = true;
|
progress.ShowHandle = true;
|
||||||
progress.OnSeek += _ => seeked = true;
|
progress.OnSeek += _ => seeked = true;
|
||||||
});
|
});
|
||||||
|
@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
|
|
||||||
AddAssert("state is available", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
checkState(DownloadState.NotDownloaded);
|
||||||
|
|
||||||
AddStep("click button", () =>
|
AddStep("click button", () =>
|
||||||
{
|
{
|
||||||
@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
|
|
||||||
AddAssert("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
checkState(DownloadState.NotDownloaded);
|
||||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
|
|
||||||
AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
checkState(DownloadState.NotDownloaded);
|
||||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,17 +174,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
|
checkState(DownloadState.NotDownloaded);
|
||||||
AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
|
||||||
|
|
||||||
AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)));
|
AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)));
|
||||||
|
|
||||||
AddUntilStep("state is available", () => downloadButton.State.Value == DownloadState.LocallyAvailable);
|
checkState(DownloadState.LocallyAvailable);
|
||||||
AddAssert("button is enabled", () => downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
AddAssert("button is enabled", () => downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||||
|
|
||||||
AddStep("delete score", () => scoreManager.Delete(imported.Value));
|
AddStep("delete score", () => scoreManager.Delete(imported.Value));
|
||||||
|
|
||||||
AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
checkState(DownloadState.NotDownloaded);
|
||||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,10 +201,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
|
|
||||||
AddAssert("state is unknown", () => downloadButton.State.Value == DownloadState.Unknown);
|
checkState(DownloadState.Unknown);
|
||||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkState(DownloadState expectedState) =>
|
||||||
|
AddUntilStep($"state is {expectedState}", () => downloadButton.State.Value, () => Is.EqualTo(expectedState));
|
||||||
|
|
||||||
private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true) => new ScoreInfo
|
private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true) => new ScoreInfo
|
||||||
{
|
{
|
||||||
OnlineID = hasOnlineId ? online_score_id : 0,
|
OnlineID = hasOnlineId ? online_score_id : 0,
|
||||||
|
@ -73,6 +73,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
messageIdSequence = 0;
|
messageIdSequence = 0;
|
||||||
channelManager.CurrentChannel.Value = testChannel = new Channel();
|
channelManager.CurrentChannel.Value = testChannel = new Channel();
|
||||||
|
|
||||||
|
reinitialiseDrawableDisplay();
|
||||||
|
});
|
||||||
|
|
||||||
|
private void reinitialiseDrawableDisplay()
|
||||||
|
{
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
chatDisplay = new TestStandAloneChatDisplay
|
chatDisplay = new TestStandAloneChatDisplay
|
||||||
@ -92,13 +97,14 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Channel = { Value = testChannel },
|
Channel = { Value = testChannel },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSystemMessageOrdering()
|
public void TestSystemMessageOrdering()
|
||||||
{
|
{
|
||||||
var standardMessage = new Message(messageIdSequence++)
|
var standardMessage = new Message(messageIdSequence++)
|
||||||
{
|
{
|
||||||
|
Timestamp = DateTimeOffset.Now,
|
||||||
Sender = admin,
|
Sender = admin,
|
||||||
Content = "I am a wang!"
|
Content = "I am a wang!"
|
||||||
};
|
};
|
||||||
@ -106,14 +112,45 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
var infoMessage1 = new InfoMessage($"the system is calling {messageIdSequence++}");
|
var infoMessage1 = new InfoMessage($"the system is calling {messageIdSequence++}");
|
||||||
var infoMessage2 = new InfoMessage($"the system is calling {messageIdSequence++}");
|
var infoMessage2 = new InfoMessage($"the system is calling {messageIdSequence++}");
|
||||||
|
|
||||||
|
var standardMessage2 = new Message(messageIdSequence++)
|
||||||
|
{
|
||||||
|
Timestamp = DateTimeOffset.Now,
|
||||||
|
Sender = admin,
|
||||||
|
Content = "I am a wang!"
|
||||||
|
};
|
||||||
|
|
||||||
AddStep("message from admin", () => testChannel.AddNewMessages(standardMessage));
|
AddStep("message from admin", () => testChannel.AddNewMessages(standardMessage));
|
||||||
AddStep("message from system", () => testChannel.AddNewMessages(infoMessage1));
|
AddStep("message from system", () => testChannel.AddNewMessages(infoMessage1));
|
||||||
AddStep("message from system", () => testChannel.AddNewMessages(infoMessage2));
|
AddStep("message from system", () => testChannel.AddNewMessages(infoMessage2));
|
||||||
|
AddStep("message from admin", () => testChannel.AddNewMessages(standardMessage2));
|
||||||
|
|
||||||
AddAssert("message order is correct", () => testChannel.Messages.Count == 3
|
AddAssert("count is correct", () => testChannel.Messages.Count, () => Is.EqualTo(4));
|
||||||
&& testChannel.Messages[0] == standardMessage
|
|
||||||
&& testChannel.Messages[1] == infoMessage1
|
AddAssert("message order is correct", () => testChannel.Messages, () => Is.EqualTo(new[]
|
||||||
&& testChannel.Messages[2] == infoMessage2);
|
{
|
||||||
|
standardMessage,
|
||||||
|
infoMessage1,
|
||||||
|
infoMessage2,
|
||||||
|
standardMessage2
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddAssert("displayed order is correct", () => chatDisplay.DrawableChannel.ChildrenOfType<ChatLine>().Select(c => c.Message), () => Is.EqualTo(new[]
|
||||||
|
{
|
||||||
|
standardMessage,
|
||||||
|
infoMessage1,
|
||||||
|
infoMessage2,
|
||||||
|
standardMessage2
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddStep("reinit drawable channel", reinitialiseDrawableDisplay);
|
||||||
|
|
||||||
|
AddAssert("displayed order is still correct", () => chatDisplay.DrawableChannel.ChildrenOfType<ChatLine>().Select(c => c.Message), () => Is.EqualTo(new[]
|
||||||
|
{
|
||||||
|
standardMessage,
|
||||||
|
infoMessage1,
|
||||||
|
infoMessage2,
|
||||||
|
standardMessage2
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -81,9 +81,14 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public double GetMostCommonBeatLength()
|
public double GetMostCommonBeatLength()
|
||||||
{
|
{
|
||||||
|
double lastTime;
|
||||||
|
|
||||||
// The last playable time in the beatmap - the last timing point extends to this time.
|
// The last playable time in the beatmap - the last timing point extends to this time.
|
||||||
// Note: This is more accurate and may present different results because osu-stable didn't have the ability to calculate slider durations in this context.
|
// Note: This is more accurate and may present different results because osu-stable didn't have the ability to calculate slider durations in this context.
|
||||||
double lastTime = HitObjects.LastOrDefault()?.GetEndTime() ?? ControlPointInfo.TimingPoints.LastOrDefault()?.Time ?? 0;
|
if (!HitObjects.Any())
|
||||||
|
lastTime = ControlPointInfo.TimingPoints.LastOrDefault()?.Time ?? 0;
|
||||||
|
else
|
||||||
|
lastTime = this.GetLastObjectTime();
|
||||||
|
|
||||||
var mostCommon =
|
var mostCommon =
|
||||||
// Construct a set of (beatLength, duration) tuples for each individual timing point.
|
// Construct a set of (beatLength, duration) tuples for each individual timing point.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -102,5 +103,16 @@ namespace osu.Game.Beatmaps
|
|||||||
addCombo(nested, ref combo);
|
addCombo(nested, ref combo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find the absolute end time of the latest <see cref="HitObject"/> in a beatmap. Will throw if beatmap contains no objects.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This correctly accounts for rulesets which have concurrent hitobjects which may have durations, causing the .Last() object
|
||||||
|
/// to not necessarily have the latest end time.
|
||||||
|
///
|
||||||
|
/// It's not super efficient so calls should be kept to a minimum.
|
||||||
|
/// </remarks>
|
||||||
|
public static double GetLastObjectTime(this IBeatmap beatmap) => beatmap.HitObjects.Max(h => h.GetEndTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
namespace osu.Game.Online.Chat
|
namespace osu.Game.Online.Chat
|
||||||
@ -13,7 +10,6 @@ namespace osu.Game.Online.Chat
|
|||||||
public InfoMessage(string message)
|
public InfoMessage(string message)
|
||||||
: base(null)
|
: base(null)
|
||||||
{
|
{
|
||||||
Timestamp = DateTimeOffset.Now;
|
|
||||||
Content = message;
|
Content = message;
|
||||||
|
|
||||||
Sender = APIUser.SYSTEM_USER;
|
Sender = APIUser.SYSTEM_USER;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Online.Chat
|
namespace osu.Game.Online.Chat
|
||||||
{
|
{
|
||||||
public class LocalEchoMessage : LocalMessage
|
public class LocalEchoMessage : LocalMessage
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Online.Chat
|
namespace osu.Game.Online.Chat
|
||||||
{
|
{
|
||||||
@ -13,6 +13,7 @@ namespace osu.Game.Online.Chat
|
|||||||
protected LocalMessage(long? id)
|
protected LocalMessage(long? id)
|
||||||
: base(id)
|
: base(id)
|
||||||
{
|
{
|
||||||
|
Timestamp = DateTimeOffset.Now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
@ -59,19 +60,28 @@ namespace osu.Game.Online.Chat
|
|||||||
/// <remarks>The <see cref="Link"/>s' <see cref="Link.Index"/> and <see cref="Link.Length"/>s are according to <see cref="DisplayContent"/></remarks>
|
/// <remarks>The <see cref="Link"/>s' <see cref="Link.Index"/> and <see cref="Link.Length"/>s are according to <see cref="DisplayContent"/></remarks>
|
||||||
public List<Link> Links;
|
public List<Link> Links;
|
||||||
|
|
||||||
|
private static long constructionOrderStatic;
|
||||||
|
private readonly long constructionOrder;
|
||||||
|
|
||||||
public Message(long? id)
|
public Message(long? id)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
|
|
||||||
|
constructionOrder = Interlocked.Increment(ref constructionOrderStatic);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Message other)
|
public int CompareTo(Message other)
|
||||||
{
|
{
|
||||||
if (!Id.HasValue)
|
if (Id.HasValue && other.Id.HasValue)
|
||||||
return other.Id.HasValue ? 1 : Timestamp.CompareTo(other.Timestamp);
|
return Id.Value.CompareTo(other.Id.Value);
|
||||||
if (!other.Id.HasValue)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return Id.Value.CompareTo(other.Id.Value);
|
int timestampComparison = Timestamp.CompareTo(other.Timestamp);
|
||||||
|
|
||||||
|
if (timestampComparison != 0)
|
||||||
|
return timestampComparison;
|
||||||
|
|
||||||
|
// Timestamp might not be accurate enough to make a stable sorting decision.
|
||||||
|
return constructionOrder.CompareTo(other.constructionOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Equals(Message other)
|
public virtual bool Equals(Message other)
|
||||||
@ -85,6 +95,6 @@ namespace osu.Game.Online.Chat
|
|||||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||||
public override int GetHashCode() => Id.GetHashCode();
|
public override int GetHashCode() => Id.GetHashCode();
|
||||||
|
|
||||||
public override string ToString() => $"[{ChannelId}] ({Id}) {Sender}: {Content}";
|
public override string ToString() => $"({(Id?.ToString() ?? "null")}) {Timestamp} {Sender}: {Content}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
loading.Hide();
|
loading.Hide();
|
||||||
tick.FadeIn(500, Easing.OutQuint);
|
tick.FadeIn(500, Easing.OutQuint);
|
||||||
|
|
||||||
Background.FadeColour(colours.Green, 500, Easing.OutQuint);
|
this.TransformTo(nameof(BackgroundColour), colours.Green, 500, Easing.OutQuint);
|
||||||
progressBar.FillColour = colours.Green;
|
progressBar.FillColour = colours.Green;
|
||||||
|
|
||||||
this.TransformBindableTo(progressBar.Current, 1, 500, Easing.OutQuint);
|
this.TransformBindableTo(progressBar.Current, 1, 500, Easing.OutQuint);
|
||||||
|
@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
protected IRulesetConfigManager Config { get; private set; }
|
protected IRulesetConfigManager Config { get; private set; }
|
||||||
|
|
||||||
protected readonly Ruleset Ruleset;
|
|
||||||
|
|
||||||
// Provides `Playfield`
|
// Provides `Playfield`
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
|
|
||||||
@ -74,8 +72,8 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
private IBindable<bool> hasTiming;
|
private IBindable<bool> hasTiming;
|
||||||
|
|
||||||
protected HitObjectComposer(Ruleset ruleset)
|
protected HitObjectComposer(Ruleset ruleset)
|
||||||
|
: base(ruleset)
|
||||||
{
|
{
|
||||||
Ruleset = ruleset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
||||||
@ -419,8 +417,11 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
[Cached]
|
[Cached]
|
||||||
public abstract partial class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
public abstract partial class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
||||||
{
|
{
|
||||||
protected HitObjectComposer()
|
public readonly Ruleset Ruleset;
|
||||||
|
|
||||||
|
protected HitObjectComposer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
|
Ruleset = ruleset;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit
|
namespace osu.Game.Rulesets.Edit
|
||||||
{
|
{
|
||||||
public interface IBeatSnapProvider
|
public interface IBeatSnapProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Snaps a duration to the closest beat of a timing point applicable at the reference time.
|
/// Snaps a duration to the closest beat of a timing point applicable at the reference time, factoring in the current <see cref="BeatDivisor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The time to snap.</param>
|
/// <param name="time">The time to snap.</param>
|
||||||
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
|
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
|
||||||
@ -16,10 +14,10 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
double SnapTime(double time, double? referenceTime = null);
|
double SnapTime(double time, double? referenceTime = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the most appropriate beat length at a given time.
|
/// Get the most appropriate beat length at a given time, pre-divided by <see cref="BeatDivisor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="referenceTime">A reference time used for lookup.</param>
|
/// <param name="referenceTime">A reference time used for lookup.</param>
|
||||||
/// <returns>The most appropriate beat length.</returns>
|
/// <returns>The most appropriate beat length, divided by <see cref="BeatDivisor"/>.</returns>
|
||||||
double GetBeatLengthAtTime(double referenceTime);
|
double GetBeatLengthAtTime(double referenceTime);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Audio;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
@ -71,7 +70,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
SpeedChange.SetDefault();
|
SpeedChange.SetDefault();
|
||||||
|
|
||||||
double firstObjectStart = beatmap.HitObjects.FirstOrDefault()?.StartTime ?? 0;
|
double firstObjectStart = beatmap.HitObjects.FirstOrDefault()?.StartTime ?? 0;
|
||||||
double lastObjectEnd = beatmap.HitObjects.LastOrDefault()?.GetEndTime() ?? 0;
|
double lastObjectEnd = beatmap.HitObjects.Any() ? beatmap.GetLastObjectTime() : 0;
|
||||||
|
|
||||||
beginRampTime = firstObjectStart;
|
beginRampTime = firstObjectStart;
|
||||||
finalRateTime = firstObjectStart + FINAL_RATE_PROGRESS * (lastObjectEnd - firstObjectStart);
|
finalRateTime = firstObjectStart + FINAL_RATE_PROGRESS * (lastObjectEnd - firstObjectStart);
|
||||||
|
@ -27,11 +27,8 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HitObject firstObject = beatmap.HitObjects.First();
|
double firstHitTime = beatmap.HitObjects.First().StartTime;
|
||||||
HitObject lastObject = beatmap.HitObjects.Last();
|
double lastHitTime = 1 + beatmap.GetLastObjectTime();
|
||||||
|
|
||||||
double firstHitTime = firstObject.StartTime;
|
|
||||||
double lastHitTime = 1 + lastObject.GetEndTime();
|
|
||||||
|
|
||||||
var timingPoints = beatmap.ControlPointInfo.TimingPoints;
|
var timingPoints = beatmap.ControlPointInfo.TimingPoints;
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
comboColourBrightness.BindValueChanged(_ => UpdateComboColour());
|
comboColourBrightness.BindValueChanged(_ => UpdateComboColour());
|
||||||
|
|
||||||
// Apply transforms
|
// Apply transforms
|
||||||
updateState(State.Value, true);
|
updateStateFromResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -266,12 +266,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
// If not loaded, the state update happens in LoadComplete().
|
// If not loaded, the state update happens in LoadComplete().
|
||||||
if (IsLoaded)
|
if (IsLoaded)
|
||||||
{
|
{
|
||||||
if (Result.IsHit)
|
updateStateFromResult();
|
||||||
updateState(ArmedState.Hit, true);
|
|
||||||
else if (Result.HasResult)
|
|
||||||
updateState(ArmedState.Miss, true);
|
|
||||||
else
|
|
||||||
updateState(ArmedState.Idle, true);
|
|
||||||
|
|
||||||
// Combo colour may have been applied via a bindable flow while no object entry was attached.
|
// Combo colour may have been applied via a bindable flow while no object entry was attached.
|
||||||
// Update here to ensure we're in a good state.
|
// Update here to ensure we're in a good state.
|
||||||
@ -279,6 +274,16 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateStateFromResult()
|
||||||
|
{
|
||||||
|
if (Result.IsHit)
|
||||||
|
updateState(ArmedState.Hit, true);
|
||||||
|
else if (Result.HasResult)
|
||||||
|
updateState(ArmedState.Miss, true);
|
||||||
|
else
|
||||||
|
updateState(ArmedState.Idle, true);
|
||||||
|
}
|
||||||
|
|
||||||
protected sealed override void OnFree(HitObjectLifetimeEntry entry)
|
protected sealed override void OnFree(HitObjectLifetimeEntry entry)
|
||||||
{
|
{
|
||||||
StartTimeBindable.UnbindFrom(HitObject.StartTimeBindable);
|
StartTimeBindable.UnbindFrom(HitObject.StartTimeBindable);
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.UI
|
||||||
|
{
|
||||||
|
public partial class DrawableRulesetDependenciesProvidingContainer : Container
|
||||||
|
{
|
||||||
|
private readonly Ruleset ruleset;
|
||||||
|
|
||||||
|
private DrawableRulesetDependencies rulesetDependencies = null!;
|
||||||
|
|
||||||
|
public DrawableRulesetDependenciesProvidingContainer(Ruleset ruleset)
|
||||||
|
{
|
||||||
|
this.ruleset = ruleset;
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
{
|
||||||
|
return rulesetDependencies = new DrawableRulesetDependencies(ruleset, base.CreateChildDependencies(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (rulesetDependencies.IsNotNull())
|
||||||
|
rulesetDependencies.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -93,7 +93,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public readonly BindableBool DisplayJudgements = new BindableBool(true);
|
public readonly BindableBool DisplayJudgements = new BindableBool(true);
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IReadOnlyList<Mod> mods { get; set; }
|
[CanBeNull]
|
||||||
|
protected IReadOnlyList<Mod> Mods { get; private set; }
|
||||||
|
|
||||||
private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager();
|
private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager();
|
||||||
|
|
||||||
@ -243,9 +244,9 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (!IsNested && mods != null)
|
if (!IsNested && Mods != null)
|
||||||
{
|
{
|
||||||
foreach (var mod in mods)
|
foreach (var mod in Mods)
|
||||||
{
|
{
|
||||||
if (mod is IUpdatableByPlayfield updatable)
|
if (mod is IUpdatableByPlayfield updatable)
|
||||||
updatable.Update(this);
|
updatable.Update(this);
|
||||||
@ -374,9 +375,9 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
// If this is the first time this DHO is being used, then apply the DHO mods.
|
// If this is the first time this DHO is being used, then apply the DHO mods.
|
||||||
// This is done before Apply() so that the state is updated once when the hitobject is applied.
|
// This is done before Apply() so that the state is updated once when the hitobject is applied.
|
||||||
if (mods != null)
|
if (Mods != null)
|
||||||
{
|
{
|
||||||
foreach (var m in mods.OfType<IApplicableToDrawableHitObject>())
|
foreach (var m in Mods.OfType<IApplicableToDrawableHitObject>())
|
||||||
m.ApplyToDrawableHitObject(dho);
|
m.ApplyToDrawableHitObject(dho);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
double lastObjectTime = Objects.LastOrDefault()?.GetEndTime() ?? double.MaxValue;
|
double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : double.MaxValue;
|
||||||
double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH;
|
double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH;
|
||||||
|
|
||||||
if (RelativeScaleBeatLengths)
|
if (RelativeScaleBeatLengths)
|
||||||
|
@ -20,6 +20,7 @@ using osu.Game.Rulesets.Edit.Tools;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Edit.Components.TernaryButtons;
|
using osu.Game.Screens.Edit.Components.TernaryButtons;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -57,7 +58,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
TernaryStates = CreateTernaryButtons().ToArray();
|
TernaryStates = CreateTernaryButtons().ToArray();
|
||||||
|
|
||||||
AddInternal(placementBlueprintContainer);
|
AddInternal(new DrawableRulesetDependenciesProvidingContainer(Composer.Ruleset)
|
||||||
|
{
|
||||||
|
Child = placementBlueprintContainer
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -18,6 +18,7 @@ using osu.Framework.Utils;
|
|||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -54,6 +55,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private ISkinSource skin { get; set; } = null!;
|
private ISkinSource skin { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||||
|
|
||||||
public TimelineHitObjectBlueprint(HitObject item)
|
public TimelineHitObjectBlueprint(HitObject item)
|
||||||
: base(item)
|
: base(item)
|
||||||
{
|
{
|
||||||
@ -165,7 +169,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
colour = colourProvider.Highlight1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSelected)
|
if (IsSelected)
|
||||||
@ -419,9 +424,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IHasDuration endTimeHitObject:
|
case IHasDuration endTimeHitObject:
|
||||||
double snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
double snappedTime = Math.Max(hitObject.StartTime + beatSnapProvider.GetBeatLengthAtTime(hitObject.StartTime), beatSnapProvider.SnapTime(time));
|
||||||
|
|
||||||
if (endTimeHitObject.EndTime == snappedTime || Precision.AlmostEquals(snappedTime, hitObject.StartTime, beatmap.GetBeatLengthAtTime(snappedTime)))
|
if (endTimeHitObject.EndTime == snappedTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
endTimeHitObject.Duration = snappedTime - hitObject.StartTime;
|
endTimeHitObject.Duration = snappedTime - hitObject.StartTime;
|
||||||
|
@ -40,7 +40,6 @@ using osu.Game.Overlays.Notifications;
|
|||||||
using osu.Game.Overlays.OSD;
|
using osu.Game.Overlays.OSD;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Screens.Edit.Components.Menus;
|
using osu.Game.Screens.Edit.Components.Menus;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
@ -538,12 +537,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
// Seek to last object time, or track end if already there.
|
// Seek to last object time, or track end if already there.
|
||||||
// Note that in osu-stable subsequent presses when at track end won't return to last object.
|
// Note that in osu-stable subsequent presses when at track end won't return to last object.
|
||||||
// This has intentionally been changed to make it more useful.
|
// This has intentionally been changed to make it more useful.
|
||||||
double? lastObjectTime = editorBeatmap.HitObjects.LastOrDefault()?.GetEndTime();
|
if (!editorBeatmap.HitObjects.Any())
|
||||||
|
{
|
||||||
if (lastObjectTime == null || clock.CurrentTime == lastObjectTime)
|
|
||||||
clock.Seek(clock.TrackLength);
|
clock.Seek(clock.TrackLength);
|
||||||
else
|
return true;
|
||||||
clock.Seek(lastObjectTime.Value);
|
}
|
||||||
|
|
||||||
|
double lastObjectTime = editorBeatmap.GetLastObjectTime();
|
||||||
|
clock.Seek(clock.CurrentTime == lastObjectTime ? clock.TrackLength : lastObjectTime);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,20 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
slider.Current.Parse(t.Text);
|
switch (slider.Current)
|
||||||
|
{
|
||||||
|
case Bindable<int> bindableInt:
|
||||||
|
bindableInt.Value = int.Parse(t.Text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bindable<double> bindableDouble:
|
||||||
|
bindableDouble.Value = double.Parse(t.Text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
slider.Current.Parse(t.Text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -58,7 +58,20 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
slider.Current.Parse(t.Text);
|
switch (slider.Current)
|
||||||
|
{
|
||||||
|
case Bindable<int> bindableInt:
|
||||||
|
bindableInt.Value = int.Parse(t.Text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bindable<double> bindableDouble:
|
||||||
|
bindableDouble.Value = double.Parse(t.Text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
slider.Current.Parse(t.Text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
@ -13,7 +12,6 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
@ -94,7 +92,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
void keyboardSeek(int direction)
|
void keyboardSeek(int direction)
|
||||||
{
|
{
|
||||||
double target = Math.Clamp(GameplayClockContainer.CurrentTime + direction * keyboard_seek_amount, 0, GameplayState.Beatmap.HitObjects.Last().GetEndTime());
|
double target = Math.Clamp(GameplayClockContainer.CurrentTime + direction * keyboard_seek_amount, 0, GameplayState.Beatmap.GetLastObjectTime());
|
||||||
|
|
||||||
Seek(target);
|
Seek(target);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.18.0" />
|
<PackageReference Include="Realm" Version="10.18.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.1130.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.1204.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.23.1" />
|
<PackageReference Include="Sentry" Version="3.23.1" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.1130.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.1204.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<PackageReference Include="DiffPlex" Version="1.7.1" />
|
<PackageReference Include="DiffPlex" Version="1.7.1" />
|
||||||
<PackageReference Include="Humanizer" Version="2.14.1" />
|
<PackageReference Include="Humanizer" Version="2.14.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.1130.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.1204.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user