mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 16:12:54 +08:00
Merge branch 'master' into localisation-proof-of-concept
This commit is contained in:
commit
b0a113a36b
@ -1,28 +1,22 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.EmptyFreeform.Objects;
|
using osu.Game.Rulesets.EmptyFreeform.Objects;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.EmptyFreeform.Replays
|
namespace osu.Game.Rulesets.EmptyFreeform.Replays
|
||||||
{
|
{
|
||||||
public class EmptyFreeformAutoGenerator : AutoGenerator
|
public class EmptyFreeformAutoGenerator : AutoGenerator<EmptyFreeformReplayFrame>
|
||||||
{
|
{
|
||||||
protected Replay Replay;
|
|
||||||
protected List<ReplayFrame> Frames => Replay.Frames;
|
|
||||||
|
|
||||||
public new Beatmap<EmptyFreeformHitObject> Beatmap => (Beatmap<EmptyFreeformHitObject>)base.Beatmap;
|
public new Beatmap<EmptyFreeformHitObject> Beatmap => (Beatmap<EmptyFreeformHitObject>)base.Beatmap;
|
||||||
|
|
||||||
public EmptyFreeformAutoGenerator(IBeatmap beatmap)
|
public EmptyFreeformAutoGenerator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Replay Generate()
|
protected override void GenerateFrames()
|
||||||
{
|
{
|
||||||
Frames.Add(new EmptyFreeformReplayFrame());
|
Frames.Add(new EmptyFreeformReplayFrame());
|
||||||
|
|
||||||
@ -35,8 +29,6 @@ namespace osu.Game.Rulesets.EmptyFreeform.Replays
|
|||||||
// todo: add required inputs and extra frames.
|
// todo: add required inputs and extra frames.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,22 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.Pippidon.Objects;
|
using osu.Game.Rulesets.Pippidon.Objects;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Pippidon.Replays
|
namespace osu.Game.Rulesets.Pippidon.Replays
|
||||||
{
|
{
|
||||||
public class PippidonAutoGenerator : AutoGenerator
|
public class PippidonAutoGenerator : AutoGenerator<PippidonReplayFrame>
|
||||||
{
|
{
|
||||||
protected Replay Replay;
|
|
||||||
protected List<ReplayFrame> Frames => Replay.Frames;
|
|
||||||
|
|
||||||
public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap;
|
public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap;
|
||||||
|
|
||||||
public PippidonAutoGenerator(IBeatmap beatmap)
|
public PippidonAutoGenerator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Replay Generate()
|
protected override void GenerateFrames()
|
||||||
{
|
{
|
||||||
Frames.Add(new PippidonReplayFrame());
|
Frames.Add(new PippidonReplayFrame());
|
||||||
|
|
||||||
@ -34,8 +28,6 @@ namespace osu.Game.Rulesets.Pippidon.Replays
|
|||||||
Position = hitObject.Position,
|
Position = hitObject.Position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,22 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.EmptyScrolling.Objects;
|
using osu.Game.Rulesets.EmptyScrolling.Objects;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.EmptyScrolling.Replays
|
namespace osu.Game.Rulesets.EmptyScrolling.Replays
|
||||||
{
|
{
|
||||||
public class EmptyScrollingAutoGenerator : AutoGenerator
|
public class EmptyScrollingAutoGenerator : AutoGenerator<EmptyScrollingReplayFrame>
|
||||||
{
|
{
|
||||||
protected Replay Replay;
|
|
||||||
protected List<ReplayFrame> Frames => Replay.Frames;
|
|
||||||
|
|
||||||
public new Beatmap<EmptyScrollingHitObject> Beatmap => (Beatmap<EmptyScrollingHitObject>)base.Beatmap;
|
public new Beatmap<EmptyScrollingHitObject> Beatmap => (Beatmap<EmptyScrollingHitObject>)base.Beatmap;
|
||||||
|
|
||||||
public EmptyScrollingAutoGenerator(IBeatmap beatmap)
|
public EmptyScrollingAutoGenerator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Replay Generate()
|
protected override void GenerateFrames()
|
||||||
{
|
{
|
||||||
Frames.Add(new EmptyScrollingReplayFrame());
|
Frames.Add(new EmptyScrollingReplayFrame());
|
||||||
|
|
||||||
@ -34,8 +28,6 @@ namespace osu.Game.Rulesets.EmptyScrolling.Replays
|
|||||||
// todo: add required inputs and extra frames.
|
// todo: add required inputs and extra frames.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,23 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.Pippidon.Objects;
|
using osu.Game.Rulesets.Pippidon.Objects;
|
||||||
using osu.Game.Rulesets.Pippidon.UI;
|
using osu.Game.Rulesets.Pippidon.UI;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Pippidon.Replays
|
namespace osu.Game.Rulesets.Pippidon.Replays
|
||||||
{
|
{
|
||||||
public class PippidonAutoGenerator : AutoGenerator
|
public class PippidonAutoGenerator : AutoGenerator<PippidonReplayFrame>
|
||||||
{
|
{
|
||||||
protected Replay Replay;
|
|
||||||
protected List<ReplayFrame> Frames => Replay.Frames;
|
|
||||||
|
|
||||||
public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap;
|
public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap;
|
||||||
|
|
||||||
public PippidonAutoGenerator(IBeatmap beatmap)
|
public PippidonAutoGenerator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Replay Generate()
|
protected override void GenerateFrames()
|
||||||
{
|
{
|
||||||
int currentLane = 0;
|
int currentLane = 0;
|
||||||
|
|
||||||
@ -55,8 +49,6 @@ namespace osu.Game.Rulesets.Pippidon.Replays
|
|||||||
|
|
||||||
currentLane = hitObject.Lane;
|
currentLane = hitObject.Lane;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFrame(double time, PippidonAction direction)
|
private void addFrame(double time, PippidonAction direction)
|
||||||
|
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.507.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.513.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -28,10 +28,12 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
catchPlayfield.CatcherArea.MovableCatcher.CatchFruitOnPlate = false;
|
catchPlayfield.CatcherArea.MovableCatcher.CatchFruitOnPlate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
base.ApplyNormalVisibilityState(hitObject, state);
|
|
||||||
|
|
||||||
if (!(hitObject is DrawableCatchHitObject catchDrawable))
|
if (!(hitObject is DrawableCatchHitObject catchDrawable))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
var offset = hitObject.TimePreempt * fade_out_offset_multiplier;
|
var offset = hitObject.TimePreempt * fade_out_offset_multiplier;
|
||||||
var duration = offset - hitObject.TimePreempt * fade_out_duration_multiplier;
|
var duration = offset - hitObject.TimePreempt * fade_out_duration_multiplier;
|
||||||
|
|
||||||
using (drawable.BeginAbsoluteSequence(hitObject.StartTime - offset, true))
|
using (drawable.BeginAbsoluteSequence(hitObject.StartTime - offset))
|
||||||
drawable.FadeOut(duration);
|
drawable.FadeOut(duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
@ -13,26 +12,19 @@ using osu.Game.Rulesets.Replays;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Replays
|
namespace osu.Game.Rulesets.Catch.Replays
|
||||||
{
|
{
|
||||||
internal class CatchAutoGenerator : AutoGenerator
|
internal class CatchAutoGenerator : AutoGenerator<CatchReplayFrame>
|
||||||
{
|
{
|
||||||
public const double RELEASE_DELAY = 20;
|
|
||||||
|
|
||||||
public new CatchBeatmap Beatmap => (CatchBeatmap)base.Beatmap;
|
public new CatchBeatmap Beatmap => (CatchBeatmap)base.Beatmap;
|
||||||
|
|
||||||
public CatchAutoGenerator(IBeatmap beatmap)
|
public CatchAutoGenerator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Replay Replay;
|
protected override void GenerateFrames()
|
||||||
|
|
||||||
private CatchReplayFrame currentFrame;
|
|
||||||
|
|
||||||
public override Replay Generate()
|
|
||||||
{
|
{
|
||||||
if (Beatmap.HitObjects.Count == 0)
|
if (Beatmap.HitObjects.Count == 0)
|
||||||
return Replay;
|
return;
|
||||||
|
|
||||||
// todo: add support for HT DT
|
// todo: add support for HT DT
|
||||||
const double dash_speed = Catcher.BASE_SPEED;
|
const double dash_speed = Catcher.BASE_SPEED;
|
||||||
@ -119,15 +111,11 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFrame(double time, float? position = null, bool dashing = false)
|
private void addFrame(double time, float? position = null, bool dashing = false)
|
||||||
{
|
{
|
||||||
var last = currentFrame;
|
Frames.Add(new CatchReplayFrame(time, position, dashing, LastFrame));
|
||||||
currentFrame = new CatchReplayFrame(time, position, dashing, last);
|
|
||||||
Replay.Frames.Add(currentFrame);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
explosion = new LegacyRollingCounter(skin, LegacyFont.Combo)
|
explosion = new LegacyRollingCounter(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Alpha = 0.65f,
|
Alpha = 0.65f,
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Scale = new Vector2(1.5f),
|
Scale = new Vector2(1.5f),
|
||||||
},
|
},
|
||||||
counter = new LegacyRollingCounter(skin, LegacyFont.Combo)
|
counter = new LegacyRollingCounter(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddBlueprint(new HoldNoteSelectionBlueprint(drawableObject));
|
AddBlueprint(new HoldNoteSelectionBlueprint(holdNote), drawableObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -184,8 +184,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
AddAssert("head note positioned correctly", () => Precision.AlmostEquals(holdNote.ScreenSpaceDrawQuad.BottomLeft, holdNote.Head.ScreenSpaceDrawQuad.BottomLeft));
|
AddAssert("head note positioned correctly", () => Precision.AlmostEquals(holdNote.ScreenSpaceDrawQuad.BottomLeft, holdNote.Head.ScreenSpaceDrawQuad.BottomLeft));
|
||||||
AddAssert("tail note positioned correctly", () => Precision.AlmostEquals(holdNote.ScreenSpaceDrawQuad.TopLeft, holdNote.Tail.ScreenSpaceDrawQuad.BottomLeft));
|
AddAssert("tail note positioned correctly", () => Precision.AlmostEquals(holdNote.ScreenSpaceDrawQuad.TopLeft, holdNote.Tail.ScreenSpaceDrawQuad.BottomLeft));
|
||||||
|
|
||||||
AddAssert("head blueprint positioned correctly", () => this.ChildrenOfType<HoldNoteNoteSelectionBlueprint>().ElementAt(0).DrawPosition == holdNote.Head.DrawPosition);
|
AddAssert("head blueprint positioned correctly", () => this.ChildrenOfType<HoldNoteNoteOverlay>().ElementAt(0).DrawPosition == holdNote.Head.DrawPosition);
|
||||||
AddAssert("tail blueprint positioned correctly", () => this.ChildrenOfType<HoldNoteNoteSelectionBlueprint>().ElementAt(1).DrawPosition == holdNote.Tail.DrawPosition);
|
AddAssert("tail blueprint positioned correctly", () => this.ChildrenOfType<HoldNoteNoteOverlay>().ElementAt(1).DrawPosition == holdNote.Tail.DrawPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setScrollStep(ScrollingDirection direction)
|
private void setScrollStep(ScrollingDirection direction)
|
||||||
|
@ -15,7 +15,6 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK;
|
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests.Editor
|
namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||||
@ -35,7 +34,11 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPlaceBeforeCurrentTimeDownwards()
|
public void TestPlaceBeforeCurrentTimeDownwards()
|
||||||
{
|
{
|
||||||
AddStep("move mouse before current time", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Single().ScreenSpaceDrawQuad.BottomLeft - new Vector2(0, 10)));
|
AddStep("move mouse before current time", () =>
|
||||||
|
{
|
||||||
|
var column = this.ChildrenOfType<Column>().Single();
|
||||||
|
InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(-100));
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
|
||||||
@ -45,7 +48,11 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPlaceAfterCurrentTimeDownwards()
|
public void TestPlaceAfterCurrentTimeDownwards()
|
||||||
{
|
{
|
||||||
AddStep("move mouse after current time", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Single()));
|
AddStep("move mouse after current time", () =>
|
||||||
|
{
|
||||||
|
var column = this.ChildrenOfType<Column>().Single();
|
||||||
|
InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(100));
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
Child = drawableObject = new DrawableNote(note)
|
Child = drawableObject = new DrawableNote(note)
|
||||||
};
|
};
|
||||||
|
|
||||||
AddBlueprint(new NoteSelectionBlueprint(drawableObject));
|
AddBlueprint(new NoteSelectionBlueprint(note), drawableObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 0), _ => new DefaultColumnBackground())
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 1), _ => new DefaultColumnBackground())
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, 0), _ => new DefaultKeyArea())
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, 1), _ => new DefaultKeyArea())
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
// 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.Framework.Graphics;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneDrawableManiaHitObject : OsuTestScene
|
||||||
|
{
|
||||||
|
private readonly ManualClock clock = new ManualClock();
|
||||||
|
|
||||||
|
private Column column;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
|
{
|
||||||
|
Child = new ScrollingTestContainer(ScrollingDirection.Down)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
TimeRange = 2000,
|
||||||
|
Clock = new FramedClock(clock),
|
||||||
|
Child = column = new Column(0)
|
||||||
|
{
|
||||||
|
Action = { Value = ManiaAction.Key1 },
|
||||||
|
Height = 0.85f,
|
||||||
|
AccentColour = Color4.Gray
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHoldNoteHeadVisibility()
|
||||||
|
{
|
||||||
|
DrawableHoldNote note = null;
|
||||||
|
AddStep("Add hold note", () =>
|
||||||
|
{
|
||||||
|
var h = new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = 0,
|
||||||
|
Duration = 1000
|
||||||
|
};
|
||||||
|
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
column.Add(note = new DrawableHoldNote(h));
|
||||||
|
});
|
||||||
|
AddStep("Hold key", () =>
|
||||||
|
{
|
||||||
|
clock.CurrentTime = 0;
|
||||||
|
note.OnPressed(ManiaAction.Key1);
|
||||||
|
});
|
||||||
|
AddStep("progress time", () => clock.CurrentTime = 500);
|
||||||
|
AddAssert("head is visible", () => note.Head.Alpha == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,13 +5,11 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
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.Replays;
|
using osu.Game.Replays;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -414,14 +412,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
|
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
|
||||||
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
|
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
|
||||||
|
|
||||||
AddUntilStep("wait for head", () => currentPlayer.GameplayClockContainer.GameplayClock.CurrentTime >= time_head);
|
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor?.HasCompleted.Value == true);
|
||||||
AddAssert("head is visible",
|
|
||||||
() => currentPlayer.ChildrenOfType<DrawableHoldNote>()
|
|
||||||
.Single(note => note.HitObject == beatmap.HitObjects[0])
|
|
||||||
.Head
|
|
||||||
.Alpha == 1);
|
|
||||||
|
|
||||||
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScoreAccessibleReplayPlayer : ReplayPlayer
|
private class ScoreAccessibleReplayPlayer : ReplayPlayer
|
||||||
|
@ -2,34 +2,35 @@
|
|||||||
// 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 osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public class HoldNoteNoteSelectionBlueprint : ManiaSelectionBlueprint
|
public class HoldNoteNoteOverlay : CompositeDrawable
|
||||||
{
|
{
|
||||||
protected new DrawableHoldNote DrawableObject => (DrawableHoldNote)base.DrawableObject;
|
private readonly HoldNoteSelectionBlueprint holdNoteBlueprint;
|
||||||
|
|
||||||
private readonly HoldNotePosition position;
|
private readonly HoldNotePosition position;
|
||||||
|
|
||||||
public HoldNoteNoteSelectionBlueprint(DrawableHoldNote holdNote, HoldNotePosition position)
|
public HoldNoteNoteOverlay(HoldNoteSelectionBlueprint holdNoteBlueprint, HoldNotePosition position)
|
||||||
: base(holdNote)
|
|
||||||
{
|
{
|
||||||
|
this.holdNoteBlueprint = holdNoteBlueprint;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
InternalChild = new EditNotePiece { RelativeSizeAxes = Axes.X };
|
|
||||||
|
|
||||||
Select();
|
InternalChild = new EditNotePiece { RelativeSizeAxes = Axes.X };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
|
var drawableObject = holdNoteBlueprint.DrawableObject;
|
||||||
|
|
||||||
// Todo: This shouldn't exist, mania should not reference the drawable hitobject directly.
|
// Todo: This shouldn't exist, mania should not reference the drawable hitobject directly.
|
||||||
if (DrawableObject.IsLoaded)
|
if (drawableObject.IsLoaded)
|
||||||
{
|
{
|
||||||
DrawableNote note = position == HoldNotePosition.Start ? (DrawableNote)DrawableObject.Head : DrawableObject.Tail;
|
DrawableNote note = position == HoldNotePosition.Start ? (DrawableNote)drawableObject.Head : drawableObject.Tail;
|
||||||
|
|
||||||
Anchor = note.Anchor;
|
Anchor = note.Anchor;
|
||||||
Origin = note.Origin;
|
Origin = note.Origin;
|
||||||
@ -38,8 +39,5 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
Position = note.DrawPosition;
|
Position = note.DrawPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo: This is temporary, since the note masks don't do anything special yet. In the future they will handle input.
|
|
||||||
public override bool HandlePositionalInput => false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,13 +8,14 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint
|
public class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint<HoldNote>
|
||||||
{
|
{
|
||||||
public new DrawableHoldNote DrawableObject => (DrawableHoldNote)base.DrawableObject;
|
public new DrawableHoldNote DrawableObject => (DrawableHoldNote)base.DrawableObject;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; }
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
public HoldNoteSelectionBlueprint(DrawableHoldNote hold)
|
public HoldNoteSelectionBlueprint(HoldNote hold)
|
||||||
: base(hold)
|
: base(hold)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -32,16 +33,11 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
private void load(IScrollingInfo scrollingInfo)
|
private void load(IScrollingInfo scrollingInfo)
|
||||||
{
|
{
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.Start),
|
new HoldNoteNoteOverlay(this, HoldNotePosition.Start),
|
||||||
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.End),
|
new HoldNoteNoteOverlay(this, HoldNotePosition.End),
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
@ -4,22 +4,23 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public abstract class ManiaSelectionBlueprint : OverlaySelectionBlueprint
|
public abstract class ManiaSelectionBlueprint<T> : HitObjectSelectionBlueprint<T>
|
||||||
|
where T : ManiaHitObject
|
||||||
{
|
{
|
||||||
public new DrawableManiaHitObject DrawableObject => (DrawableManiaHitObject)base.DrawableObject;
|
public new DrawableManiaHitObject DrawableObject => (DrawableManiaHitObject)base.DrawableObject;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IScrollingInfo scrollingInfo { get; set; }
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
|
|
||||||
protected ManiaSelectionBlueprint(DrawableHitObject drawableObject)
|
protected ManiaSelectionBlueprint(T hitObject)
|
||||||
: base(drawableObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.None;
|
RelativeSizeAxes = Axes.None;
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public class NoteSelectionBlueprint : ManiaSelectionBlueprint
|
public class NoteSelectionBlueprint : ManiaSelectionBlueprint<Note>
|
||||||
{
|
{
|
||||||
public NoteSelectionBlueprint(DrawableNote note)
|
public NoteSelectionBlueprint(Note note)
|
||||||
: base(note)
|
: base(note)
|
||||||
{
|
{
|
||||||
AddInternal(new EditNotePiece { RelativeSizeAxes = Axes.X });
|
AddInternal(new EditNotePiece { RelativeSizeAxes = Axes.X });
|
||||||
|
@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
foreach (var line in grid.Objects.OfType<DrawableGridLine>())
|
foreach (var line in grid.Objects.OfType<DrawableGridLine>())
|
||||||
availableLines.Push(line);
|
availableLines.Push(line);
|
||||||
|
|
||||||
grid.Clear(false);
|
grid.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectionTimeRange == null)
|
if (selectionTimeRange == null)
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit
|
namespace osu.Game.Rulesets.Mania.Edit
|
||||||
@ -17,18 +16,18 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
|
public override HitObjectSelectionBlueprint CreateHitObjectBlueprintFor(HitObject hitObject)
|
||||||
{
|
{
|
||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
{
|
{
|
||||||
case DrawableNote note:
|
case Note note:
|
||||||
return new NoteSelectionBlueprint(note);
|
return new NoteSelectionBlueprint(note);
|
||||||
|
|
||||||
case DrawableHoldNote holdNote:
|
case HoldNote holdNote:
|
||||||
return new HoldNoteSelectionBlueprint(holdNote);
|
return new HoldNoteSelectionBlueprint(holdNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.CreateBlueprintFor(hitObject);
|
return base.CreateHitObjectBlueprintFor(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new ManiaSelectionHandler();
|
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new ManiaSelectionHandler();
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -23,8 +22,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
|
|
||||||
public override bool HandleMovement(MoveSelectionEvent<HitObject> moveEvent)
|
public override bool HandleMovement(MoveSelectionEvent<HitObject> moveEvent)
|
||||||
{
|
{
|
||||||
var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint;
|
var hitObjectBlueprint = (HitObjectSelectionBlueprint)moveEvent.Blueprint;
|
||||||
int lastColumn = maniaBlueprint.DrawableObject.HitObject.Column;
|
int lastColumn = ((ManiaHitObject)hitObjectBlueprint.Item).Column;
|
||||||
|
|
||||||
performColumnMovement(lastColumn, moveEvent);
|
performColumnMovement(lastColumn, moveEvent);
|
||||||
|
|
||||||
@ -59,8 +58,9 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
|
|
||||||
EditorBeatmap.PerformOnSelection(h =>
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
{
|
{
|
||||||
if (h is ManiaHitObject maniaObj)
|
maniaPlayfield.Remove(h);
|
||||||
maniaObj.Column += columnDelta;
|
((ManiaHitObject)h).Column += columnDelta;
|
||||||
|
maniaPlayfield.Add(h);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
|
||||||
|
|
||||||
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new DrainingHealthProcessor(drainStartTime, 0.2);
|
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new DrainingHealthProcessor(drainStartTime, 0.5);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
|
@ -9,12 +9,6 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
{
|
{
|
||||||
public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents>
|
public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The intended <see cref="Column"/> index for this component.
|
|
||||||
/// May be null if the component does not exist in a <see cref="Column"/>.
|
|
||||||
/// </summary>
|
|
||||||
public readonly int? TargetColumn;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The intended <see cref="StageDefinition"/> for this component.
|
/// The intended <see cref="StageDefinition"/> for this component.
|
||||||
/// May be null if the component is not a direct member of a <see cref="Stage"/>.
|
/// May be null if the component is not a direct member of a <see cref="Stage"/>.
|
||||||
@ -25,12 +19,10 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
/// Creates a new <see cref="ManiaSkinComponent"/>.
|
/// Creates a new <see cref="ManiaSkinComponent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="component">The component.</param>
|
/// <param name="component">The component.</param>
|
||||||
/// <param name="targetColumn">The intended <see cref="Column"/> index for this component. May be null if the component does not exist in a <see cref="Column"/>.</param>
|
|
||||||
/// <param name="stageDefinition">The intended <see cref="StageDefinition"/> for this component. May be null if the component is not a direct member of a <see cref="Stage"/>.</param>
|
/// <param name="stageDefinition">The intended <see cref="StageDefinition"/> for this component. May be null if the component is not a direct member of a <see cref="Stage"/>.</param>
|
||||||
public ManiaSkinComponent(ManiaSkinComponents component, int? targetColumn = null, StageDefinition? stageDefinition = null)
|
public ManiaSkinComponent(ManiaSkinComponents component, StageDefinition? stageDefinition = null)
|
||||||
: base(component)
|
: base(component)
|
||||||
{
|
{
|
||||||
TargetColumn = targetColumn;
|
|
||||||
StageDefinition = stageDefinition;
|
StageDefinition = stageDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
@ -39,5 +40,13 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -12,6 +13,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -29,21 +31,21 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
public DrawableHoldNoteHead Head => headContainer.Child;
|
public DrawableHoldNoteHead Head => headContainer.Child;
|
||||||
public DrawableHoldNoteTail Tail => tailContainer.Child;
|
public DrawableHoldNoteTail Tail => tailContainer.Child;
|
||||||
|
|
||||||
private readonly Container<DrawableHoldNoteHead> headContainer;
|
private Container<DrawableHoldNoteHead> headContainer;
|
||||||
private readonly Container<DrawableHoldNoteTail> tailContainer;
|
private Container<DrawableHoldNoteTail> tailContainer;
|
||||||
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
private Container<DrawableHoldNoteTick> tickContainer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the size of the hold note covering the whole head/tail bounds. The size of this container changes as the hold note is being pressed.
|
/// Contains the size of the hold note covering the whole head/tail bounds. The size of this container changes as the hold note is being pressed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Container sizingContainer;
|
private Container sizingContainer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the contents of the hold note that should be masked as the hold note is being pressed. Follows changes in the size of <see cref="sizingContainer"/>.
|
/// Contains the contents of the hold note that should be masked as the hold note is being pressed. Follows changes in the size of <see cref="sizingContainer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Container maskingContainer;
|
private Container maskingContainer;
|
||||||
|
|
||||||
private readonly SkinnableDrawable bodyPiece;
|
private SkinnableDrawable bodyPiece;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
|
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
|
||||||
@ -60,11 +62,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double? releaseTime;
|
private double? releaseTime;
|
||||||
|
|
||||||
|
public DrawableHoldNote()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public DrawableHoldNote(HoldNote hitObject)
|
public DrawableHoldNote(HoldNote hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
Container maskedContents;
|
Container maskedContents;
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
@ -86,7 +96,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both }
|
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody, hitObject.Column), _ => new DefaultBodyPiece
|
bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
})
|
})
|
||||||
@ -105,6 +115,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
base.OnApply();
|
||||||
|
|
||||||
|
sizingContainer.Size = Vector2.One;
|
||||||
|
HoldStartTime = null;
|
||||||
|
HoldBrokenTime = null;
|
||||||
|
releaseTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
base.AddNestedHitObject(hitObject);
|
base.AddNestedHitObject(hitObject);
|
||||||
@ -128,37 +148,23 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
protected override void ClearNestedHitObjects()
|
protected override void ClearNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.ClearNestedHitObjects();
|
base.ClearNestedHitObjects();
|
||||||
headContainer.Clear();
|
headContainer.Clear(false);
|
||||||
tailContainer.Clear();
|
tailContainer.Clear(false);
|
||||||
tickContainer.Clear();
|
tickContainer.Clear(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
||||||
{
|
{
|
||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
{
|
{
|
||||||
case TailNote _:
|
case TailNote tail:
|
||||||
return new DrawableHoldNoteTail(this)
|
return new DrawableHoldNoteTail(tail);
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
AccentColour = { BindTarget = AccentColour }
|
|
||||||
};
|
|
||||||
|
|
||||||
case Note _:
|
case HeadNote head:
|
||||||
return new DrawableHoldNoteHead(this)
|
return new DrawableHoldNoteHead(head);
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
AccentColour = { BindTarget = AccentColour }
|
|
||||||
};
|
|
||||||
|
|
||||||
case HoldNoteTick tick:
|
case HoldNoteTick tick:
|
||||||
return new DrawableHoldNoteTick(tick)
|
return new DrawableHoldNoteTick(tick);
|
||||||
{
|
|
||||||
HoldStartTime = () => HoldStartTime,
|
|
||||||
AccentColour = { BindTarget = AccentColour }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.CreateNestedHitObject(hitObject);
|
return base.CreateNestedHitObject(hitObject);
|
||||||
|
@ -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 osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
@ -12,11 +13,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteHead;
|
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteHead;
|
||||||
|
|
||||||
public DrawableHoldNoteHead(DrawableHoldNote holdNote)
|
public DrawableHoldNoteHead()
|
||||||
: base(holdNote.HitObject.Head)
|
: this(null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DrawableHoldNoteHead(HeadNote headNote)
|
||||||
|
: base(headNote)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre;
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateResult() => base.UpdateResult(true);
|
public void UpdateResult() => base.UpdateResult(true);
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
|
@ -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.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
@ -20,12 +21,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteTail;
|
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteTail;
|
||||||
|
|
||||||
private readonly DrawableHoldNote holdNote;
|
protected DrawableHoldNote HoldNote => (DrawableHoldNote)ParentHitObject;
|
||||||
|
|
||||||
public DrawableHoldNoteTail(DrawableHoldNote holdNote)
|
public DrawableHoldNoteTail()
|
||||||
: base(holdNote.HitObject.Tail)
|
: this(null)
|
||||||
{
|
{
|
||||||
this.holdNote = holdNote;
|
}
|
||||||
|
|
||||||
|
public DrawableHoldNoteTail(TailNote tailNote)
|
||||||
|
: base(tailNote)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre;
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateResult() => base.UpdateResult(true);
|
public void UpdateResult() => base.UpdateResult(true);
|
||||||
@ -54,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
ApplyResult(r =>
|
ApplyResult(r =>
|
||||||
{
|
{
|
||||||
// If the head wasn't hit or the hold note was broken, cap the max score to Meh.
|
// If the head wasn't hit or the hold note was broken, cap the max score to Meh.
|
||||||
if (result > HitResult.Meh && (!holdNote.Head.IsHit || holdNote.HoldBrokenTime != null))
|
if (result > HitResult.Meh && (!HoldNote.Head.IsHit || HoldNote.HoldBrokenTime != null))
|
||||||
result = HitResult.Meh;
|
result = HitResult.Meh;
|
||||||
|
|
||||||
r.Type = result;
|
r.Type = result;
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
// 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 osuTK;
|
using System.Diagnostics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -19,22 +20,28 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// References the time at which the user started holding the hold note.
|
/// References the time at which the user started holding the hold note.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<double?> HoldStartTime;
|
private Func<double?> holdStartTime;
|
||||||
|
|
||||||
|
private Container glowContainer;
|
||||||
|
|
||||||
|
public DrawableHoldNoteTick()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public DrawableHoldNoteTick(HoldNoteTick hitObject)
|
public DrawableHoldNoteTick(HoldNoteTick hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
Container glowContainer;
|
|
||||||
|
|
||||||
Anchor = Anchor.TopCentre;
|
Anchor = Anchor.TopCentre;
|
||||||
Origin = Anchor.TopCentre;
|
Origin = Anchor.TopCentre;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Size = new Vector2(1);
|
}
|
||||||
|
|
||||||
AddRangeInternal(new[]
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
glowContainer = new CircularContainer
|
AddInternal(glowContainer = new CircularContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
@ -49,8 +56,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
AlwaysPresent = true
|
AlwaysPresent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
AccentColour.BindValueChanged(colour =>
|
AccentColour.BindValueChanged(colour =>
|
||||||
{
|
{
|
||||||
@ -64,12 +75,29 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
base.OnApply();
|
||||||
|
|
||||||
|
Debug.Assert(ParentHitObject != null);
|
||||||
|
|
||||||
|
var holdNote = (DrawableHoldNote)ParentHitObject;
|
||||||
|
holdStartTime = () => holdNote.HoldStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
base.OnFree();
|
||||||
|
|
||||||
|
holdStartTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (Time.Current < HitObject.StartTime)
|
if (Time.Current < HitObject.StartTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var startTime = HoldStartTime?.Invoke();
|
var startTime = holdStartTime?.Invoke();
|
||||||
|
|
||||||
if (startTime == null || startTime > HitObject.StartTime)
|
if (startTime == null || startTime > HitObject.StartTime)
|
||||||
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
|
@ -6,6 +6,7 @@ using JetBrains.Annotations;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
@ -24,6 +25,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private ManiaPlayfield playfield { get; set; }
|
private ManiaPlayfield playfield { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the samples that are played by this object during gameplay.
|
||||||
|
/// </summary>
|
||||||
|
public ISampleInfo[] GetGameplaySamples() => Samples.Samples;
|
||||||
|
|
||||||
protected override float SamplePlaybackPosition
|
protected override float SamplePlaybackPosition
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -44,6 +50,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
protected DrawableManiaHitObject(ManiaHitObject hitObject)
|
protected DrawableManiaHitObject(ManiaHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
@ -53,9 +60,31 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
Action.BindTo(action);
|
Action.BindTo(action);
|
||||||
|
|
||||||
Direction.BindTo(scrollingInfo.Direction);
|
Direction.BindTo(scrollingInfo.Direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
Direction.BindValueChanged(OnDirectionChanged, true);
|
Direction.BindValueChanged(OnDirectionChanged, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
base.OnApply();
|
||||||
|
|
||||||
|
if (ParentHitObject != null)
|
||||||
|
AccentColour.BindTo(ParentHitObject.AccentColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
base.OnFree();
|
||||||
|
|
||||||
|
if (ParentHitObject != null)
|
||||||
|
AccentColour.UnbindFrom(ParentHitObject.AccentColour);
|
||||||
|
}
|
||||||
|
|
||||||
private double computedLifetimeStart;
|
private double computedLifetimeStart;
|
||||||
|
|
||||||
public override double LifetimeStart
|
public override double LifetimeStart
|
||||||
@ -141,12 +170,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
|
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
|
||||||
where TObject : ManiaHitObject
|
where TObject : ManiaHitObject
|
||||||
{
|
{
|
||||||
public new readonly TObject HitObject;
|
public new TObject HitObject => (TObject)base.HitObject;
|
||||||
|
|
||||||
protected DrawableManiaHitObject(TObject hitObject)
|
protected DrawableManiaHitObject(TObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,31 +33,37 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected virtual ManiaSkinComponents Component => ManiaSkinComponents.Note;
|
protected virtual ManiaSkinComponents Component => ManiaSkinComponents.Note;
|
||||||
|
|
||||||
private readonly Drawable headPiece;
|
private Drawable headPiece;
|
||||||
|
|
||||||
|
public DrawableNote()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public DrawableNote(Note hitObject)
|
public DrawableNote(Note hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinComponent(Component, hitObject.Column), _ => new DefaultNotePiece())
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(ManiaRulesetConfigManager rulesetConfig)
|
private void load(ManiaRulesetConfigManager rulesetConfig)
|
||||||
{
|
{
|
||||||
rulesetConfig?.BindWith(ManiaRulesetSetting.TimingBasedNoteColouring, configTimingBasedNoteColouring);
|
rulesetConfig?.BindWith(ManiaRulesetSetting.TimingBasedNoteColouring, configTimingBasedNoteColouring);
|
||||||
|
|
||||||
|
AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinComponent(Component), _ => new DefaultNotePiece())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
HitObject.StartTimeBindable.BindValueChanged(_ => updateSnapColour());
|
base.LoadComplete();
|
||||||
configTimingBasedNoteColouring.BindValueChanged(_ => updateSnapColour(), true);
|
|
||||||
|
configTimingBasedNoteColouring.BindValueChanged(_ => updateSnapColour());
|
||||||
|
StartTimeBindable.BindValueChanged(_ => updateSnapColour(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
||||||
@ -102,7 +108,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
private void updateSnapColour()
|
private void updateSnapColour()
|
||||||
{
|
{
|
||||||
if (beatmap == null) return;
|
if (beatmap == null || HitObject == null) return;
|
||||||
|
|
||||||
int snapDivisor = beatmap.ControlPointInfo.GetClosestBeatDivisor(HitObject.StartTime);
|
int snapDivisor = beatmap.ControlPointInfo.GetClosestBeatDivisor(HitObject.StartTime);
|
||||||
|
|
||||||
|
9
osu.Game.Rulesets.Mania/Objects/HeadNote.cs
Normal file
9
osu.Game.Rulesets.Mania/Objects/HeadNote.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
{
|
||||||
|
public class HeadNote : Note
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The head note of the hold.
|
/// The head note of the hold.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Note Head { get; private set; }
|
public HeadNote Head { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tail note of the hold.
|
/// The tail note of the hold.
|
||||||
@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
|
|
||||||
createTicks(cancellationToken);
|
createTicks(cancellationToken);
|
||||||
|
|
||||||
AddNested(Head = new Note
|
AddNested(Head = new HeadNote
|
||||||
{
|
{
|
||||||
StartTime = StartTime,
|
StartTime = StartTime,
|
||||||
Column = Column,
|
Column = Column,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -11,7 +10,7 @@ using osu.Game.Rulesets.Replays;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Replays
|
namespace osu.Game.Rulesets.Mania.Replays
|
||||||
{
|
{
|
||||||
internal class ManiaAutoGenerator : AutoGenerator
|
internal class ManiaAutoGenerator : AutoGenerator<ManiaReplayFrame>
|
||||||
{
|
{
|
||||||
public const double RELEASE_DELAY = 20;
|
public const double RELEASE_DELAY = 20;
|
||||||
|
|
||||||
@ -22,8 +21,6 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
public ManiaAutoGenerator(ManiaBeatmap beatmap)
|
public ManiaAutoGenerator(ManiaBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
|
|
||||||
columnActions = new ManiaAction[Beatmap.TotalColumns];
|
columnActions = new ManiaAction[Beatmap.TotalColumns];
|
||||||
|
|
||||||
var normalAction = ManiaAction.Key1;
|
var normalAction = ManiaAction.Key1;
|
||||||
@ -43,12 +40,10 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Replay Replay;
|
protected override void GenerateFrames()
|
||||||
|
|
||||||
public override Replay Generate()
|
|
||||||
{
|
{
|
||||||
if (Beatmap.HitObjects.Count == 0)
|
if (Beatmap.HitObjects.Count == 0)
|
||||||
return Replay;
|
return;
|
||||||
|
|
||||||
var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time);
|
var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time);
|
||||||
|
|
||||||
@ -70,10 +65,8 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray()));
|
Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IActionPoint> generateActionPoints()
|
private IEnumerable<IActionPoint> generateActionPoints()
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
@ -27,6 +28,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public const float COLUMN_WIDTH = 80;
|
public const float COLUMN_WIDTH = 80;
|
||||||
public const float SPECIAL_COLUMN_WIDTH = 70;
|
public const float SPECIAL_COLUMN_WIDTH = 70;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For hitsounds played by this <see cref="Column"/> (i.e. not as a result of hitting a hitobject),
|
||||||
|
/// a certain number of samples are allowed to be played concurrently so that it feels better when spam-pressing the key.
|
||||||
|
/// </summary>
|
||||||
|
private const int max_concurrent_hitsounds = OsuGameBase.SAMPLE_CONCURRENCY;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The index of this column as part of the whole playfield.
|
/// The index of this column as part of the whole playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -38,6 +45,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
internal readonly Container TopLevelContainer;
|
internal readonly Container TopLevelContainer;
|
||||||
private readonly DrawablePool<PoolableHitExplosion> hitExplosionPool;
|
private readonly DrawablePool<PoolableHitExplosion> hitExplosionPool;
|
||||||
private readonly OrderedHitPolicy hitPolicy;
|
private readonly OrderedHitPolicy hitPolicy;
|
||||||
|
private readonly Container<SkinnableSound> hitSounds;
|
||||||
|
|
||||||
public Container UnderlayElements => HitObjectArea.UnderlayElements;
|
public Container UnderlayElements => HitObjectArea.UnderlayElements;
|
||||||
|
|
||||||
@ -48,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
Width = COLUMN_WIDTH;
|
Width = COLUMN_WIDTH;
|
||||||
|
|
||||||
Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, Index), _ => new DefaultColumnBackground())
|
Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
};
|
};
|
||||||
@ -59,17 +67,36 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
||||||
background.CreateProxy(),
|
background.CreateProxy(),
|
||||||
HitObjectArea = new ColumnHitObjectArea(Index, HitObjectContainer) { RelativeSizeAxes = Axes.Both },
|
HitObjectArea = new ColumnHitObjectArea(Index, HitObjectContainer) { RelativeSizeAxes = Axes.Both },
|
||||||
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, Index), _ => new DefaultKeyArea())
|
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
background,
|
background,
|
||||||
|
hitSounds = new Container<SkinnableSound>
|
||||||
|
{
|
||||||
|
Name = "Column samples pool",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new SkinnableSound()).ToArray()
|
||||||
|
},
|
||||||
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||||
};
|
};
|
||||||
|
|
||||||
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
||||||
|
|
||||||
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
|
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
|
||||||
|
|
||||||
|
RegisterPool<Note, DrawableNote>(10, 50);
|
||||||
|
RegisterPool<HoldNote, DrawableHoldNote>(10, 50);
|
||||||
|
RegisterPool<HeadNote, DrawableHoldNoteHead>(10, 50);
|
||||||
|
RegisterPool<TailNote, DrawableHoldNoteTail>(10, 50);
|
||||||
|
RegisterPool<HoldNoteTick, DrawableHoldNoteTick>(50, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
NewResult += OnNewResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColumnType ColumnType { get; set; }
|
public ColumnType ColumnType { get; set; }
|
||||||
@ -85,28 +112,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
return dependencies;
|
return dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObject)
|
||||||
/// Adds a DrawableHitObject to this Playfield.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The DrawableHitObject to add.</param>
|
|
||||||
public override void Add(DrawableHitObject hitObject)
|
|
||||||
{
|
{
|
||||||
hitObject.AccentColour.Value = AccentColour;
|
base.OnNewDrawableHitObject(drawableHitObject);
|
||||||
hitObject.OnNewResult += OnNewResult;
|
|
||||||
|
|
||||||
DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)hitObject;
|
DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)drawableHitObject;
|
||||||
|
|
||||||
|
maniaObject.AccentColour.Value = AccentColour;
|
||||||
maniaObject.CheckHittable = hitPolicy.IsHittable;
|
maniaObject.CheckHittable = hitPolicy.IsHittable;
|
||||||
|
|
||||||
base.Add(hitObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Remove(DrawableHitObject h)
|
|
||||||
{
|
|
||||||
if (!base.Remove(h))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
h.OnNewResult -= OnNewResult;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
@ -120,6 +133,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result)));
|
HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int nextHitSoundIndex;
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (action != Action.Value)
|
if (action != Action.Value)
|
||||||
@ -131,7 +146,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
HitObjectContainer.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ??
|
HitObjectContainer.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ??
|
||||||
HitObjectContainer.Objects.LastOrDefault();
|
HitObjectContainer.Objects.LastOrDefault();
|
||||||
|
|
||||||
nextObject?.PlaySamples();
|
if (nextObject is DrawableManiaHitObject maniaObject)
|
||||||
|
{
|
||||||
|
var hitSound = hitSounds[nextHitSoundIndex];
|
||||||
|
|
||||||
|
hitSound.Samples = maniaObject.GetGameplaySamples();
|
||||||
|
hitSound.Play();
|
||||||
|
|
||||||
|
nextHitSoundIndex = (nextHitSoundIndex + 1) % max_concurrent_hitsounds;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Depth = 2,
|
Depth = 2,
|
||||||
},
|
},
|
||||||
hitTarget = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitTarget, columnIndex), _ => new DefaultHitTarget())
|
hitTarget = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitTarget), _ => new DefaultHitTarget())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Depth = 1
|
Depth = 1
|
||||||
|
@ -18,7 +18,6 @@ using osu.Game.Replays;
|
|||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -134,20 +133,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
||||||
|
|
||||||
public override DrawableHitObject<ManiaHitObject> CreateDrawableRepresentation(ManiaHitObject h)
|
public override DrawableHitObject<ManiaHitObject> CreateDrawableRepresentation(ManiaHitObject h) => null;
|
||||||
{
|
|
||||||
switch (h)
|
|
||||||
{
|
|
||||||
case HoldNote holdNote:
|
|
||||||
return new DrawableHoldNote(holdNote);
|
|
||||||
|
|
||||||
case Note note:
|
|
||||||
return new DrawableNote(note);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -56,6 +57,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Add(HitObject hitObject) => getStageByColumn(((ManiaHitObject)hitObject).Column).Add(hitObject);
|
||||||
|
|
||||||
|
public override bool Remove(HitObject hitObject) => getStageByColumn(((ManiaHitObject)hitObject).Column).Remove(hitObject);
|
||||||
|
|
||||||
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
|
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
|
||||||
|
|
||||||
public override bool Remove(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Remove(h);
|
public override bool Remove(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Remove(h);
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, column.Index), _ => new DefaultHitExplosion())
|
InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion), _ => new DefaultHitExplosion())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.UI.Components;
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -132,33 +133,19 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
var maniaObject = (ManiaHitObject)h.HitObject;
|
base.LoadComplete();
|
||||||
|
NewResult += OnNewResult;
|
||||||
int columnIndex = -1;
|
|
||||||
|
|
||||||
maniaObject.ColumnBindable.BindValueChanged(_ =>
|
|
||||||
{
|
|
||||||
if (columnIndex != -1)
|
|
||||||
Columns.ElementAt(columnIndex).Remove(h);
|
|
||||||
|
|
||||||
columnIndex = maniaObject.Column - firstColumnIndex;
|
|
||||||
Columns.ElementAt(columnIndex).Add(h);
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
h.OnNewResult += OnNewResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Remove(DrawableHitObject h)
|
public override void Add(HitObject hitObject) => Columns.ElementAt(((ManiaHitObject)hitObject).Column - firstColumnIndex).Add(hitObject);
|
||||||
{
|
|
||||||
var maniaObject = (ManiaHitObject)h.HitObject;
|
|
||||||
int columnIndex = maniaObject.Column - firstColumnIndex;
|
|
||||||
Columns.ElementAt(columnIndex).Remove(h);
|
|
||||||
|
|
||||||
h.OnNewResult -= OnNewResult;
|
public override bool Remove(HitObject hitObject) => Columns.ElementAt(((ManiaHitObject)hitObject).Column - firstColumnIndex).Remove(hitObject);
|
||||||
return true;
|
|
||||||
}
|
public override void Add(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column - firstColumnIndex).Add(h);
|
||||||
|
|
||||||
|
public override bool Remove(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column - firstColumnIndex).Remove(h);
|
||||||
|
|
||||||
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
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;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Checks;
|
using osu.Game.Rulesets.Osu.Edit.Checks;
|
||||||
@ -224,12 +225,14 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
|
|
||||||
private void assertOk(IBeatmap beatmap)
|
private void assertOk(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(beatmap, new TestWorkingBeatmap(beatmap)), Is.Empty);
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertOffscreenCircle(IBeatmap beatmap)
|
private void assertOffscreenCircle(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenCircle);
|
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenCircle);
|
||||||
@ -237,7 +240,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
|
|
||||||
private void assertOffscreenSlider(IBeatmap beatmap)
|
private void assertOffscreenSlider(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenSlider);
|
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenSlider);
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
|
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
|
||||||
|
|
||||||
Add(drawableObject = new DrawableHitCircle(hitCircle));
|
Add(drawableObject = new DrawableHitCircle(hitCircle));
|
||||||
AddBlueprint(blueprint = new TestBlueprint(drawableObject));
|
AddBlueprint(blueprint = new TestBlueprint(hitCircle), drawableObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -63,8 +63,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
{
|
{
|
||||||
public new HitCirclePiece CirclePiece => base.CirclePiece;
|
public new HitCirclePiece CirclePiece => base.CirclePiece;
|
||||||
|
|
||||||
public TestBlueprint(DrawableHitCircle drawableCircle)
|
public TestBlueprint(HitCircle circle)
|
||||||
: base(drawableCircle)
|
: base(circle)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
|
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
|
||||||
|
|
||||||
Add(drawableObject = new DrawableSlider(slider));
|
Add(drawableObject = new DrawableSlider(slider));
|
||||||
AddBlueprint(new TestSliderBlueprint(drawableObject));
|
AddBlueprint(new TestSliderBlueprint(slider), drawableObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -150,23 +150,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
private class TestSliderBlueprint : SliderSelectionBlueprint
|
private class TestSliderBlueprint : SliderSelectionBlueprint
|
||||||
{
|
{
|
||||||
public new SliderBodyPiece BodyPiece => base.BodyPiece;
|
public new SliderBodyPiece BodyPiece => base.BodyPiece;
|
||||||
public new TestSliderCircleBlueprint HeadBlueprint => (TestSliderCircleBlueprint)base.HeadBlueprint;
|
public new TestSliderCircleOverlay HeadOverlay => (TestSliderCircleOverlay)base.HeadOverlay;
|
||||||
public new TestSliderCircleBlueprint TailBlueprint => (TestSliderCircleBlueprint)base.TailBlueprint;
|
public new TestSliderCircleOverlay TailOverlay => (TestSliderCircleOverlay)base.TailOverlay;
|
||||||
public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser;
|
public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser;
|
||||||
|
|
||||||
public TestSliderBlueprint(DrawableSlider slider)
|
public TestSliderBlueprint(Slider slider)
|
||||||
: base(slider)
|
: base(slider)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new TestSliderCircleBlueprint(slider, position);
|
protected override SliderCircleOverlay CreateCircleOverlay(Slider slider, SliderPosition position) => new TestSliderCircleOverlay(slider, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestSliderCircleBlueprint : SliderCircleSelectionBlueprint
|
private class TestSliderCircleOverlay : SliderCircleOverlay
|
||||||
{
|
{
|
||||||
public new HitCirclePiece CirclePiece => base.CirclePiece;
|
public new HitCirclePiece CirclePiece => base.CirclePiece;
|
||||||
|
|
||||||
public TestSliderCircleBlueprint(DrawableSlider slider, SliderPosition position)
|
public TestSliderCircleOverlay(Slider slider, SliderPosition position)
|
||||||
: base(slider, position)
|
: base(slider, position)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
|
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
|
||||||
|
|
||||||
Add(drawableObject = new DrawableSlider(slider));
|
Add(drawableObject = new DrawableSlider(slider));
|
||||||
AddBlueprint(blueprint = new TestSliderBlueprint(drawableObject));
|
AddBlueprint(blueprint = new TestSliderBlueprint(slider), drawableObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -174,10 +174,10 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
AddAssert("body positioned correctly", () => blueprint.BodyPiece.Position == slider.StackedPosition);
|
AddAssert("body positioned correctly", () => blueprint.BodyPiece.Position == slider.StackedPosition);
|
||||||
|
|
||||||
AddAssert("head positioned correctly",
|
AddAssert("head positioned correctly",
|
||||||
() => Precision.AlmostEquals(blueprint.HeadBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.HeadCircle.ScreenSpaceDrawQuad.Centre));
|
() => Precision.AlmostEquals(blueprint.HeadOverlay.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.HeadCircle.ScreenSpaceDrawQuad.Centre));
|
||||||
|
|
||||||
AddAssert("tail positioned correctly",
|
AddAssert("tail positioned correctly",
|
||||||
() => Precision.AlmostEquals(blueprint.TailBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre));
|
() => Precision.AlmostEquals(blueprint.TailOverlay.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void moveMouseToControlPoint(int index)
|
private void moveMouseToControlPoint(int index)
|
||||||
@ -195,23 +195,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
private class TestSliderBlueprint : SliderSelectionBlueprint
|
private class TestSliderBlueprint : SliderSelectionBlueprint
|
||||||
{
|
{
|
||||||
public new SliderBodyPiece BodyPiece => base.BodyPiece;
|
public new SliderBodyPiece BodyPiece => base.BodyPiece;
|
||||||
public new TestSliderCircleBlueprint HeadBlueprint => (TestSliderCircleBlueprint)base.HeadBlueprint;
|
public new TestSliderCircleOverlay HeadOverlay => (TestSliderCircleOverlay)base.HeadOverlay;
|
||||||
public new TestSliderCircleBlueprint TailBlueprint => (TestSliderCircleBlueprint)base.TailBlueprint;
|
public new TestSliderCircleOverlay TailOverlay => (TestSliderCircleOverlay)base.TailOverlay;
|
||||||
public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser;
|
public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser;
|
||||||
|
|
||||||
public TestSliderBlueprint(DrawableSlider slider)
|
public TestSliderBlueprint(Slider slider)
|
||||||
: base(slider)
|
: base(slider)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new TestSliderCircleBlueprint(slider, position);
|
protected override SliderCircleOverlay CreateCircleOverlay(Slider slider, SliderPosition position) => new TestSliderCircleOverlay(slider, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestSliderCircleBlueprint : SliderCircleSelectionBlueprint
|
private class TestSliderCircleOverlay : SliderCircleOverlay
|
||||||
{
|
{
|
||||||
public new HitCirclePiece CirclePiece => base.CirclePiece;
|
public new HitCirclePiece CirclePiece => base.CirclePiece;
|
||||||
|
|
||||||
public TestSliderCircleBlueprint(DrawableSlider slider, SliderPosition position)
|
public TestSliderCircleOverlay(Slider slider, SliderPosition position)
|
||||||
: base(slider, position)
|
: base(slider, position)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
Child = drawableSpinner = new DrawableSpinner(spinner)
|
Child = drawableSpinner = new DrawableSpinner(spinner)
|
||||||
});
|
});
|
||||||
|
|
||||||
AddBlueprint(new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) });
|
AddBlueprint(new SpinnerSelectionBlueprint(spinner) { Size = new Vector2(0.5f) }, drawableSpinner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
Child = new SkinProvidingContainer(new DefaultSkin())
|
Child = new SkinProvidingContainer(new DefaultSkin(null))
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = drawableHitCircle = new DrawableHitCircle(hitCircle)
|
Child = drawableHitCircle = new DrawableHitCircle(hitCircle)
|
||||||
|
@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
|
|||||||
|
|
||||||
protected readonly HitCirclePiece CirclePiece;
|
protected readonly HitCirclePiece CirclePiece;
|
||||||
|
|
||||||
public HitCircleSelectionBlueprint(DrawableHitCircle drawableCircle)
|
public HitCircleSelectionBlueprint(HitCircle circle)
|
||||||
: base(drawableCircle)
|
: base(circle)
|
||||||
{
|
{
|
||||||
InternalChild = CirclePiece = new HitCirclePiece();
|
InternalChild = CirclePiece = new HitCirclePiece();
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,20 @@
|
|||||||
// 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 osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public abstract class OsuSelectionBlueprint<T> : OverlaySelectionBlueprint
|
public abstract class OsuSelectionBlueprint<T> : HitObjectSelectionBlueprint<T>
|
||||||
where T : OsuHitObject
|
where T : OsuHitObject
|
||||||
{
|
{
|
||||||
protected T HitObject => (T)DrawableObject.HitObject;
|
protected new DrawableOsuHitObject DrawableObject => (DrawableOsuHitObject)base.DrawableObject;
|
||||||
|
|
||||||
protected override bool AlwaysShowWhenSelected => true;
|
protected override bool AlwaysShowWhenSelected => true;
|
||||||
|
|
||||||
protected OsuSelectionBlueprint(DrawableHitObject drawableObject)
|
protected OsuSelectionBlueprint(T hitObject)
|
||||||
: base(drawableObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
int totalCount = Pieces.Count(p => p.IsSelected.Value);
|
int totalCount = Pieces.Count(p => p.IsSelected.Value);
|
||||||
int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type.Value == type);
|
int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type.Value == type);
|
||||||
|
|
||||||
var item = new PathTypeMenuItem(type, () =>
|
var item = new TernaryStateRadioMenuItem(type == null ? "Inherit" : type.ToString().Humanize(), MenuItemType.Standard, _ =>
|
||||||
{
|
{
|
||||||
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
|
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
|
||||||
updatePathType(p, type);
|
updatePathType(p, type);
|
||||||
@ -258,15 +258,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PathTypeMenuItem : TernaryStateMenuItem
|
|
||||||
{
|
|
||||||
public PathTypeMenuItem(PathType? type, Action action)
|
|
||||||
: base(type == null ? "Inherit" : type.ToString().Humanize(), changeState, MenuItemType.Standard, _ => action?.Invoke())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TernaryState changeState(TernaryState state) => TernaryState.True;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
{
|
{
|
||||||
AccentColour = Color4.Transparent
|
AccentColour = Color4.Transparent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SliderSelectionBlueprint relies on calling ReceivePositionalInputAt on this drawable to determine whether selection should occur.
|
||||||
|
// Without AlwaysPresent, a movement in a parent container (ie. the editor composer area resizing) could cause incorrect input handling.
|
||||||
|
AlwaysPresent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -1,36 +1,32 @@
|
|||||||
// 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 osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||||
{
|
{
|
||||||
public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint<Slider>
|
public class SliderCircleOverlay : CompositeDrawable
|
||||||
{
|
{
|
||||||
protected readonly HitCirclePiece CirclePiece;
|
protected readonly HitCirclePiece CirclePiece;
|
||||||
|
|
||||||
|
private readonly Slider slider;
|
||||||
private readonly SliderPosition position;
|
private readonly SliderPosition position;
|
||||||
|
|
||||||
public SliderCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position)
|
public SliderCircleOverlay(Slider slider, SliderPosition position)
|
||||||
: base(slider)
|
|
||||||
{
|
{
|
||||||
|
this.slider = slider;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
|
||||||
InternalChild = CirclePiece = new HitCirclePiece();
|
InternalChild = CirclePiece = new HitCirclePiece();
|
||||||
|
|
||||||
Select();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
CirclePiece.UpdateFrom(position == SliderPosition.Start ? (HitCircle)HitObject.HeadCircle : HitObject.TailCircle);
|
CirclePiece.UpdateFrom(position == SliderPosition.Start ? (HitCircle)slider.HeadCircle : slider.TailCircle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input.
|
|
||||||
public override bool HandlePositionalInput => false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,7 +16,6 @@ using osu.Game.Rulesets.Edit;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -27,14 +26,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
public class SliderSelectionBlueprint : OsuSelectionBlueprint<Slider>
|
public class SliderSelectionBlueprint : OsuSelectionBlueprint<Slider>
|
||||||
{
|
{
|
||||||
protected SliderBodyPiece BodyPiece { get; private set; }
|
protected SliderBodyPiece BodyPiece { get; private set; }
|
||||||
protected SliderCircleSelectionBlueprint HeadBlueprint { get; private set; }
|
protected SliderCircleOverlay HeadOverlay { get; private set; }
|
||||||
protected SliderCircleSelectionBlueprint TailBlueprint { get; private set; }
|
protected SliderCircleOverlay TailOverlay { get; private set; }
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
protected PathControlPointVisualiser ControlPointVisualiser { get; private set; }
|
protected PathControlPointVisualiser ControlPointVisualiser { get; private set; }
|
||||||
|
|
||||||
private readonly DrawableSlider slider;
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private HitObjectComposer composer { get; set; }
|
private HitObjectComposer composer { get; set; }
|
||||||
|
|
||||||
@ -52,10 +49,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
|
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
|
||||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||||
|
|
||||||
public SliderSelectionBlueprint(DrawableSlider slider)
|
public SliderSelectionBlueprint(Slider slider)
|
||||||
: base(slider)
|
: base(slider)
|
||||||
{
|
{
|
||||||
this.slider = slider;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -64,8 +60,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
BodyPiece = new SliderBodyPiece(),
|
BodyPiece = new SliderBodyPiece(),
|
||||||
HeadBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.Start),
|
HeadOverlay = CreateCircleOverlay(HitObject, SliderPosition.Start),
|
||||||
TailBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.End),
|
TailOverlay = CreateCircleOverlay(HitObject, SliderPosition.End),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
|
|
||||||
protected override void OnSelected()
|
protected override void OnSelected()
|
||||||
{
|
{
|
||||||
AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(slider.HitObject, true)
|
AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(HitObject, true)
|
||||||
{
|
{
|
||||||
RemoveControlPointsRequested = removeControlPoints
|
RemoveControlPointsRequested = removeControlPoints
|
||||||
});
|
});
|
||||||
@ -215,7 +211,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there are 0 or 1 remaining control points, the slider is in a degenerate (single point) form and should be deleted
|
// If there are 0 or 1 remaining control points, the slider is in a degenerate (single point) form and should be deleted
|
||||||
if (controlPoints.Count <= 1 || !slider.HitObject.Path.HasValidLength)
|
if (controlPoints.Count <= 1 || !HitObject.Path.HasValidLength)
|
||||||
{
|
{
|
||||||
placementHandler?.Delete(HitObject);
|
placementHandler?.Delete(HitObject);
|
||||||
return;
|
return;
|
||||||
@ -245,6 +241,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
|
||||||
BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true;
|
BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true;
|
||||||
|
|
||||||
protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position);
|
protected virtual SliderCircleOverlay CreateCircleOverlay(Slider slider, SliderPosition position) => new SliderCircleOverlay(slider, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
||||||
@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
|||||||
{
|
{
|
||||||
private readonly SpinnerPiece piece;
|
private readonly SpinnerPiece piece;
|
||||||
|
|
||||||
public SpinnerSelectionBlueprint(DrawableSpinner spinner)
|
public SpinnerSelectionBlueprint(Spinner spinner)
|
||||||
: base(spinner)
|
: base(spinner)
|
||||||
{
|
{
|
||||||
InternalChild = piece = new SpinnerPiece();
|
InternalChild = piece = new SpinnerPiece();
|
||||||
|
@ -2,7 +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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
|||||||
new IssueTemplateOffscreenSlider(this)
|
new IssueTemplateOffscreenSlider(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
foreach (var hitobject in playableBeatmap.HitObjects)
|
foreach (var hitobject in context.Beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
switch (hitobject)
|
switch (hitobject)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Checks;
|
using osu.Game.Rulesets.Osu.Edit.Checks;
|
||||||
@ -17,9 +16,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new CheckOffscreenObjects()
|
new CheckOffscreenObjects()
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
return checks.SelectMany(check => check.Run(playableBeatmap, workingBeatmap));
|
return checks.SelectMany(check => check.Run(context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,10 @@
|
|||||||
|
|
||||||
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.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
@ -21,21 +20,21 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new OsuSelectionHandler();
|
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new OsuSelectionHandler();
|
||||||
|
|
||||||
public override OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
|
public override HitObjectSelectionBlueprint CreateHitObjectBlueprintFor(HitObject hitObject)
|
||||||
{
|
{
|
||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
{
|
{
|
||||||
case DrawableHitCircle circle:
|
case HitCircle circle:
|
||||||
return new HitCircleSelectionBlueprint(circle);
|
return new HitCircleSelectionBlueprint(circle);
|
||||||
|
|
||||||
case DrawableSlider slider:
|
case Slider slider:
|
||||||
return new SliderSelectionBlueprint(slider);
|
return new SliderSelectionBlueprint(slider);
|
||||||
|
|
||||||
case DrawableSpinner spinner:
|
case Spinner spinner:
|
||||||
return new SpinnerSelectionBlueprint(spinner);
|
return new SpinnerSelectionBlueprint(spinner);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.CreateBlueprintFor(hitObject);
|
return base.CreateHitObjectBlueprintFor(hitObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,23 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using osuTK;
|
using Vector2 = osuTK.Vector2;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
{
|
{
|
||||||
public class OsuSelectionHandler : EditorSelectionHandler
|
public class OsuSelectionHandler : EditorSelectionHandler
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
||||||
|
/// </summary>
|
||||||
|
private Vector2? referenceOrigin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// During a transform, the initial path types of a single selected slider are stored so they
|
||||||
|
/// can be maintained throughout the operation.
|
||||||
|
/// </summary>
|
||||||
|
private List<PathType?> referencePathTypes;
|
||||||
|
|
||||||
protected override void OnSelectionChanged()
|
protected override void OnSelectionChanged()
|
||||||
{
|
{
|
||||||
base.OnSelectionChanged();
|
base.OnSelectionChanged();
|
||||||
@ -50,17 +61,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
|
||||||
/// </summary>
|
|
||||||
private Vector2? referenceOrigin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// During a transform, the initial path types of a single selected slider are stored so they
|
|
||||||
/// can be maintained throughout the operation.
|
|
||||||
/// </summary>
|
|
||||||
private List<PathType?> referencePathTypes;
|
|
||||||
|
|
||||||
public override bool HandleReverse()
|
public override bool HandleReverse()
|
||||||
{
|
{
|
||||||
var hitObjects = EditorBeatmap.SelectedHitObjects;
|
var hitObjects = EditorBeatmap.SelectedHitObjects;
|
||||||
@ -114,24 +114,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
var hitObjects = selectedMovableObjects;
|
var hitObjects = selectedMovableObjects;
|
||||||
|
|
||||||
var selectedObjectsQuad = getSurroundingQuad(hitObjects);
|
var selectedObjectsQuad = getSurroundingQuad(hitObjects);
|
||||||
var centre = selectedObjectsQuad.Centre;
|
|
||||||
|
|
||||||
foreach (var h in hitObjects)
|
foreach (var h in hitObjects)
|
||||||
{
|
{
|
||||||
var pos = h.Position;
|
h.Position = GetFlippedPosition(direction, selectedObjectsQuad, h.Position);
|
||||||
|
|
||||||
switch (direction)
|
|
||||||
{
|
|
||||||
case Direction.Horizontal:
|
|
||||||
pos.X = centre.X - (pos.X - centre.X);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Direction.Vertical:
|
|
||||||
pos.Y = centre.Y - (pos.Y - centre.Y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Position = pos;
|
|
||||||
|
|
||||||
if (h is Slider slider)
|
if (h is Slider slider)
|
||||||
{
|
{
|
||||||
@ -204,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList();
|
referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList();
|
||||||
|
|
||||||
Quad sliderQuad = getSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value));
|
Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value));
|
||||||
|
|
||||||
// Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0.
|
// Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0.
|
||||||
scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size;
|
scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size;
|
||||||
@ -333,7 +319,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hitObjects">The hit objects to calculate a quad for.</param>
|
/// <param name="hitObjects">The hit objects to calculate a quad for.</param>
|
||||||
private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
|
private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
|
||||||
getSurroundingQuad(hitObjects.SelectMany(h =>
|
GetSurroundingQuad(hitObjects.SelectMany(h =>
|
||||||
{
|
{
|
||||||
if (h is IHasPath path)
|
if (h is IHasPath path)
|
||||||
{
|
{
|
||||||
@ -348,30 +334,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return new[] { h.Position };
|
return new[] { h.Position };
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a gamefield-space quad surrounding the provided points.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="points">The points to calculate a quad for.</param>
|
|
||||||
private Quad getSurroundingQuad(IEnumerable<Vector2> points)
|
|
||||||
{
|
|
||||||
if (!EditorBeatmap.SelectedHitObjects.Any())
|
|
||||||
return new Quad();
|
|
||||||
|
|
||||||
Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue);
|
|
||||||
Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);
|
|
||||||
|
|
||||||
// Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted
|
|
||||||
foreach (var p in points)
|
|
||||||
{
|
|
||||||
minPosition = Vector2.ComponentMin(minPosition, p);
|
|
||||||
maxPosition = Vector2.ComponentMax(maxPosition, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 size = maxPosition - minPosition;
|
|
||||||
|
|
||||||
return new Quad(minPosition.X, minPosition.Y, size.X, size.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All osu! hitobjects which can be moved/rotated/scaled.
|
/// All osu! hitobjects which can be moved/rotated/scaled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -43,13 +43,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
base.ApplyIncreasedVisibilityState(hitObject, state);
|
|
||||||
applyState(hitObject, true);
|
applyState(hitObject, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
base.ApplyNormalVisibilityState(hitObject, state);
|
|
||||||
applyState(hitObject, false);
|
applyState(hitObject, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,20 +58,20 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
OsuHitObject hitObject = drawableOsuObject.HitObject;
|
OsuHitObject hitObject = drawableOsuObject.HitObject;
|
||||||
|
|
||||||
(double startTime, double duration) fadeOut = getFadeOutParameters(drawableOsuObject);
|
(double fadeStartTime, double fadeDuration) = getFadeOutParameters(drawableOsuObject);
|
||||||
|
|
||||||
switch (drawableObject)
|
switch (drawableObject)
|
||||||
{
|
{
|
||||||
case DrawableSliderTail _:
|
case DrawableSliderTail _:
|
||||||
using (drawableObject.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (drawableObject.BeginAbsoluteSequence(fadeStartTime))
|
||||||
drawableObject.FadeOut(fadeOut.duration);
|
drawableObject.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSliderRepeat sliderRepeat:
|
case DrawableSliderRepeat sliderRepeat:
|
||||||
using (drawableObject.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (drawableObject.BeginAbsoluteSequence(fadeStartTime))
|
||||||
// only apply to circle piece – reverse arrow is not affected by hidden.
|
// only apply to circle piece – reverse arrow is not affected by hidden.
|
||||||
sliderRepeat.CirclePiece.FadeOut(fadeOut.duration);
|
sliderRepeat.CirclePiece.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -88,23 +86,23 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we don't want to see the approach circle
|
// we don't want to see the approach circle
|
||||||
using (circle.BeginAbsoluteSequence(hitObject.StartTime - hitObject.TimePreempt, true))
|
using (circle.BeginAbsoluteSequence(hitObject.StartTime - hitObject.TimePreempt))
|
||||||
circle.ApproachCircle.Hide();
|
circle.ApproachCircle.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (drawableObject.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (drawableObject.BeginAbsoluteSequence(fadeStartTime))
|
||||||
fadeTarget.FadeOut(fadeOut.duration);
|
fadeTarget.FadeOut(fadeDuration);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSlider slider:
|
case DrawableSlider slider:
|
||||||
using (slider.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (slider.BeginAbsoluteSequence(fadeStartTime))
|
||||||
slider.Body.FadeOut(fadeOut.duration, Easing.Out);
|
slider.Body.FadeOut(fadeDuration, Easing.Out);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSliderTick sliderTick:
|
case DrawableSliderTick sliderTick:
|
||||||
using (sliderTick.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (sliderTick.BeginAbsoluteSequence(fadeStartTime))
|
||||||
sliderTick.FadeOut(fadeOut.duration);
|
sliderTick.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -112,14 +110,14 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
// hide elements we don't care about.
|
// hide elements we don't care about.
|
||||||
// todo: hide background
|
// todo: hide background
|
||||||
|
|
||||||
using (spinner.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (spinner.BeginAbsoluteSequence(fadeStartTime))
|
||||||
spinner.FadeOut(fadeOut.duration);
|
spinner.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private (double startTime, double duration) getFadeOutParameters(DrawableOsuHitObject drawableObject)
|
private (double fadeStartTime, double fadeDuration) getFadeOutParameters(DrawableOsuHitObject drawableObject)
|
||||||
{
|
{
|
||||||
switch (drawableObject)
|
switch (drawableObject)
|
||||||
{
|
{
|
||||||
@ -137,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
return getParameters(drawableObject.HitObject);
|
return getParameters(drawableObject.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
static (double startTime, double duration) getParameters(OsuHitObject hitObject)
|
static (double fadeStartTime, double fadeDuration) getParameters(OsuHitObject hitObject)
|
||||||
{
|
{
|
||||||
var fadeOutStartTime = hitObject.StartTime - hitObject.TimePreempt + hitObject.TimeFadeIn;
|
var fadeOutStartTime = hitObject.StartTime - hitObject.TimePreempt + hitObject.TimeFadeIn;
|
||||||
var fadeOutDuration = hitObject.TimePreempt * fade_out_duration_multiplier;
|
var fadeOutDuration = hitObject.TimePreempt * fade_out_duration_multiplier;
|
||||||
|
@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Y = SPINNER_TOP_OFFSET + 115,
|
Y = SPINNER_TOP_OFFSET + 115,
|
||||||
},
|
},
|
||||||
bonusCounter = new LegacySpriteText(source, LegacyFont.Score)
|
bonusCounter = new LegacySpriteText(LegacyFont.Score)
|
||||||
{
|
{
|
||||||
Alpha = 0f,
|
Alpha = 0f,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Position = new Vector2(-87, 445 + spm_hide_offset),
|
Position = new Vector2(-87, 445 + spm_hide_offset),
|
||||||
},
|
},
|
||||||
spmCounter = new LegacySpriteText(source, LegacyFont.Score)
|
spmCounter = new LegacySpriteText(LegacyFont.Score)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
|
@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
if (!this.HasFont(LegacyFont.HitCircle))
|
if (!this.HasFont(LegacyFont.HitCircle))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new LegacySpriteText(Source, LegacyFont.HitCircle)
|
return new LegacySpriteText(LegacyFont.HitCircle)
|
||||||
{
|
{
|
||||||
// stable applies a blanket 0.8x scale to hitcircle fonts
|
// stable applies a blanket 0.8x scale to hitcircle fonts
|
||||||
Scale = new Vector2(0.8f),
|
Scale = new Vector2(0.8f),
|
||||||
|
@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
var point = new HitPoint(pointType, this)
|
var point = new HitPoint(pointType, this)
|
||||||
{
|
{
|
||||||
Colour = pointType == HitPointType.Hit ? new Color4(102, 255, 204, 255) : new Color4(255, 102, 102, 255)
|
BaseColour = pointType == HitPointType.Hit ? new Color4(102, 255, 204, 255) : new Color4(255, 102, 102, 255)
|
||||||
};
|
};
|
||||||
|
|
||||||
points[r][c] = point;
|
points[r][c] = point;
|
||||||
@ -234,6 +234,11 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
private class HitPoint : Circle
|
private class HitPoint : Circle
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The base colour which will be lightened/darkened depending on the value of this <see cref="HitPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Color4 BaseColour;
|
||||||
|
|
||||||
private readonly HitPointType pointType;
|
private readonly HitPointType pointType;
|
||||||
private readonly AccuracyHeatmap heatmap;
|
private readonly AccuracyHeatmap heatmap;
|
||||||
|
|
||||||
@ -284,7 +289,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
Alpha = Math.Min(amount / lighten_cutoff, 1);
|
Alpha = Math.Min(amount / lighten_cutoff, 1);
|
||||||
if (pointType == HitPointType.Hit)
|
if (pointType == HitPointType.Hit)
|
||||||
Colour = ((Color4)Colour).Lighten(Math.Max(0, amount - lighten_cutoff));
|
Colour = BaseColour.Lighten(Math.Max(0, amount - lighten_cutoff));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
var hitWindows = new OsuHitWindows();
|
var hitWindows = new OsuHitWindows();
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
||||||
poolDictionary.Add(result, new DrawableJudgementPool(result, onJudgmentLoaded));
|
poolDictionary.Add(result, new DrawableJudgementPool(result, onJudgementLoaded));
|
||||||
|
|
||||||
AddRangeInternal(poolDictionary.Values);
|
AddRangeInternal(poolDictionary.Values);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJudgmentLoaded(DrawableOsuJudgement judgement)
|
private void onJudgementLoaded(DrawableOsuJudgement judgement)
|
||||||
{
|
{
|
||||||
judgementAboveHitObjectLayer.Add(judgement.GetProxyAboveHitObjectsContent());
|
judgementAboveHitObjectLayer.Add(judgement.GetProxyAboveHitObjectsContent());
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
=> AddStep("clear SHOC", () => hitObjectContainer.Clear(false));
|
=> AddStep("clear SHOC", () => hitObjectContainer.Clear());
|
||||||
|
|
||||||
protected void AddHitObject(DrawableHitObject hitObject)
|
protected void AddHitObject(DrawableHitObject hitObject)
|
||||||
=> AddStep("add to SHOC", () => hitObjectContainer.Add(hitObject));
|
=> AddStep("add to SHOC", () => hitObjectContainer.Add(hitObject));
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Legacy;
|
using osu.Game.Rulesets.Taiko.Skinning.Legacy;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -27,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
AddToggleStep("Toggle passing", passing => this.ChildrenOfType<LegacyTaikoScroller>().ForEach(s => s.LastResult.Value =
|
AddToggleStep("Toggle passing", passing => this.ChildrenOfType<LegacyTaikoScroller>().ForEach(s => s.LastResult.Value =
|
||||||
new JudgementResult(null, new Judgement()) { Type = passing ? HitResult.Great : HitResult.Miss }));
|
new JudgementResult(new HitObject(), new Judgement()) { Type = passing ? HitResult.Great : HitResult.Miss }));
|
||||||
|
|
||||||
AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
|
AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public class TaikoSelectionBlueprint : OverlaySelectionBlueprint
|
public class TaikoSelectionBlueprint : HitObjectSelectionBlueprint
|
||||||
{
|
{
|
||||||
public TaikoSelectionBlueprint(DrawableHitObject hitObject)
|
public TaikoSelectionBlueprint(HitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.None;
|
RelativeSizeAxes = Axes.None;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
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.Drawables;
|
|
||||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
@ -18,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
|
|
||||||
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new TaikoSelectionHandler();
|
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new TaikoSelectionHandler();
|
||||||
|
|
||||||
public override OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) =>
|
public override HitObjectSelectionBlueprint CreateHitObjectBlueprintFor(HitObject hitObject) =>
|
||||||
new TaikoSelectionBlueprint(hitObject);
|
new TaikoSelectionBlueprint(hitObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,10 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint<HitObject>> selection)
|
protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint<HitObject>> selection)
|
||||||
{
|
{
|
||||||
if (selection.All(s => s.Item is Hit))
|
if (selection.All(s => s.Item is Hit))
|
||||||
yield return new TernaryStateMenuItem("Rim") { State = { BindTarget = selectionRimState } };
|
yield return new TernaryStateToggleMenuItem("Rim") { State = { BindTarget = selectionRimState } };
|
||||||
|
|
||||||
if (selection.All(s => s.Item is TaikoHitObject))
|
if (selection.All(s => s.Item is TaikoHitObject))
|
||||||
yield return new TernaryStateMenuItem("Strong") { State = { BindTarget = selectionStrongState } };
|
yield return new TernaryStateToggleMenuItem("Strong") { State = { BindTarget = selectionStrongState } };
|
||||||
|
|
||||||
foreach (var item in base.GetContextMenuItemsForSelection(selection))
|
foreach (var item in base.GetContextMenuItemsForSelection(selection))
|
||||||
yield return item;
|
yield return item;
|
||||||
|
@ -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 osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Mods
|
namespace osu.Game.Rulesets.Taiko.Mods
|
||||||
{
|
{
|
||||||
@ -10,5 +11,13 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public override string Description => @"Beats fade out before you hit them!";
|
public override string Description => @"Beats fade out before you hit them!";
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => 1.06;
|
||||||
public override bool HasImplementation => false;
|
public override bool HasImplementation => false;
|
||||||
|
|
||||||
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// 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 System.Linq;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -12,6 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public class TaikoModRandom : ModRandom, IApplicableToBeatmap
|
public class TaikoModRandom : ModRandom, IApplicableToBeatmap
|
||||||
{
|
{
|
||||||
public override string Description => @"Shuffle around the colours!";
|
public override string Description => @"Shuffle around the colours!";
|
||||||
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(TaikoModSwap)).ToArray();
|
||||||
|
|
||||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
|
33
osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
Normal file
33
osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Mods
|
||||||
|
{
|
||||||
|
public class TaikoModSwap : Mod, IApplicableToBeatmap
|
||||||
|
{
|
||||||
|
public override string Name => "Swap";
|
||||||
|
public override string Acronym => "SW";
|
||||||
|
public override string Description => @"Dons become kats, kats become dons";
|
||||||
|
public override ModType Type => ModType.Conversion;
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray();
|
||||||
|
|
||||||
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
var taikoBeatmap = (TaikoBeatmap)beatmap;
|
||||||
|
|
||||||
|
foreach (var obj in taikoBeatmap.HitObjects)
|
||||||
|
{
|
||||||
|
if (obj is Hit hit)
|
||||||
|
hit.Type = hit.Type == HitType.Centre ? HitType.Rim : HitType.Centre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,8 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
@ -13,7 +11,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Replays
|
namespace osu.Game.Rulesets.Taiko.Replays
|
||||||
{
|
{
|
||||||
public class TaikoAutoGenerator : AutoGenerator
|
public class TaikoAutoGenerator : AutoGenerator<TaikoReplayFrame>
|
||||||
{
|
{
|
||||||
public new TaikoBeatmap Beatmap => (TaikoBeatmap)base.Beatmap;
|
public new TaikoBeatmap Beatmap => (TaikoBeatmap)base.Beatmap;
|
||||||
|
|
||||||
@ -22,16 +20,12 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
|||||||
public TaikoAutoGenerator(IBeatmap beatmap)
|
public TaikoAutoGenerator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Replay = new Replay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Replay Replay;
|
protected override void GenerateFrames()
|
||||||
protected List<ReplayFrame> Frames => Replay.Frames;
|
|
||||||
|
|
||||||
public override Replay Generate()
|
|
||||||
{
|
{
|
||||||
if (Beatmap.HitObjects.Count == 0)
|
if (Beatmap.HitObjects.Count == 0)
|
||||||
return Replay;
|
return;
|
||||||
|
|
||||||
bool hitButton = true;
|
bool hitButton = true;
|
||||||
|
|
||||||
@ -128,8 +122,6 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
|||||||
|
|
||||||
hitButton = !hitButton;
|
hitButton = !hitButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Replay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
// store X before checking wide enough so if we perform layout there is no positional discrepancy.
|
// store X before checking wide enough so if we perform layout there is no positional discrepancy.
|
||||||
float currentX = (InternalChildren?.FirstOrDefault()?.X ?? 0) - (float)Clock.ElapsedFrameTime * 0.1f;
|
float currentX = (InternalChildren.FirstOrDefault()?.X ?? 0) - (float)Clock.ElapsedFrameTime * 0.1f;
|
||||||
|
|
||||||
// ensure we have enough sprites
|
// ensure we have enough sprites
|
||||||
if (!InternalChildren.Any()
|
if (!InternalChildren.Any()
|
||||||
|
@ -136,6 +136,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
new TaikoModRandom(),
|
new TaikoModRandom(),
|
||||||
new TaikoModDifficultyAdjust(),
|
new TaikoModDifficultyAdjust(),
|
||||||
new TaikoModClassic(),
|
new TaikoModClassic(),
|
||||||
|
new TaikoModSwap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
|
@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Mods;
|
|||||||
namespace osu.Game.Tests.Beatmaps
|
namespace osu.Game.Tests.Beatmaps
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BeatmapDifficultyManagerTest
|
public class BeatmapDifficultyCacheTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestKeyEqualsWithDifferentModInstances()
|
public void TestKeyEqualsWithDifferentModInstances()
|
@ -12,6 +12,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
@ -264,7 +265,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
// change filename
|
// change filename
|
||||||
var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First());
|
var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First());
|
||||||
firstFile.MoveTo(Path.Combine(firstFile.DirectoryName, $"{firstFile.Name}-changed{firstFile.Extension}"));
|
firstFile.MoveTo(Path.Combine(firstFile.DirectoryName.AsNonNull(), $"{firstFile.Name}-changed{firstFile.Extension}"));
|
||||||
|
|
||||||
using (var zip = ZipArchive.Create())
|
using (var zip = ZipArchive.Create())
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -40,23 +41,23 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||||
mock.SetupGet(w => w.Track).Returns((Track)null);
|
mock.SetupGet(w => w.Track).Returns((Track)null);
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(new BeatmapVerifierContext(beatmap, mock.Object)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAcceptable()
|
public void TestAcceptable()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(192);
|
var context = getContext(192);
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNullBitrate()
|
public void TestNullBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(null);
|
var context = getContext(null);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
||||||
@ -65,9 +66,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestZeroBitrate()
|
public void TestZeroBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(0);
|
var context = getContext(0);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
||||||
@ -76,9 +77,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooHighBitrate()
|
public void TestTooHighBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(320);
|
var context = getContext(320);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooHighBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooHighBitrate);
|
||||||
@ -87,14 +88,19 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooLowBitrate()
|
public void TestTooLowBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(64);
|
var context = getContext(64);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooLowBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooLowBitrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BeatmapVerifierContext getContext(int? audioBitrate)
|
||||||
|
{
|
||||||
|
return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(audioBitrate).Object);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the mock of the working beatmap with the given audio properties.
|
/// Returns the mock of the working beatmap with the given audio properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,6 +9,7 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using FileInfo = osu.Game.IO.FileInfo;
|
using FileInfo = osu.Game.IO.FileInfo;
|
||||||
@ -53,25 +54,25 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = null;
|
||||||
var mock = getMockWorkingBeatmap(null, System.Array.Empty<byte>());
|
var context = getContext(null, System.Array.Empty<byte>());
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAcceptable()
|
public void TestAcceptable()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(1920, 1080));
|
var context = getContext(new Texture(1920, 1080));
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestTooHighResolution()
|
public void TestTooHighResolution()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(3840, 2160));
|
var context = getContext(new Texture(3840, 2160));
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooHighResolution);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooHighResolution);
|
||||||
@ -80,9 +81,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLowResolution()
|
public void TestLowResolution()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(640, 480));
|
var context = getContext(new Texture(640, 480));
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateLowResolution);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateLowResolution);
|
||||||
@ -91,9 +92,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooLowResolution()
|
public void TestTooLowResolution()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(100, 100));
|
var context = getContext(new Texture(100, 100));
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooLowResolution);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooLowResolution);
|
||||||
@ -102,14 +103,19 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooUncompressed()
|
public void TestTooUncompressed()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(1920, 1080), new byte[1024 * 1024 * 3]);
|
var context = getContext(new Texture(1920, 1080), new byte[1024 * 1024 * 3]);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BeatmapVerifierContext getContext(Texture background, [CanBeNull] byte[] fileBytes = null)
|
||||||
|
{
|
||||||
|
return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, fileBytes).Object);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the mock of the working beatmap with the given background and filesize.
|
/// Returns the mock of the working beatmap with the given background and filesize.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -6,11 +6,13 @@ using System.Linq;
|
|||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Editing.Checks
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
{
|
{
|
||||||
@ -105,7 +107,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
new HitCircle { StartTime = 300 }
|
new HitCircle { StartTime = 300 }
|
||||||
};
|
};
|
||||||
|
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitobjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(3));
|
Assert.That(issues, Has.Count.EqualTo(3));
|
||||||
Assert.That(issues.Where(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent).ToList(), Has.Count.EqualTo(2));
|
Assert.That(issues.Where(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent).ToList(), Has.Count.EqualTo(2));
|
||||||
@ -164,12 +166,12 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
|
|
||||||
private void assertOk(List<HitObject> hitobjects)
|
private void assertOk(List<HitObject> hitobjects)
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(getPlayableBeatmap(hitobjects), null), Is.Empty);
|
Assert.That(check.Run(getContext(hitobjects)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertConcurrentSame(List<HitObject> hitobjects, int count = 1)
|
private void assertConcurrentSame(List<HitObject> hitobjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitobjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentSame));
|
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentSame));
|
||||||
@ -177,18 +179,16 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
|
|
||||||
private void assertConcurrentDifferent(List<HitObject> hitobjects, int count = 1)
|
private void assertConcurrentDifferent(List<HitObject> hitobjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitobjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent));
|
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap getPlayableBeatmap(List<HitObject> hitobjects)
|
private BeatmapVerifierContext getContext(List<HitObject> hitobjects)
|
||||||
{
|
{
|
||||||
return new Beatmap<HitObject>
|
var beatmap = new Beatmap<HitObject> { HitObjects = hitobjects };
|
||||||
{
|
return new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
HitObjects = hitobjects
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
@ -45,7 +46,8 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBackgroundSetAndInFiles()
|
public void TestBackgroundSetAndInFiles()
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(beatmap, new TestWorkingBeatmap(beatmap)), Is.Empty);
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -53,7 +55,8 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
|
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
|
||||||
|
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateDoesNotExist);
|
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateDoesNotExist);
|
||||||
@ -64,7 +67,8 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = null;
|
||||||
|
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateNoneSet);
|
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateNoneSet);
|
||||||
|
@ -7,10 +7,12 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Editing.Checks
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
{
|
{
|
||||||
@ -100,12 +102,12 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
}, count: 2);
|
}, count: 2);
|
||||||
|
|
||||||
// Start and end are 2 ms and 1.25 ms off respectively, hence two different issues in one object.
|
// Start and end are 2 ms and 1.25 ms off respectively, hence two different issues in one object.
|
||||||
var hitobjects = new List<HitObject>
|
var hitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
getSliderMock(startTime: 98, endTime: 398.75d).Object
|
getSliderMock(startTime: 98, endTime: 398.75d).Object
|
||||||
};
|
};
|
||||||
|
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitObjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(2));
|
Assert.That(issues, Has.Count.EqualTo(2));
|
||||||
Assert.That(issues.Any(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
Assert.That(issues.Any(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
||||||
@ -122,34 +124,36 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
return mockSlider;
|
return mockSlider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertOk(List<HitObject> hitobjects)
|
private void assertOk(List<HitObject> hitObjects)
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(getPlayableBeatmap(hitobjects), null), Is.Empty);
|
Assert.That(check.Run(getContext(hitObjects)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assert1Ms(List<HitObject> hitobjects, int count = 1)
|
private void assert1Ms(List<HitObject> hitObjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitObjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assert2Ms(List<HitObject> hitobjects, int count = 1)
|
private void assert2Ms(List<HitObject> hitObjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitObjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateLargeUnsnap));
|
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateLargeUnsnap));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap getPlayableBeatmap(List<HitObject> hitobjects)
|
private BeatmapVerifierContext getContext(List<HitObject> hitObjects)
|
||||||
{
|
{
|
||||||
return new Beatmap<HitObject>
|
var beatmap = new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
ControlPointInfo = cpi,
|
ControlPointInfo = cpi,
|
||||||
HitObjects = hitobjects
|
HitObjects = hitObjects
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
175
osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs
Normal file
175
osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Edit.Compose;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Editing
|
||||||
|
{
|
||||||
|
[HeadlessTest]
|
||||||
|
public class TestSceneHitObjectContainerEventBuffer : OsuTestScene
|
||||||
|
{
|
||||||
|
private readonly TestHitObject testObj = new TestHitObject();
|
||||||
|
|
||||||
|
private TestPlayfield playfield1;
|
||||||
|
private TestPlayfield playfield2;
|
||||||
|
private TestDrawable intermediateDrawable;
|
||||||
|
private HitObjectUsageEventBuffer eventBuffer;
|
||||||
|
|
||||||
|
private HitObject beganUsage;
|
||||||
|
private HitObject finishedUsage;
|
||||||
|
private HitObject transferredUsage;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup() => Schedule(() =>
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (eventBuffer != null)
|
||||||
|
{
|
||||||
|
eventBuffer.HitObjectUsageBegan -= onHitObjectUsageBegan;
|
||||||
|
eventBuffer.HitObjectUsageFinished -= onHitObjectUsageFinished;
|
||||||
|
eventBuffer.HitObjectUsageTransferred -= onHitObjectUsageTransferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
var topPlayfield = new TestPlayfield();
|
||||||
|
topPlayfield.AddNested(playfield1 = new TestPlayfield());
|
||||||
|
topPlayfield.AddNested(playfield2 = new TestPlayfield());
|
||||||
|
|
||||||
|
eventBuffer = new HitObjectUsageEventBuffer(topPlayfield);
|
||||||
|
eventBuffer.HitObjectUsageBegan += onHitObjectUsageBegan;
|
||||||
|
eventBuffer.HitObjectUsageFinished += onHitObjectUsageFinished;
|
||||||
|
eventBuffer.HitObjectUsageTransferred += onHitObjectUsageTransferred;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
topPlayfield,
|
||||||
|
intermediateDrawable = new TestDrawable(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
private void onHitObjectUsageBegan(HitObject obj) => beganUsage = obj;
|
||||||
|
|
||||||
|
private void onHitObjectUsageFinished(HitObject obj) => finishedUsage = obj;
|
||||||
|
|
||||||
|
private void onHitObjectUsageTransferred(HitObject obj, DrawableHitObject drawableObj) => transferredUsage = obj;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUsageBeganAfterAdd()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addCheckStep(began: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUsageFinishedAfterRemove()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addResetStep();
|
||||||
|
AddStep("remove hitobject", () => playfield1.Remove(testObj));
|
||||||
|
addCheckStep(finished: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUsageTransferredWhenMovedBetweenPlayfields()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addResetStep();
|
||||||
|
AddStep("transfer hitobject to other playfield", () =>
|
||||||
|
{
|
||||||
|
playfield1.Remove(testObj);
|
||||||
|
playfield2.Add(testObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
addCheckStep(transferred: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRemoveImmediatelyAfterUsageBegan()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject and schedule removal", () =>
|
||||||
|
{
|
||||||
|
playfield1.Add(testObj);
|
||||||
|
intermediateDrawable.Schedule(() => playfield1.Remove(testObj));
|
||||||
|
});
|
||||||
|
|
||||||
|
addCheckStep(began: true, finished: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRemoveImmediatelyAfterTransferred()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addResetStep();
|
||||||
|
AddStep("transfer hitobject to other playfield and schedule removal", () =>
|
||||||
|
{
|
||||||
|
playfield1.Remove(testObj);
|
||||||
|
playfield2.Add(testObj);
|
||||||
|
intermediateDrawable.Schedule(() => playfield2.Remove(testObj));
|
||||||
|
});
|
||||||
|
|
||||||
|
addCheckStep(transferred: true, finished: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateAfterChildren()
|
||||||
|
{
|
||||||
|
base.UpdateAfterChildren();
|
||||||
|
eventBuffer.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addResetStep() => AddStep("reset", reset);
|
||||||
|
|
||||||
|
private void reset()
|
||||||
|
{
|
||||||
|
beganUsage = null;
|
||||||
|
finishedUsage = null;
|
||||||
|
transferredUsage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCheckStep(bool began = false, bool finished = false, bool transferred = false)
|
||||||
|
=> AddAssert($"began = {began}, finished = {finished}, transferred = {transferred}",
|
||||||
|
() => (beganUsage == testObj) == began && (finishedUsage == testObj) == finished && (transferredUsage == testObj) == transferred);
|
||||||
|
|
||||||
|
private class TestPlayfield : Playfield
|
||||||
|
{
|
||||||
|
public TestPlayfield()
|
||||||
|
{
|
||||||
|
RegisterPool<TestHitObject, TestDrawableHitObject>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void AddNested(Playfield playfield)
|
||||||
|
{
|
||||||
|
AddInternal(playfield);
|
||||||
|
base.AddNested(playfield);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject)
|
||||||
|
{
|
||||||
|
var entry = base.CreateLifetimeEntry(hitObject);
|
||||||
|
entry.KeepAlive = true;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHitObject : HitObject
|
||||||
|
{
|
||||||
|
public override string ToString() => "TestHitObject";
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawableHitObject : DrawableHitObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawable : Drawable
|
||||||
|
{
|
||||||
|
public new void Schedule(Action action) => base.Schedule(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -45,15 +45,16 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
AddStep("Create DHO", () =>
|
AddStep("Create DHO", () =>
|
||||||
{
|
{
|
||||||
dho = new TestDrawableHitObject(null);
|
dho = new TestDrawableHitObject(null);
|
||||||
dho.Apply(entry = new TestLifetimeEntry(new HitObject())
|
dho.Apply(entry = new TestLifetimeEntry(new HitObject()));
|
||||||
{
|
|
||||||
LifetimeStart = 0,
|
|
||||||
LifetimeEnd = 1000,
|
|
||||||
});
|
|
||||||
Child = dho;
|
Child = dho;
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("KeepAlive = true", () => entry.KeepAlive = true);
|
AddStep("KeepAlive = true", () =>
|
||||||
|
{
|
||||||
|
entry.LifetimeStart = 0;
|
||||||
|
entry.LifetimeEnd = 1000;
|
||||||
|
entry.KeepAlive = true;
|
||||||
|
});
|
||||||
AddAssert("Lifetime is overriden", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == double.MaxValue);
|
AddAssert("Lifetime is overriden", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == double.MaxValue);
|
||||||
|
|
||||||
AddStep("Set LifetimeStart", () => dho.LifetimeStart = 500);
|
AddStep("Set LifetimeStart", () => dho.LifetimeStart = 500);
|
||||||
|
@ -146,7 +146,7 @@ namespace osu.Game.Tests.Mods
|
|||||||
if (isValid)
|
if (isValid)
|
||||||
Assert.IsNull(invalid);
|
Assert.IsNull(invalid);
|
||||||
else
|
else
|
||||||
Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
Assert.That(invalid.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class CustomMod1 : Mod
|
public abstract class CustomMod1 : Mod
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Tests.Visual.Multiplayer;
|
using osu.Game.Tests.Visual.Multiplayer;
|
||||||
@ -34,7 +35,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
|||||||
changeState(6, MultiplayerUserState.WaitingForLoad);
|
changeState(6, MultiplayerUserState.WaitingForLoad);
|
||||||
checkPlayingUserCount(6);
|
checkPlayingUserCount(6);
|
||||||
|
|
||||||
AddStep("another user left", () => Client.RemoveUser(Client.Room?.Users.Last().User));
|
AddStep("another user left", () => Client.RemoveUser((Client.Room?.Users.Last().User).AsNonNull()));
|
||||||
checkPlayingUserCount(5);
|
checkPlayingUserCount(5);
|
||||||
|
|
||||||
AddStep("leave room", () => Client.LeaveRoom());
|
AddStep("leave room", () => Client.LeaveRoom());
|
||||||
@ -53,9 +54,9 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
|||||||
Client.RoomSetupAction = room =>
|
Client.RoomSetupAction = room =>
|
||||||
{
|
{
|
||||||
room.State = MultiplayerRoomState.Playing;
|
room.State = MultiplayerRoomState.Playing;
|
||||||
room.Users.Add(new MultiplayerRoomUser(55)
|
room.Users.Add(new MultiplayerRoomUser(PLAYER_1_ID)
|
||||||
{
|
{
|
||||||
User = new User { Id = 55 },
|
User = new User { Id = PLAYER_1_ID },
|
||||||
State = MultiplayerUserState.Playing
|
State = MultiplayerUserState.Playing
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
223
osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs
Normal file
223
osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.OnlinePlay
|
||||||
|
{
|
||||||
|
[HeadlessTest]
|
||||||
|
public class TestSceneCatchUpSyncManager : OsuTestScene
|
||||||
|
{
|
||||||
|
private TestManualClock master;
|
||||||
|
private CatchUpSyncManager syncManager;
|
||||||
|
|
||||||
|
private TestSpectatorPlayerClock player1;
|
||||||
|
private TestSpectatorPlayerClock player2;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
syncManager = new CatchUpSyncManager(master = new TestManualClock());
|
||||||
|
syncManager.AddPlayerClock(player1 = new TestSpectatorPlayerClock(1));
|
||||||
|
syncManager.AddPlayerClock(player2 = new TestSpectatorPlayerClock(2));
|
||||||
|
|
||||||
|
Schedule(() => Child = syncManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMasterClockStartsWhenAllPlayerClocksHaveFrames()
|
||||||
|
{
|
||||||
|
setWaiting(() => player1, false);
|
||||||
|
assertMasterState(false);
|
||||||
|
assertPlayerClockState(() => player1, false);
|
||||||
|
assertPlayerClockState(() => player2, false);
|
||||||
|
|
||||||
|
setWaiting(() => player2, false);
|
||||||
|
assertMasterState(true);
|
||||||
|
assertPlayerClockState(() => player1, true);
|
||||||
|
assertPlayerClockState(() => player2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMasterClockDoesNotStartWhenNoneReadyForMaximumDelayTime()
|
||||||
|
{
|
||||||
|
AddWaitStep($"wait {CatchUpSyncManager.MAXIMUM_START_DELAY} milliseconds", (int)Math.Ceiling(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction));
|
||||||
|
assertMasterState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMasterClockStartsWhenAnyReadyForMaximumDelayTime()
|
||||||
|
{
|
||||||
|
setWaiting(() => player1, false);
|
||||||
|
AddWaitStep($"wait {CatchUpSyncManager.MAXIMUM_START_DELAY} milliseconds", (int)Math.Ceiling(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction));
|
||||||
|
assertMasterState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerClockDoesNotCatchUpWhenSlightlyOutOfSync()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
setMasterTime(CatchUpSyncManager.SYNC_TARGET + 1);
|
||||||
|
assertCatchingUp(() => player1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerClockStartsCatchingUpWhenTooFarBehind()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 1);
|
||||||
|
assertCatchingUp(() => player1, true);
|
||||||
|
assertCatchingUp(() => player2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerClockKeepsCatchingUpWhenSlightlyOutOfSync()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 1);
|
||||||
|
setPlayerClockTime(() => player1, CatchUpSyncManager.SYNC_TARGET + 1);
|
||||||
|
assertCatchingUp(() => player1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerClockStopsCatchingUpWhenInSync()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 2);
|
||||||
|
setPlayerClockTime(() => player1, CatchUpSyncManager.SYNC_TARGET);
|
||||||
|
assertCatchingUp(() => player1, false);
|
||||||
|
assertCatchingUp(() => player2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerClockDoesNotStopWhenSlightlyAhead()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
setPlayerClockTime(() => player1, -CatchUpSyncManager.SYNC_TARGET);
|
||||||
|
assertCatchingUp(() => player1, false);
|
||||||
|
assertPlayerClockState(() => player1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerClockStopsWhenTooFarAheadAndStartsWhenBackInSync()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
setPlayerClockTime(() => player1, -CatchUpSyncManager.SYNC_TARGET - 1);
|
||||||
|
|
||||||
|
// This is a silent catchup, where IsCatchingUp = false but IsRunning = false also.
|
||||||
|
assertCatchingUp(() => player1, false);
|
||||||
|
assertPlayerClockState(() => player1, false);
|
||||||
|
|
||||||
|
setMasterTime(1);
|
||||||
|
assertCatchingUp(() => player1, false);
|
||||||
|
assertPlayerClockState(() => player1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInSyncPlayerClockDoesNotStartIfWaitingOnFrames()
|
||||||
|
{
|
||||||
|
setAllWaiting(false);
|
||||||
|
|
||||||
|
assertPlayerClockState(() => player1, true);
|
||||||
|
setWaiting(() => player1, true);
|
||||||
|
assertPlayerClockState(() => player1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setWaiting(Func<TestSpectatorPlayerClock> playerClock, bool waiting)
|
||||||
|
=> AddStep($"set player clock {playerClock().Id} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting);
|
||||||
|
|
||||||
|
private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () =>
|
||||||
|
{
|
||||||
|
player1.WaitingOnFrames.Value = waiting;
|
||||||
|
player2.WaitingOnFrames.Value = waiting;
|
||||||
|
});
|
||||||
|
|
||||||
|
private void setMasterTime(double time)
|
||||||
|
=> AddStep($"set master = {time}", () => master.Seek(time));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// clock.Time = master.Time - offsetFromMaster
|
||||||
|
/// </summary>
|
||||||
|
private void setPlayerClockTime(Func<TestSpectatorPlayerClock> playerClock, double offsetFromMaster)
|
||||||
|
=> AddStep($"set player clock {playerClock().Id} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster));
|
||||||
|
|
||||||
|
private void assertMasterState(bool running)
|
||||||
|
=> AddAssert($"master clock {(running ? "is" : "is not")} running", () => master.IsRunning == running);
|
||||||
|
|
||||||
|
private void assertCatchingUp(Func<TestSpectatorPlayerClock> playerClock, bool catchingUp) =>
|
||||||
|
AddAssert($"player clock {playerClock().Id} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp);
|
||||||
|
|
||||||
|
private void assertPlayerClockState(Func<TestSpectatorPlayerClock> playerClock, bool running)
|
||||||
|
=> AddAssert($"player clock {playerClock().Id} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running);
|
||||||
|
|
||||||
|
private class TestSpectatorPlayerClock : TestManualClock, ISpectatorPlayerClock
|
||||||
|
{
|
||||||
|
public Bindable<bool> WaitingOnFrames { get; } = new Bindable<bool>(true);
|
||||||
|
|
||||||
|
public bool IsCatchingUp { get; set; }
|
||||||
|
|
||||||
|
public IFrameBasedClock Source
|
||||||
|
{
|
||||||
|
set => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly int Id;
|
||||||
|
|
||||||
|
public TestSpectatorPlayerClock(int id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
|
||||||
|
WaitingOnFrames.BindValueChanged(waiting =>
|
||||||
|
{
|
||||||
|
if (waiting.NewValue)
|
||||||
|
Stop();
|
||||||
|
else
|
||||||
|
Start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessFrame()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ElapsedFrameTime => 0;
|
||||||
|
|
||||||
|
public double FramesPerSecond => 0;
|
||||||
|
|
||||||
|
public FrameTimeInfo TimeInfo => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestManualClock : ManualClock, IAdjustableClock
|
||||||
|
{
|
||||||
|
public void Start() => IsRunning = true;
|
||||||
|
|
||||||
|
public void Stop() => IsRunning = false;
|
||||||
|
|
||||||
|
public bool Seek(double position)
|
||||||
|
{
|
||||||
|
CurrentTime = position;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetSpeedAdjustments()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,26 @@
|
|||||||
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Editing
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
{
|
{
|
||||||
public class TestSceneComposeSelectBox : OsuTestScene
|
public class TestSceneComposeSelectBox : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private Container selectionArea;
|
private Container selectionArea;
|
||||||
|
private SelectionBox selectionBox;
|
||||||
|
|
||||||
public TestSceneComposeSelectBox()
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
SelectionBox selectionBox = null;
|
|
||||||
|
|
||||||
AddStep("create box", () =>
|
|
||||||
Child = selectionArea = new Container
|
Child = selectionArea = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(400),
|
Size = new Vector2(400),
|
||||||
@ -26,6 +30,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
selectionBox = new SelectionBox
|
selectionBox = new SelectionBox
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
|
||||||
CanRotate = true,
|
CanRotate = true,
|
||||||
CanScaleX = true,
|
CanScaleX = true,
|
||||||
CanScaleY = true,
|
CanScaleY = true,
|
||||||
@ -34,12 +40,11 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
OnScale = handleScale
|
OnScale = handleScale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
AddToggleStep("toggle rotation", state => selectionBox.CanRotate = state);
|
InputManager.MoveMouseTo(selectionBox);
|
||||||
AddToggleStep("toggle x", state => selectionBox.CanScaleX = state);
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
AddToggleStep("toggle y", state => selectionBox.CanScaleY = state);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private bool handleScale(Vector2 amount, Anchor reference)
|
private bool handleScale(Vector2 amount, Anchor reference)
|
||||||
{
|
{
|
||||||
@ -68,5 +73,115 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
selectionArea.Rotation += angle;
|
selectionArea.Rotation += angle;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRotationHandleShownOnHover()
|
||||||
|
{
|
||||||
|
SelectionBoxRotationHandle rotationHandle = null;
|
||||||
|
|
||||||
|
AddStep("retrieve rotation handle", () => rotationHandle = this.ChildrenOfType<SelectionBoxRotationHandle>().First());
|
||||||
|
|
||||||
|
AddAssert("handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
AddStep("hover over handle", () => InputManager.MoveMouseTo(rotationHandle));
|
||||||
|
AddUntilStep("rotation handle shown", () => rotationHandle.Alpha == 1);
|
||||||
|
|
||||||
|
AddStep("move mouse away", () => InputManager.MoveMouseTo(selectionBox));
|
||||||
|
AddUntilStep("handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRotationHandleShownOnHoveringClosestScaleHandler()
|
||||||
|
{
|
||||||
|
SelectionBoxRotationHandle rotationHandle = null;
|
||||||
|
|
||||||
|
AddStep("retrieve rotation handle", () => rotationHandle = this.ChildrenOfType<SelectionBoxRotationHandle>().First());
|
||||||
|
|
||||||
|
AddAssert("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
AddStep("hover over closest scale handle", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == rotationHandle.Anchor));
|
||||||
|
});
|
||||||
|
AddUntilStep("rotation handle shown", () => rotationHandle.Alpha == 1);
|
||||||
|
|
||||||
|
AddStep("move mouse away", () => InputManager.MoveMouseTo(selectionBox));
|
||||||
|
AddUntilStep("handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHoverRotationHandleFromScaleHandle()
|
||||||
|
{
|
||||||
|
SelectionBoxRotationHandle rotationHandle = null;
|
||||||
|
|
||||||
|
AddStep("retrieve rotation handle", () => rotationHandle = this.ChildrenOfType<SelectionBoxRotationHandle>().First());
|
||||||
|
|
||||||
|
AddAssert("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
AddStep("hover over closest scale handle", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == rotationHandle.Anchor));
|
||||||
|
});
|
||||||
|
AddUntilStep("rotation handle shown", () => rotationHandle.Alpha == 1);
|
||||||
|
AddAssert("rotation handle not hovered", () => !rotationHandle.IsHovered);
|
||||||
|
|
||||||
|
AddStep("hover over rotation handle", () => InputManager.MoveMouseTo(rotationHandle));
|
||||||
|
AddAssert("rotation handle still shown", () => rotationHandle.Alpha == 1);
|
||||||
|
AddAssert("rotation handle hovered", () => rotationHandle.IsHovered);
|
||||||
|
|
||||||
|
AddStep("move mouse away", () => InputManager.MoveMouseTo(selectionBox));
|
||||||
|
AddUntilStep("handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHoldingScaleHandleHidesCorrespondingRotationHandle()
|
||||||
|
{
|
||||||
|
SelectionBoxRotationHandle rotationHandle = null;
|
||||||
|
|
||||||
|
AddStep("retrieve rotation handle", () => rotationHandle = this.ChildrenOfType<SelectionBoxRotationHandle>().First());
|
||||||
|
|
||||||
|
AddAssert("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
AddStep("hover over closest scale handle", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == rotationHandle.Anchor));
|
||||||
|
});
|
||||||
|
AddUntilStep("rotation handle shown", () => rotationHandle.Alpha == 1);
|
||||||
|
AddStep("hold scale handle", () => InputManager.PressButton(MouseButton.Left));
|
||||||
|
AddUntilStep("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
ScheduledDelegate mouseMove = null;
|
||||||
|
|
||||||
|
AddStep("start dragging", () =>
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
mouseMove = Scheduler.AddDelayed(() =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(selectionBox.ScreenSpaceDrawQuad.TopLeft + Vector2.One * (5 * ++i));
|
||||||
|
}, 100, true);
|
||||||
|
});
|
||||||
|
AddAssert("rotation handle still hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
|
||||||
|
AddStep("end dragging", () => mouseMove.Cancel());
|
||||||
|
AddAssert("rotation handle still hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
AddStep("unhold left", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
|
AddUntilStep("rotation handle shown", () => rotationHandle.Alpha == 1);
|
||||||
|
AddStep("move mouse away", () => InputManager.MoveMouseTo(selectionBox, new Vector2(20)));
|
||||||
|
AddUntilStep("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests that hovering over two handles instantaneously from one to another does not crash or cause issues to the visibility state.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestHoverOverTwoHandlesInstantaneously()
|
||||||
|
{
|
||||||
|
AddStep("hover over top-left scale handle", () =>
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == Anchor.TopLeft)));
|
||||||
|
AddStep("hover over top-right scale handle", () =>
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == Anchor.TopRight)));
|
||||||
|
AddUntilStep("top-left rotation handle hidden", () =>
|
||||||
|
this.ChildrenOfType<SelectionBoxRotationHandle>().Single(r => r.Anchor == Anchor.TopLeft).Alpha == 0);
|
||||||
|
AddUntilStep("top-right rotation handle shown", () =>
|
||||||
|
this.ChildrenOfType<SelectionBoxRotationHandle>().Single(r => r.Anchor == Anchor.TopRight).Alpha == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 100 },
|
new HitCircle { StartTime = 100 },
|
||||||
new HitCircle { StartTime = 200, Position = new Vector2(50) },
|
new HitCircle { StartTime = 200, Position = new Vector2(100) },
|
||||||
new HitCircle { StartTime = 300, Position = new Vector2(100) },
|
new HitCircle { StartTime = 300, Position = new Vector2(200) },
|
||||||
new HitCircle { StartTime = 400, Position = new Vector2(150) },
|
new HitCircle { StartTime = 400, Position = new Vector2(300) },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("select objects", () => EditorBeatmap.SelectedHitObjects.AddRange(addedObjects));
|
AddStep("select objects", () => EditorBeatmap.SelectedHitObjects.AddRange(addedObjects));
|
||||||
@ -95,9 +95,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
var addedObjects = new[]
|
var addedObjects = new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 100 },
|
new HitCircle { StartTime = 100 },
|
||||||
new HitCircle { StartTime = 200, Position = new Vector2(50) },
|
new HitCircle { StartTime = 200, Position = new Vector2(100) },
|
||||||
new HitCircle { StartTime = 300, Position = new Vector2(100) },
|
new HitCircle { StartTime = 300, Position = new Vector2(200) },
|
||||||
new HitCircle { StartTime = 400, Position = new Vector2(150) },
|
new HitCircle { StartTime = 400, Position = new Vector2(300) },
|
||||||
};
|
};
|
||||||
|
|
||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects));
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects));
|
||||||
@ -131,9 +131,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 100 },
|
new HitCircle { StartTime = 100 },
|
||||||
new HitCircle { StartTime = 200, Position = new Vector2(50) },
|
new HitCircle { StartTime = 200, Position = new Vector2(100) },
|
||||||
new HitCircle { StartTime = 300, Position = new Vector2(100) },
|
new HitCircle { StartTime = 300, Position = new Vector2(200) },
|
||||||
new HitCircle { StartTime = 400, Position = new Vector2(150) },
|
new HitCircle { StartTime = 400, Position = new Vector2(300) },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
moveMouseToObject(() => addedObjects[0]);
|
moveMouseToObject(() => addedObjects[0]);
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private void seekToBreak(int breakIndex)
|
private void seekToBreak(int breakIndex)
|
||||||
{
|
{
|
||||||
AddStep($"seek to break {breakIndex}", () => Player.GameplayClockContainer.Seek(destBreak().StartTime));
|
AddStep($"seek to break {breakIndex}", () => Player.GameplayClockContainer.Seek(destBreak().StartTime));
|
||||||
AddUntilStep("wait for seek to complete", () => Player.HUDOverlay.Progress.ReferenceClock.CurrentTime >= destBreak().StartTime);
|
AddUntilStep("wait for seek to complete", () => Player.DrawableRuleset.FrameStableClock.CurrentTime >= destBreak().StartTime);
|
||||||
|
|
||||||
BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
|
BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,35 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneComboCounter : SkinnableTestScene
|
public class TestSceneComboCounter : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableComboCounter> comboCounters => CreatedDrawables.OfType<SkinnableComboCounter>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create combo counters", () => SetContents(() =>
|
AddStep("Create combo counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ComboCounter))));
|
||||||
{
|
|
||||||
var comboCounter = new SkinnableComboCounter();
|
|
||||||
comboCounter.Current.Value = 1;
|
|
||||||
return comboCounter;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestComboCounterIncrementing()
|
public void TestComboCounterIncrementing()
|
||||||
{
|
{
|
||||||
AddRepeatStep("increase combo", () =>
|
AddRepeatStep("increase combo", () => scoreProcessor.Combo.Value++, 10);
|
||||||
{
|
|
||||||
foreach (var counter in comboCounters)
|
|
||||||
counter.Current.Value++;
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
AddStep("reset combo", () =>
|
AddStep("reset combo", () => scoreProcessor.Combo.Value = 0);
|
||||||
{
|
|
||||||
foreach (var counter in comboCounters)
|
|
||||||
counter.Current.Value = 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +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.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -20,24 +23,28 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
[SetUpSteps]
|
private void create(HealthProcessor healthProcessor)
|
||||||
public void SetUpSteps()
|
|
||||||
{
|
{
|
||||||
AddStep("create layer", () =>
|
AddStep("create layer", () =>
|
||||||
{
|
{
|
||||||
Child = layer = new FailingLayer();
|
Child = new HealthProcessorContainer(healthProcessor)
|
||||||
layer.BindHealthProcessor(new DrainingHealthProcessor(1));
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = layer = new FailingLayer()
|
||||||
|
};
|
||||||
|
|
||||||
layer.ShowHealth.BindTo(showHealth);
|
layer.ShowHealth.BindTo(showHealth);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("show health", () => showHealth.Value = true);
|
AddStep("show health", () => showHealth.Value = true);
|
||||||
AddStep("enable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
AddStep("enable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||||
AddUntilStep("layer is visible", () => layer.IsPresent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLayerFading()
|
public void TestLayerFading()
|
||||||
{
|
{
|
||||||
|
create(new DrainingHealthProcessor(0));
|
||||||
|
|
||||||
AddSliderStep("current health", 0.0, 1.0, 1.0, val =>
|
AddSliderStep("current health", 0.0, 1.0, 1.0, val =>
|
||||||
{
|
{
|
||||||
if (layer != null)
|
if (layer != null)
|
||||||
@ -45,14 +52,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||||
AddUntilStep("layer fade is visible", () => layer.Child.Alpha > 0.1f);
|
AddUntilStep("layer fade is visible", () => layer.ChildrenOfType<Container>().First().Alpha > 0.1f);
|
||||||
AddStep("set health to 1", () => layer.Current.Value = 1f);
|
AddStep("set health to 1", () => layer.Current.Value = 1f);
|
||||||
AddUntilStep("layer fade is invisible", () => !layer.Child.IsPresent);
|
AddUntilStep("layer fade is invisible", () => !layer.ChildrenOfType<Container>().First().IsPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLayerDisabledViaConfig()
|
public void TestLayerDisabledViaConfig()
|
||||||
{
|
{
|
||||||
|
create(new DrainingHealthProcessor(0));
|
||||||
|
AddUntilStep("layer is visible", () => layer.IsPresent);
|
||||||
AddStep("disable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
AddStep("disable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||||
AddUntilStep("layer is not visible", () => !layer.IsPresent);
|
AddUntilStep("layer is not visible", () => !layer.IsPresent);
|
||||||
@ -61,7 +70,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLayerVisibilityWithAccumulatingProcessor()
|
public void TestLayerVisibilityWithAccumulatingProcessor()
|
||||||
{
|
{
|
||||||
AddStep("bind accumulating processor", () => layer.BindHealthProcessor(new AccumulatingHealthProcessor(1)));
|
create(new AccumulatingHealthProcessor(1));
|
||||||
|
AddUntilStep("layer is not visible", () => !layer.IsPresent);
|
||||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||||
AddUntilStep("layer is not visible", () => !layer.IsPresent);
|
AddUntilStep("layer is not visible", () => !layer.IsPresent);
|
||||||
}
|
}
|
||||||
@ -69,7 +79,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLayerVisibilityWithDrainingProcessor()
|
public void TestLayerVisibilityWithDrainingProcessor()
|
||||||
{
|
{
|
||||||
AddStep("bind accumulating processor", () => layer.BindHealthProcessor(new DrainingHealthProcessor(1)));
|
create(new DrainingHealthProcessor(0));
|
||||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||||
AddWaitStep("wait for potential fade", 10);
|
AddWaitStep("wait for potential fade", 10);
|
||||||
AddAssert("layer is still visible", () => layer.IsPresent);
|
AddAssert("layer is still visible", () => layer.IsPresent);
|
||||||
@ -78,6 +88,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLayerVisibilityWithDifferentOptions()
|
public void TestLayerVisibilityWithDifferentOptions()
|
||||||
{
|
{
|
||||||
|
create(new DrainingHealthProcessor(0));
|
||||||
|
|
||||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||||
|
|
||||||
AddStep("don't show health", () => showHealth.Value = false);
|
AddStep("don't show health", () => showHealth.Value = false);
|
||||||
@ -96,5 +108,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||||
AddUntilStep("layer fade is visible", () => layer.IsPresent);
|
AddUntilStep("layer fade is visible", () => layer.IsPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class HealthProcessorContainer : Container
|
||||||
|
{
|
||||||
|
[Cached(typeof(HealthProcessor))]
|
||||||
|
private readonly HealthProcessor healthProcessor;
|
||||||
|
|
||||||
|
public HealthProcessorContainer(HealthProcessor healthProcessor)
|
||||||
|
{
|
||||||
|
this.healthProcessor = healthProcessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
@ -19,6 +20,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
private HUDOverlay hudOverlay;
|
private HUDOverlay hudOverlay;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
|
|
||||||
|
[Cached(typeof(HealthProcessor))]
|
||||||
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
|
|
||||||
// best way to check without exposing.
|
// best way to check without exposing.
|
||||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||||
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
|
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
|
||||||
@ -31,9 +38,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
createNew();
|
createNew();
|
||||||
|
|
||||||
AddRepeatStep("increase combo", () => { hudOverlay.ComboCounter.Current.Value++; }, 10);
|
AddRepeatStep("increase combo", () => { scoreProcessor.Combo.Value++; }, 10);
|
||||||
|
|
||||||
AddStep("reset combo", () => { hudOverlay.ComboCounter.Current.Value = 0; });
|
AddStep("reset combo", () => { scoreProcessor.Combo.Value = 0; });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -139,12 +146,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddStep("create overlay", () =>
|
AddStep("create overlay", () =>
|
||||||
{
|
{
|
||||||
hudOverlay = new HUDOverlay(null, null, null, Array.Empty<Mod>());
|
hudOverlay = new HUDOverlay(null, Array.Empty<Mod>());
|
||||||
|
|
||||||
// Add any key just to display the key counter visually.
|
// Add any key just to display the key counter visually.
|
||||||
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
||||||
|
|
||||||
hudOverlay.ComboCounter.Current.Value = 1;
|
scoreProcessor.Combo.Value = 1;
|
||||||
|
|
||||||
action?.Invoke(hudOverlay);
|
action?.Invoke(hudOverlay);
|
||||||
|
|
||||||
|
@ -1,32 +1,39 @@
|
|||||||
// 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 System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Catch.Scoring;
|
using osu.Game.Rulesets.Catch.Scoring;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Scoring;
|
using osu.Game.Rulesets.Taiko.Scoring;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneHitErrorMeter : OsuTestScene
|
public class TestSceneHitErrorMeter : OsuTestScene
|
||||||
{
|
{
|
||||||
private BarHitErrorMeter barMeter;
|
[Cached]
|
||||||
private BarHitErrorMeter barMeter2;
|
private ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
private BarHitErrorMeter barMeter3;
|
|
||||||
private ColourHitErrorMeter colourMeter;
|
[Cached(typeof(DrawableRuleset))]
|
||||||
private ColourHitErrorMeter colourMeter2;
|
private TestDrawableRuleset drawableRuleset = new TestDrawableRuleset();
|
||||||
private ColourHitErrorMeter colourMeter3;
|
|
||||||
private HitWindows hitWindows;
|
|
||||||
|
|
||||||
public TestSceneHitErrorMeter()
|
public TestSceneHitErrorMeter()
|
||||||
{
|
{
|
||||||
@ -34,8 +41,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddRepeatStep("New random judgement", () => newJudgement(), 40);
|
AddRepeatStep("New random judgement", () => newJudgement(), 40);
|
||||||
|
|
||||||
AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20);
|
AddRepeatStep("New max negative", () => newJudgement(-drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
|
||||||
AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20);
|
AddRepeatStep("New max positive", () => newJudgement(drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
|
||||||
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
|
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
|
||||||
|
|
||||||
AddStep("Judgement barrage", () =>
|
AddStep("Judgement barrage", () =>
|
||||||
@ -85,10 +92,10 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
|
private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
|
||||||
{
|
{
|
||||||
this.hitWindows = hitWindows;
|
|
||||||
|
|
||||||
hitWindows?.SetDifficulty(overallDifficulty);
|
hitWindows?.SetDifficulty(overallDifficulty);
|
||||||
|
|
||||||
|
drawableRuleset.HitWindows = hitWindows;
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
Add(new FillFlowContainer
|
Add(new FillFlowContainer
|
||||||
@ -105,40 +112,40 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(barMeter = new BarHitErrorMeter(hitWindows, true)
|
Add(new BarHitErrorMeter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(barMeter2 = new BarHitErrorMeter(hitWindows, false)
|
Add(new BarHitErrorMeter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(barMeter3 = new BarHitErrorMeter(hitWindows, true)
|
Add(new BarHitErrorMeter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Rotation = 270,
|
Rotation = 270,
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(colourMeter = new ColourHitErrorMeter(hitWindows)
|
Add(new ColourHitErrorMeter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
Margin = new MarginPadding { Right = 50 }
|
Margin = new MarginPadding { Right = 50 }
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(colourMeter2 = new ColourHitErrorMeter(hitWindows)
|
Add(new ColourHitErrorMeter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Margin = new MarginPadding { Left = 50 }
|
Margin = new MarginPadding { Left = 50 }
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(colourMeter3 = new ColourHitErrorMeter(hitWindows)
|
Add(new ColourHitErrorMeter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
@ -149,18 +156,47 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private void newJudgement(double offset = 0)
|
private void newJudgement(double offset = 0)
|
||||||
{
|
{
|
||||||
var judgement = new JudgementResult(new HitObject(), new Judgement())
|
scoreProcessor.ApplyResult(new JudgementResult(new HitCircle { HitWindows = drawableRuleset.HitWindows }, new Judgement())
|
||||||
{
|
{
|
||||||
TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset,
|
TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset,
|
||||||
Type = HitResult.Perfect,
|
Type = HitResult.Perfect,
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
barMeter.OnNewJudgement(judgement);
|
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
|
||||||
barMeter2.OnNewJudgement(judgement);
|
private class TestDrawableRuleset : DrawableRuleset
|
||||||
barMeter3.OnNewJudgement(judgement);
|
{
|
||||||
colourMeter.OnNewJudgement(judgement);
|
public HitWindows HitWindows;
|
||||||
colourMeter2.OnNewJudgement(judgement);
|
|
||||||
colourMeter3.OnNewJudgement(judgement);
|
public override IEnumerable<HitObject> Objects => new[] { new HitCircle { HitWindows = HitWindows } };
|
||||||
|
|
||||||
|
public override event Action<JudgementResult> NewResult;
|
||||||
|
public override event Action<JudgementResult> RevertResult;
|
||||||
|
|
||||||
|
public override Playfield Playfield { get; }
|
||||||
|
public override Container Overlays { get; }
|
||||||
|
public override Container FrameStableComponents { get; }
|
||||||
|
public override IFrameStableClock FrameStableClock { get; }
|
||||||
|
public override IReadOnlyList<Mod> Mods { get; }
|
||||||
|
|
||||||
|
public override double GameplayStartTime { get; }
|
||||||
|
public override GameplayCursorContainer Cursor { get; }
|
||||||
|
|
||||||
|
public TestDrawableRuleset()
|
||||||
|
: base(new OsuRuleset())
|
||||||
|
{
|
||||||
|
// won't compile without this.
|
||||||
|
NewResult?.Invoke(null);
|
||||||
|
RevertResult?.Invoke(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetReplayScore(Score replayScore) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override void SetRecordTarget(Score score) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override void RequestResume(Action continueResume) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override void CancelResume() => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
// 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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Skinning.Editor;
|
using osu.Game.Skinning.Editor;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
@ -13,14 +16,20 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
private SkinEditor skinEditor;
|
private SkinEditor skinEditor;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private SkinManager skinManager { get; set; }
|
||||||
|
|
||||||
|
protected override bool Autoplay => true;
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public override void SetUpSteps()
|
public override void SetUpSteps()
|
||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
|
|
||||||
AddStep("add editor overlay", () =>
|
AddStep("reload skin editor", () =>
|
||||||
{
|
{
|
||||||
skinEditor?.Expire();
|
skinEditor?.Expire();
|
||||||
|
Player.ScaleTo(SkinEditorOverlay.VISIBLE_TARGET_SCALE);
|
||||||
LoadComponentAsync(skinEditor = new SkinEditor(Player), Add);
|
LoadComponentAsync(skinEditor = new SkinEditor(Player), Add);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Skinning.Editor;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public class TestSceneSkinEditorComponentsList : SkinnableTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestToggleEditor()
|
||||||
|
{
|
||||||
|
AddStep("show available components", () => SetContents(() => new SkinComponentToolbox(300)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
// 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.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -17,6 +16,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestSceneSkinEditorMultipleSkins : SkinnableTestScene
|
public class TestSceneSkinEditorMultipleSkins : SkinnableTestScene
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
|
|
||||||
|
[Cached(typeof(HealthProcessor))]
|
||||||
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
@ -25,14 +30,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
SetContents(() =>
|
SetContents(() =>
|
||||||
{
|
{
|
||||||
var ruleset = new OsuRuleset();
|
var ruleset = new OsuRuleset();
|
||||||
|
var mods = new[] { ruleset.GetAutoplayMod() };
|
||||||
var working = CreateWorkingBeatmap(ruleset.RulesetInfo);
|
var working = CreateWorkingBeatmap(ruleset.RulesetInfo);
|
||||||
var beatmap = working.GetPlayableBeatmap(ruleset.RulesetInfo);
|
var beatmap = working.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
|
||||||
|
|
||||||
ScoreProcessor scoreProcessor = new ScoreProcessor();
|
var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap, mods);
|
||||||
|
|
||||||
var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap);
|
var hudOverlay = new HUDOverlay(drawableRuleset, mods)
|
||||||
|
|
||||||
var hudOverlay = new HUDOverlay(scoreProcessor, null, drawableRuleset, Array.Empty<Mod>())
|
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -40,7 +44,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
// Add any key just to display the key counter visually.
|
// Add any key just to display the key counter visually.
|
||||||
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
||||||
hudOverlay.ComboCounter.Current.Value = 1;
|
scoreProcessor.Combo.Value = 1;
|
||||||
|
|
||||||
return new Container
|
return new Container
|
||||||
{
|
{
|
||||||
|
@ -1,49 +1,36 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene
|
public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableAccuracyCounter> accuracyCounters => CreatedDrawables.OfType<SkinnableAccuracyCounter>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create combo counters", () => SetContents(() =>
|
AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1);
|
||||||
{
|
AddStep("Create accuracy counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter))));
|
||||||
var accuracyCounter = new SkinnableAccuracyCounter();
|
|
||||||
|
|
||||||
accuracyCounter.Current.Value = 1;
|
|
||||||
|
|
||||||
return accuracyCounter;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestChangingAccuracy()
|
public void TestChangingAccuracy()
|
||||||
{
|
{
|
||||||
AddStep(@"Reset all", delegate
|
AddStep(@"Reset all", () => scoreProcessor.Accuracy.Value = 1);
|
||||||
{
|
|
||||||
foreach (var s in accuracyCounters)
|
|
||||||
s.Current.Value = 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
AddStep(@"Hit! :D", delegate
|
AddStep(@"Miss :(", () => scoreProcessor.Accuracy.Value -= 0.023);
|
||||||
{
|
|
||||||
foreach (var s in accuracyCounters)
|
|
||||||
s.Current.Value -= 0.023f;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
@ -23,6 +24,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
private HUDOverlay hudOverlay;
|
private HUDOverlay hudOverlay;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
|
|
||||||
|
[Cached(typeof(HealthProcessor))]
|
||||||
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
|
|
||||||
private IEnumerable<HUDOverlay> hudOverlays => CreatedDrawables.OfType<HUDOverlay>();
|
private IEnumerable<HUDOverlay> hudOverlays => CreatedDrawables.OfType<HUDOverlay>();
|
||||||
|
|
||||||
// best way to check without exposing.
|
// best way to check without exposing.
|
||||||
@ -37,17 +44,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
createNew();
|
createNew();
|
||||||
|
|
||||||
AddRepeatStep("increase combo", () =>
|
AddRepeatStep("increase combo", () => scoreProcessor.Combo.Value++, 10);
|
||||||
{
|
|
||||||
foreach (var hud in hudOverlays)
|
|
||||||
hud.ComboCounter.Current.Value++;
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
AddStep("reset combo", () =>
|
AddStep("reset combo", () => scoreProcessor.Combo.Value = 0);
|
||||||
{
|
|
||||||
foreach (var hud in hudOverlays)
|
|
||||||
hud.ComboCounter.Current.Value = 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -80,13 +79,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
SetContents(() =>
|
SetContents(() =>
|
||||||
{
|
{
|
||||||
hudOverlay = new HUDOverlay(null, null, null, Array.Empty<Mod>());
|
hudOverlay = new HUDOverlay(null, Array.Empty<Mod>());
|
||||||
|
|
||||||
// Add any key just to display the key counter visually.
|
// Add any key just to display the key counter visually.
|
||||||
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
||||||
|
|
||||||
hudOverlay.ComboCounter.Current.Value = 1;
|
|
||||||
|
|
||||||
action?.Invoke(hudOverlay);
|
action?.Invoke(hudOverlay);
|
||||||
|
|
||||||
return hudOverlay;
|
return hudOverlay;
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneSkinnableHealthDisplay : SkinnableTestScene
|
public class TestSceneSkinnableHealthDisplay : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableHealthDisplay> healthDisplays => CreatedDrawables.OfType<SkinnableHealthDisplay>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Cached(typeof(HealthProcessor))]
|
||||||
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create health displays", () =>
|
AddStep("Create health displays", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.HealthDisplay))));
|
||||||
{
|
|
||||||
SetContents(() => new SkinnableHealthDisplay());
|
|
||||||
});
|
|
||||||
AddStep(@"Reset all", delegate
|
AddStep(@"Reset all", delegate
|
||||||
{
|
{
|
||||||
foreach (var s in healthDisplays)
|
healthProcessor.Health.Value = 1;
|
||||||
s.Current.Value = 1;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,23 +36,21 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddRepeatStep(@"decrease hp", delegate
|
AddRepeatStep(@"decrease hp", delegate
|
||||||
{
|
{
|
||||||
foreach (var healthDisplay in healthDisplays)
|
healthProcessor.Health.Value -= 0.08f;
|
||||||
healthDisplay.Current.Value -= 0.08f;
|
|
||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
AddRepeatStep(@"increase hp without flash", delegate
|
AddRepeatStep(@"increase hp without flash", delegate
|
||||||
{
|
{
|
||||||
foreach (var healthDisplay in healthDisplays)
|
healthProcessor.Health.Value += 0.1f;
|
||||||
healthDisplay.Current.Value += 0.1f;
|
|
||||||
}, 3);
|
}, 3);
|
||||||
|
|
||||||
AddRepeatStep(@"increase hp with flash", delegate
|
AddRepeatStep(@"increase hp with flash", delegate
|
||||||
{
|
{
|
||||||
foreach (var healthDisplay in healthDisplays)
|
healthProcessor.Health.Value += 0.1f;
|
||||||
|
healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement())
|
||||||
{
|
{
|
||||||
healthDisplay.Current.Value += 0.1f;
|
Type = HitResult.Perfect
|
||||||
healthDisplay.Flash(new JudgementResult(null, new OsuJudgement()));
|
});
|
||||||
}
|
|
||||||
}, 3);
|
}, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,41 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneSkinnableScoreCounter : SkinnableTestScene
|
public class TestSceneSkinnableScoreCounter : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableScoreCounter> scoreCounters => CreatedDrawables.OfType<SkinnableScoreCounter>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor();
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create combo counters", () => SetContents(() =>
|
AddStep("Create score counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ScoreCounter))));
|
||||||
{
|
|
||||||
var comboCounter = new SkinnableScoreCounter();
|
|
||||||
comboCounter.Current.Value = 1;
|
|
||||||
return comboCounter;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestScoreCounterIncrementing()
|
public void TestScoreCounterIncrementing()
|
||||||
{
|
{
|
||||||
AddStep(@"Reset all", delegate
|
AddStep(@"Reset all", () => scoreProcessor.TotalScore.Value = 0);
|
||||||
{
|
|
||||||
foreach (var s in scoreCounters)
|
|
||||||
s.Current.Value = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
AddStep(@"Hit! :D", delegate
|
AddStep(@"Hit! :D", () => scoreProcessor.TotalScore.Value += 300);
|
||||||
{
|
|
||||||
foreach (var s in scoreCounters)
|
|
||||||
s.Current.Value += 300;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVeryLargeScore()
|
public void TestVeryLargeScore()
|
||||||
{
|
{
|
||||||
AddStep("set large score", () => scoreCounters.ForEach(counter => counter.Current.Value = 1_000_000_000));
|
AddStep("set large score", () => scoreProcessor.TotalScore.Value = 1_000_000_000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user