mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 09:22:54 +08:00
Fix merge conflicts.
This commit is contained in:
commit
00c1ff993a
@ -2,6 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu.Desktop/.idea/.idea.osu.Desktop.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu.Desktop/.idea/.idea.osu.Desktop.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu.Desktop/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu.Desktop/riderModule.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
|
@ -93,7 +93,7 @@ JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it
|
||||
|
||||
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time to ensure no effort is wasted.
|
||||
|
||||
If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) label).
|
||||
If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aopen+label%3Agood-first-issue+sort%3Aupdated-desc) label).
|
||||
|
||||
Before starting, please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
|
||||
|
||||
|
@ -97,8 +97,10 @@ platform :ios do
|
||||
changelog.gsub!('$BUILD_ID', options[:build])
|
||||
|
||||
pilot(
|
||||
wait_processing_interval: 1800,
|
||||
wait_processing_interval: 900,
|
||||
changelog: changelog,
|
||||
groups: ['osu! supporters', 'public'],
|
||||
distribute_external: true,
|
||||
ipa: './osu.iOS/bin/iPhone/Release/osu.iOS.ipa'
|
||||
)
|
||||
end
|
||||
|
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.312.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.319.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
new KeyBinding(InputKey.Shift, CatchAction.Dash),
|
||||
};
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new CatchModNightcore();
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
}
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
Position = currentFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
||||
Dashing = currentFrame.ButtonState == ReplayButtonState.Left1;
|
||||
@ -56,5 +56,14 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
Actions.Add(CatchAction.MoveLeft);
|
||||
}
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
ReplayButtonState state = ReplayButtonState.None;
|
||||
|
||||
if (Actions.Contains(CatchAction.Dash)) state |= ReplayButtonState.Left1;
|
||||
|
||||
return new LegacyReplayFrame(Time, Position * CatchPlayfield.BASE_WIDTH, null, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
Normal file
26
osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
Normal file
@ -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 System.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatchReplayRecorder : ReplayRecorder<CatchAction>
|
||||
{
|
||||
private readonly CatchPlayfield playfield;
|
||||
|
||||
public CatchReplayRecorder(Replay target, CatchPlayfield playfield)
|
||||
: base(target)
|
||||
{
|
||||
this.playfield = playfield;
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<CatchAction> actions, ReplayFrame previousFrame)
|
||||
=> new CatchReplayFrame(Time.Current, playfield.CatcherArea.MovableCatcher.X, actions.Contains(CatchAction.Dash), previousFrame as CatchReplayFrame);
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -55,14 +56,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate or deactive the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met.
|
||||
/// Activate or deactivate the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met.
|
||||
/// </summary>
|
||||
protected bool Trail
|
||||
{
|
||||
get => trail;
|
||||
set
|
||||
{
|
||||
if (value == trail) return;
|
||||
if (value == trail || AdditiveTarget == null) return;
|
||||
|
||||
trail = value;
|
||||
|
||||
@ -77,6 +78,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private CatcherSprite catcherKiai;
|
||||
private CatcherSprite catcherFail;
|
||||
|
||||
private CatcherSprite currentCatcher;
|
||||
|
||||
private int currentDirection;
|
||||
|
||||
private bool dashing;
|
||||
@ -236,10 +239,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
|
||||
Trail = true;
|
||||
|
||||
var hyperDashEndGlow = createAdditiveSprite(true);
|
||||
var hyperDashEndGlow = createAdditiveSprite();
|
||||
|
||||
hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In);
|
||||
hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In);
|
||||
hyperDashEndGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In);
|
||||
hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.95f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In);
|
||||
hyperDashEndGlow.FadeOut(1200);
|
||||
hyperDashEndGlow.Expire(true);
|
||||
}
|
||||
@ -358,39 +361,36 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private void updateCatcher()
|
||||
{
|
||||
catcherIdle.Hide();
|
||||
catcherKiai.Hide();
|
||||
catcherFail.Hide();
|
||||
|
||||
CatcherSprite current;
|
||||
currentCatcher?.Hide();
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
default:
|
||||
current = catcherIdle;
|
||||
currentCatcher = catcherIdle;
|
||||
break;
|
||||
|
||||
case CatcherAnimationState.Fail:
|
||||
current = catcherFail;
|
||||
currentCatcher = catcherFail;
|
||||
break;
|
||||
|
||||
case CatcherAnimationState.Kiai:
|
||||
current = catcherKiai;
|
||||
currentCatcher = catcherKiai;
|
||||
break;
|
||||
}
|
||||
|
||||
current.Show();
|
||||
(current.Drawable as IAnimation)?.GotoFrame(0);
|
||||
currentCatcher.Show();
|
||||
(currentCatcher.Drawable as IAnimation)?.GotoFrame(0);
|
||||
}
|
||||
|
||||
private void beginTrail()
|
||||
{
|
||||
Trail &= dashing || HyperDashing;
|
||||
Trail &= AdditiveTarget != null;
|
||||
if (!dashing && !HyperDashing)
|
||||
{
|
||||
Trail = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Trail) return;
|
||||
|
||||
var additive = createAdditiveSprite(HyperDashing);
|
||||
var additive = createAdditiveSprite();
|
||||
|
||||
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
|
||||
additive.Expire(true);
|
||||
@ -398,27 +398,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
|
||||
}
|
||||
|
||||
private Drawable createAdditiveSprite(bool hyperDash)
|
||||
{
|
||||
var additive = createCatcherSprite();
|
||||
|
||||
additive.Anchor = Anchor;
|
||||
additive.Scale = Scale;
|
||||
additive.Colour = hyperDash ? Color4.Red : Color4.White;
|
||||
additive.Blending = BlendingParameters.Additive;
|
||||
additive.RelativePositionAxes = RelativePositionAxes;
|
||||
additive.Position = Position;
|
||||
|
||||
AdditiveTarget.Add(additive);
|
||||
|
||||
return additive;
|
||||
}
|
||||
|
||||
private Drawable createCatcherSprite()
|
||||
{
|
||||
return new CatcherSprite(CurrentState);
|
||||
}
|
||||
|
||||
private void updateState(CatcherAnimationState state)
|
||||
{
|
||||
if (CurrentState == state)
|
||||
@ -428,6 +407,25 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
updateCatcher();
|
||||
}
|
||||
|
||||
private CatcherTrailSprite createAdditiveSprite()
|
||||
{
|
||||
var tex = (currentCatcher.Drawable as TextureAnimation)?.CurrentFrame ?? ((Sprite)currentCatcher.Drawable).Texture;
|
||||
|
||||
var sprite = new CatcherTrailSprite(tex)
|
||||
{
|
||||
Anchor = Anchor,
|
||||
Scale = Scale,
|
||||
Colour = HyperDashing ? Color4.Red : Color4.White,
|
||||
Blending = BlendingParameters.Additive,
|
||||
RelativePositionAxes = RelativePositionAxes,
|
||||
Position = Position
|
||||
};
|
||||
|
||||
AdditiveTarget?.Add(sprite);
|
||||
|
||||
return sprite;
|
||||
}
|
||||
|
||||
private void removeFromPlateWithTransform(DrawableHitObject fruit, Action<DrawableHitObject> action)
|
||||
{
|
||||
if (ExplodingFruitTarget != null)
|
||||
|
22
osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs
Normal file
22
osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatcherTrailSprite : Sprite
|
||||
{
|
||||
public CatcherTrailSprite(Texture texture)
|
||||
{
|
||||
Texture = texture;
|
||||
|
||||
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
||||
|
||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new CatchReplayRecorder(replay, (CatchPlayfield)Playfield);
|
||||
|
||||
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
||||
|
||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
}
|
||||
|
||||
protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
protected override KeyBindingContainer<ManiaAction> CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
=> new LocalKeyBindingContainer(ruleset, variant, unique);
|
||||
|
||||
private class LocalKeyBindingContainer : RulesetKeyBindingContainer
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new ManiaLegacySkinTransformer(source);
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new ManiaModNightcore();
|
||||
@ -118,6 +118,59 @@ namespace osu.Game.Rulesets.Mania
|
||||
yield return new ManiaModRandom();
|
||||
}
|
||||
|
||||
public override LegacyMods ConvertToLegacyMods(Mod[] mods)
|
||||
{
|
||||
var value = base.ConvertToLegacyMods(mods);
|
||||
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case ManiaModKey1 _:
|
||||
value |= LegacyMods.Key1;
|
||||
break;
|
||||
|
||||
case ManiaModKey2 _:
|
||||
value |= LegacyMods.Key2;
|
||||
break;
|
||||
|
||||
case ManiaModKey3 _:
|
||||
value |= LegacyMods.Key3;
|
||||
break;
|
||||
|
||||
case ManiaModKey4 _:
|
||||
value |= LegacyMods.Key4;
|
||||
break;
|
||||
|
||||
case ManiaModKey5 _:
|
||||
value |= LegacyMods.Key5;
|
||||
break;
|
||||
|
||||
case ManiaModKey6 _:
|
||||
value |= LegacyMods.Key6;
|
||||
break;
|
||||
|
||||
case ManiaModKey7 _:
|
||||
value |= LegacyMods.Key7;
|
||||
break;
|
||||
|
||||
case ManiaModKey8 _:
|
||||
value |= LegacyMods.Key8;
|
||||
break;
|
||||
|
||||
case ManiaModKey9 _:
|
||||
value |= LegacyMods.Key9;
|
||||
break;
|
||||
|
||||
case ManiaModFadeIn _:
|
||||
value |= LegacyMods.FadeIn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||
{
|
||||
switch (type)
|
||||
|
@ -3,24 +3,17 @@
|
||||
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModRandom : Mod, IApplicableToBeatmap
|
||||
public class ManiaModRandom : ModRandom, IApplicableToBeatmap
|
||||
{
|
||||
public override string Name => "Random";
|
||||
public override string Acronym => "RD";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override IconUsage? Icon => OsuIcon.Dice;
|
||||
public override string Description => @"Shuffle around the keys!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
// We don't need to fully convert, just create the converter
|
||||
var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
|
||||
@ -56,5 +56,42 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
activeColumns >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
int keys = 0;
|
||||
|
||||
var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
|
||||
|
||||
var stage = new StageDefinition { Columns = converter.TargetColumns };
|
||||
|
||||
var specialColumns = new List<int>();
|
||||
|
||||
for (int i = 0; i < converter.TargetColumns; i++)
|
||||
{
|
||||
if (stage.IsSpecialColumn(i))
|
||||
specialColumns.Add(i);
|
||||
}
|
||||
|
||||
foreach (var action in Actions)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ManiaAction.Special1:
|
||||
keys |= 1 << specialColumns[0];
|
||||
break;
|
||||
|
||||
case ManiaAction.Special2:
|
||||
keys |= 1 << specialColumns[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
keys |= 1 << (action - ManiaAction.Key1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new LegacyReplayFrame(Time, keys, null, ReplayButtonState.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,5 +88,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new ManiaReplayRecorder(replay);
|
||||
}
|
||||
}
|
||||
|
23
osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs
Normal file
23
osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaReplayRecorder : ReplayRecorder<ManiaAction>
|
||||
{
|
||||
public ManiaReplayRecorder(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<ManiaAction> actions, ReplayFrame previousFrame)
|
||||
=> new ManiaReplayFrame(Time.Current, actions.ToArray());
|
||||
}
|
||||
}
|
@ -4,48 +4,43 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneHitCircleArea : ManualInputManagerTestScene
|
||||
public class TestSceneHitCircleArea : OsuManualInputManagerTestScene
|
||||
{
|
||||
private HitCircle hitCircle;
|
||||
private DrawableHitCircle drawableHitCircle;
|
||||
private DrawableHitCircle.HitReceptor hitAreaReceptor => drawableHitCircle.HitArea;
|
||||
|
||||
[SetUp]
|
||||
public new void SetUp()
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
Schedule(() =>
|
||||
hitCircle = new HitCircle
|
||||
{
|
||||
hitCircle = new HitCircle
|
||||
{
|
||||
Position = new Vector2(100, 100),
|
||||
StartTime = Time.Current + 500
|
||||
};
|
||||
Position = new Vector2(100, 100),
|
||||
StartTime = Time.Current + 500
|
||||
};
|
||||
|
||||
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
Child = new SkinProvidingContainer(new DefaultSkin())
|
||||
Child = new SkinProvidingContainer(new DefaultSkin())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = drawableHitCircle = new DrawableHitCircle(hitCircle)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = drawableHitCircle = new DrawableHitCircle(hitCircle)
|
||||
{
|
||||
Size = new Vector2(100)
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
Size = new Vector2(100)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestCircleHitCentre()
|
||||
|
@ -23,7 +23,7 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneOsuDistanceSnapGrid : ManualInputManagerTestScene
|
||||
public class TestSceneOsuDistanceSnapGrid : OsuManualInputManagerTestScene
|
||||
{
|
||||
private const double beat_length = 100;
|
||||
private static readonly Vector2 grid_position = new Vector2(512, 384);
|
||||
|
@ -12,7 +12,7 @@ using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneResumeOverlay : ManualInputManagerTestScene
|
||||
public class TestSceneResumeOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
typeof(DrawableSliderTick),
|
||||
typeof(DrawableSliderTail),
|
||||
typeof(DrawableSliderHead),
|
||||
typeof(DrawableRepeatPoint),
|
||||
typeof(DrawableSliderRepeat),
|
||||
typeof(DrawableOsuHitObject)
|
||||
};
|
||||
|
||||
@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
AddAssert("head samples updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle));
|
||||
AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderTick>().All(assertTickSamples));
|
||||
AddAssert("repeat samples updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<RepeatPoint>().All(assertSamples));
|
||||
AddAssert("repeat samples updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderRepeat>().All(assertSamples));
|
||||
AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0);
|
||||
|
||||
static bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick";
|
||||
@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
AddAssert("head samples not updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle));
|
||||
AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderTick>().All(assertTickSamples));
|
||||
AddAssert("repeat samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<RepeatPoint>().All(assertSamples));
|
||||
AddAssert("repeat samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderRepeat>().All(assertSamples));
|
||||
AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0);
|
||||
|
||||
static bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick";
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
typeof(SliderBall),
|
||||
typeof(DrawableSlider),
|
||||
typeof(DrawableSliderTick),
|
||||
typeof(DrawableRepeatPoint),
|
||||
typeof(DrawableSliderRepeat),
|
||||
typeof(DrawableOsuHitObject),
|
||||
typeof(DrawableSliderHead),
|
||||
typeof(DrawableSliderTail),
|
||||
@ -327,7 +327,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
AddAssert("Tracking dropped", assertMidSliderJudgementFail);
|
||||
}
|
||||
|
||||
private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
|
||||
private bool assertGreatJudge() => judgementResults.Any() && judgementResults.All(t => t.Type == HitResult.Great);
|
||||
|
||||
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
|
||||
|
||||
|
16
osu.Game.Rulesets.Osu/Judgements/OsuIgnoreJudgement.cs
Normal file
16
osu.Game.Rulesets.Osu/Judgements/OsuIgnoreJudgement.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Judgements
|
||||
{
|
||||
public class OsuIgnoreJudgement : OsuJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
|
||||
protected override double HealthIncreaseFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
return;
|
||||
|
||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<RepeatPoint>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
|
||||
foreach (var point in slider.Path.ControlPoints)
|
||||
point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y);
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
case DrawableSliderHead _:
|
||||
case DrawableSliderTail _:
|
||||
case DrawableSliderTick _:
|
||||
case DrawableRepeatPoint _:
|
||||
case DrawableSliderRepeat _:
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
// Wiggle the repeat points with the slider instead of independently.
|
||||
// Also fixes an issue with repeat points being positioned incorrectly.
|
||||
if (osuObject is RepeatPoint)
|
||||
if (osuObject is SliderRepeat)
|
||||
return;
|
||||
|
||||
Random objRand = new Random((int)osuObject.StartTime);
|
||||
|
@ -88,8 +88,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
private void refresh()
|
||||
{
|
||||
ClearInternal();
|
||||
|
||||
OsuHitObject osuStart = Start.HitObject;
|
||||
double startTime = osuStart.GetEndTime();
|
||||
|
||||
@ -116,6 +114,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
double? firstTransformStartTime = null;
|
||||
double finalTransformEndTime = startTime;
|
||||
|
||||
int point = 0;
|
||||
|
||||
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
|
||||
{
|
||||
float fraction = (float)d / distance;
|
||||
@ -126,13 +126,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
FollowPoint fp;
|
||||
|
||||
AddInternal(fp = new FollowPoint
|
||||
if (InternalChildren.Count > point)
|
||||
{
|
||||
Position = pointStartPosition,
|
||||
Rotation = rotation,
|
||||
Alpha = 0,
|
||||
Scale = new Vector2(1.5f * osuEnd.Scale),
|
||||
});
|
||||
fp = (FollowPoint)InternalChildren[point];
|
||||
fp.ClearTransforms();
|
||||
}
|
||||
else
|
||||
AddInternal(fp = new FollowPoint());
|
||||
|
||||
fp.Position = pointStartPosition;
|
||||
fp.Rotation = rotation;
|
||||
fp.Alpha = 0;
|
||||
fp.Scale = new Vector2(1.5f * osuEnd.Scale);
|
||||
|
||||
if (firstTransformStartTime == null)
|
||||
firstTransformStartTime = fadeInTime;
|
||||
@ -146,8 +151,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn;
|
||||
}
|
||||
|
||||
point++;
|
||||
}
|
||||
|
||||
int excessPoints = InternalChildren.Count - point;
|
||||
for (int i = 0; i < excessPoints; i++)
|
||||
RemoveInternal(InternalChildren[^1]);
|
||||
|
||||
// todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed.
|
||||
LifetimeStart = firstTransformStartTime ?? startTime;
|
||||
LifetimeEnd = finalTransformEndTime;
|
||||
|
@ -6,13 +6,11 @@ using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
@ -26,12 +24,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public readonly SliderBall Ball;
|
||||
public readonly SkinnableDrawable Body;
|
||||
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
|
||||
|
||||
private readonly Container<DrawableSliderHead> headContainer;
|
||||
private readonly Container<DrawableSliderTail> tailContainer;
|
||||
private readonly Container<DrawableSliderTick> tickContainer;
|
||||
private readonly Container<DrawableRepeatPoint> repeatContainer;
|
||||
private readonly Container<DrawableSliderRepeat> repeatContainer;
|
||||
|
||||
private readonly Slider slider;
|
||||
|
||||
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling),
|
||||
tickContainer = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
|
||||
repeatContainer = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
|
||||
repeatContainer = new Container<DrawableSliderRepeat> { RelativeSizeAxes = Axes.Both },
|
||||
Ball = new SliderBall(s, this)
|
||||
{
|
||||
GetInitialHitAction = () => HeadCircle.HitAction,
|
||||
@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
tickContainer.Add(tick);
|
||||
break;
|
||||
|
||||
case DrawableRepeatPoint repeat:
|
||||
case DrawableSliderRepeat repeat:
|
||||
repeatContainer.Add(repeat);
|
||||
break;
|
||||
}
|
||||
@ -129,8 +129,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
case SliderTick tick:
|
||||
return new DrawableSliderTick(tick) { Position = tick.Position - slider.Position };
|
||||
|
||||
case RepeatPoint repeat:
|
||||
return new DrawableRepeatPoint(repeat, this) { Position = repeat.Position - slider.Position };
|
||||
case SliderRepeat repeat:
|
||||
return new DrawableSliderRepeat(repeat, this) { Position = repeat.Position - slider.Position };
|
||||
}
|
||||
|
||||
return base.CreateNestedHitObject(hitObject);
|
||||
@ -185,7 +185,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
base.ApplySkin(skin, allowFallback);
|
||||
|
||||
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
||||
Ball.AccentColour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||
Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
@ -193,22 +193,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
if (userTriggered || Time.Current < slider.EndTime)
|
||||
return;
|
||||
|
||||
ApplyResult(r =>
|
||||
{
|
||||
var judgementsCount = NestedHitObjects.Count;
|
||||
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
||||
|
||||
var hitFraction = (double)judgementsHit / judgementsCount;
|
||||
|
||||
if (hitFraction == 1 && HeadCircle.Result.Type == HitResult.Great)
|
||||
r.Type = HitResult.Great;
|
||||
else if (hitFraction >= 0.5 && HeadCircle.Result.Type >= HitResult.Good)
|
||||
r.Type = HitResult.Good;
|
||||
else if (hitFraction > 0)
|
||||
r.Type = HitResult.Meh;
|
||||
else
|
||||
r.Type = HitResult.Miss;
|
||||
});
|
||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||
}
|
||||
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
|
@ -14,19 +14,19 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
public class DrawableRepeatPoint : DrawableOsuHitObject, ITrackSnaking
|
||||
public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking
|
||||
{
|
||||
private readonly RepeatPoint repeatPoint;
|
||||
private readonly SliderRepeat sliderRepeat;
|
||||
private readonly DrawableSlider drawableSlider;
|
||||
|
||||
private double animDuration;
|
||||
|
||||
private readonly Drawable scaleContainer;
|
||||
|
||||
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
|
||||
: base(repeatPoint)
|
||||
public DrawableSliderRepeat(SliderRepeat sliderRepeat, DrawableSlider drawableSlider)
|
||||
: base(sliderRepeat)
|
||||
{
|
||||
this.repeatPoint = repeatPoint;
|
||||
this.sliderRepeat = sliderRepeat;
|
||||
this.drawableSlider = drawableSlider;
|
||||
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
@ -48,13 +48,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (repeatPoint.StartTime <= Time.Current)
|
||||
if (sliderRepeat.StartTime <= Time.Current)
|
||||
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? HitResult.Great : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
animDuration = Math.Min(300, repeatPoint.SpanDuration);
|
||||
animDuration = Math.Min(300, sliderRepeat.SpanDuration);
|
||||
|
||||
this.Animate(
|
||||
d => d.FadeIn(animDuration),
|
||||
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||
{
|
||||
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
|
||||
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
|
||||
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
|
||||
|
||||
Position = isRepeatAtEnd ? end : start;
|
@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered && timeOffset >= 0)
|
||||
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
|
||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : HitResult.Miss);
|
||||
}
|
||||
|
||||
private void updatePosition() => Position = HitObject.Position - slider.Position;
|
||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (timeOffset >= 0)
|
||||
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
|
||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
|
@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
.FadeTo(tracking_alpha, 250, Easing.OutQuint);
|
||||
}
|
||||
|
||||
this.RotateTo(currentRotation / 2, validAndTracking ? 500 : 1500, Easing.OutExpo);
|
||||
Rotation = (float)Interpolation.Lerp(Rotation, currentRotation / 2, Math.Clamp(Math.Abs(Time.Elapsed) / 40, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
break;
|
||||
|
||||
case SliderEventType.Repeat:
|
||||
AddNested(new RepeatPoint
|
||||
AddNested(new SliderRepeat
|
||||
{
|
||||
RepeatIndex = e.SpanIndex,
|
||||
SpanDuration = SpanDuration,
|
||||
@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
foreach (var tick in NestedHitObjects.OfType<SliderTick>())
|
||||
tick.Samples = sampleList;
|
||||
|
||||
foreach (var repeat in NestedHitObjects.OfType<RepeatPoint>())
|
||||
foreach (var repeat in NestedHitObjects.OfType<SliderRepeat>())
|
||||
repeat.Samples = getNodeSamples(repeat.RepeatIndex + 1);
|
||||
|
||||
if (HeadCircle != null)
|
||||
@ -233,7 +233,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
private IList<HitSampleInfo> getNodeSamples(int nodeIndex) =>
|
||||
nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples;
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
public override Judgement CreateJudgement() => new OsuIgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
public class RepeatPoint : OsuHitObject
|
||||
public class SliderRepeat : OsuHitObject
|
||||
{
|
||||
public int RepeatIndex { get; set; }
|
||||
public double SpanDuration { get; set; }
|
||||
@ -28,8 +28,15 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
public override Judgement CreateJudgement() => new SliderRepeatJudgement();
|
||||
|
||||
public class SliderRepeatJudgement : OsuJudgement
|
||||
{
|
||||
public override bool IsBonus => true;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 30 : 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -22,8 +22,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
public override Judgement CreateJudgement() => new SliderRepeat.SliderRepeatJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,15 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
public override Judgement CreateJudgement() => new SliderTickJudgement();
|
||||
|
||||
public class SliderTickJudgement : OsuJudgement
|
||||
{
|
||||
public override bool IsBonus => true;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 10 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
/// </summary>
|
||||
public bool AllowUserCursorMovement { get; set; } = true;
|
||||
|
||||
protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
protected override KeyBindingContainer<OsuAction> CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
=> new OsuKeyBindingContainer(ruleset, variant, unique);
|
||||
|
||||
public OsuInputManager(RulesetInfo ruleset)
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
||||
};
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new OsuModNightcore();
|
||||
|
@ -26,11 +26,23 @@ namespace osu.Game.Rulesets.Osu.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
Position = currentFrame.Position;
|
||||
if (currentFrame.MouseLeft) Actions.Add(OsuAction.LeftButton);
|
||||
if (currentFrame.MouseRight) Actions.Add(OsuAction.RightButton);
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
ReplayButtonState state = ReplayButtonState.None;
|
||||
|
||||
if (Actions.Contains(OsuAction.LeftButton))
|
||||
state |= ReplayButtonState.Left1;
|
||||
if (Actions.Contains(OsuAction.RightButton))
|
||||
state |= ReplayButtonState.Right1;
|
||||
|
||||
return new LegacyReplayFrame(Time, Position.X, Position.Y, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new OsuReplayRecorder(replay);
|
||||
|
||||
public override double GameplayStartTime
|
||||
{
|
||||
get
|
||||
|
23
osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs
Normal file
23
osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class OsuReplayRecorder : ReplayRecorder<OsuAction>
|
||||
{
|
||||
public OsuReplayRecorder(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<OsuAction> actions, ReplayFrame previousFrame)
|
||||
=> new OsuReplayFrame(Time.Current, mousePosition, actions.ToArray());
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestHit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new CentreHit { StartTime = 1000 }), shouldMiss);
|
||||
public void TestHit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Hit { StartTime = 1000, Type = HitType.Centre }), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
|
@ -27,8 +27,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
StartTime = hitObject.StartTime,
|
||||
EndTime = hitObject.GetEndTime(),
|
||||
IsRim = hitObject is RimHit,
|
||||
IsCentre = hitObject is CentreHit,
|
||||
IsRim = (hitObject as Hit)?.Type == HitType.Rim,
|
||||
IsCentre = (hitObject as Hit)?.Type == HitType.Centre,
|
||||
IsDrumRoll = hitObject is DrumRoll,
|
||||
IsSwell = hitObject is Swell,
|
||||
IsStrong = ((TaikoHitObject)hitObject).IsStrong
|
||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject> { new CentreHit() },
|
||||
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty(),
|
||||
|
@ -124,24 +124,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||
strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
||||
|
||||
if (isRim)
|
||||
yield return new Hit
|
||||
{
|
||||
yield return new RimHit
|
||||
{
|
||||
StartTime = j,
|
||||
Samples = currentSamples,
|
||||
IsStrong = strong
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new CentreHit
|
||||
{
|
||||
StartTime = j,
|
||||
Samples = currentSamples,
|
||||
IsStrong = strong
|
||||
};
|
||||
}
|
||||
StartTime = j,
|
||||
Type = isRim ? HitType.Rim : HitType.Centre,
|
||||
Samples = currentSamples,
|
||||
IsStrong = strong
|
||||
};
|
||||
|
||||
i = (i + 1) % allSamples.Count;
|
||||
}
|
||||
@ -180,24 +169,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
{
|
||||
bool isRim = samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||
|
||||
if (isRim)
|
||||
yield return new Hit
|
||||
{
|
||||
yield return new RimHit
|
||||
{
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
IsStrong = strong
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new CentreHit
|
||||
{
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
IsStrong = strong
|
||||
};
|
||||
}
|
||||
StartTime = obj.StartTime,
|
||||
Type = isRim ? HitType.Rim : HitType.Centre,
|
||||
Samples = obj.Samples,
|
||||
IsStrong = strong
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
||||
public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate)
|
||||
: base(hitObject, lastObject, clockRate)
|
||||
{
|
||||
HasTypeChange = lastObject is RimHit != hitObject is RimHit;
|
||||
HasTypeChange = (lastObject as Hit)?.Type != (hitObject as Hit)?.Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs
Normal file
27
osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Utils;
|
||||
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 TaikoModRandom : ModRandom, IApplicableToBeatmap
|
||||
{
|
||||
public override string Description => @"Shuffle around the colours!";
|
||||
|
||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
var taikoBeatmap = (TaikoBeatmap)beatmap;
|
||||
|
||||
foreach (var obj in taikoBeatmap.HitObjects)
|
||||
{
|
||||
if (obj is Hit hit)
|
||||
hit.Type = RNG.Next(2) == 0 ? HitType.Centre : HitType.Rim;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
// 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.Taiko.Objects
|
||||
{
|
||||
public class CentreHit : Hit
|
||||
{
|
||||
}
|
||||
}
|
@ -5,5 +5,9 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
public class Hit : TaikoHitObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="HitType"/> that actuates this <see cref="Hit"/>.
|
||||
/// </summary>
|
||||
public HitType Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
21
osu.Game.Rulesets.Taiko/Objects/HitType.cs
Normal file
21
osu.Game.Rulesets.Taiko/Objects/HitType.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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.Taiko.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of a <see cref="Hit"/>.
|
||||
/// </summary>
|
||||
public enum HitType
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="Hit"/> that can be hit by the centre portion of the drum.
|
||||
/// </summary>
|
||||
Centre,
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Hit"/> that can be hit by the rim portion of the drum.
|
||||
/// </summary>
|
||||
Rim
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
// 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.Taiko.Objects
|
||||
{
|
||||
public class RimHit : Hit
|
||||
{
|
||||
}
|
||||
}
|
@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
TaikoAction[] actions;
|
||||
|
||||
if (hit is CentreHit)
|
||||
if (hit.Type == HitType.Centre)
|
||||
{
|
||||
actions = h.IsStrong
|
||||
? new[] { TaikoAction.LeftCentre, TaikoAction.RightCentre }
|
||||
|
@ -23,12 +23,24 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
if (currentFrame.MouseRight1) Actions.Add(TaikoAction.LeftRim);
|
||||
if (currentFrame.MouseRight2) Actions.Add(TaikoAction.RightRim);
|
||||
if (currentFrame.MouseLeft1) Actions.Add(TaikoAction.LeftCentre);
|
||||
if (currentFrame.MouseLeft2) Actions.Add(TaikoAction.RightCentre);
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
ReplayButtonState state = ReplayButtonState.None;
|
||||
|
||||
if (Actions.Contains(TaikoAction.LeftRim)) state |= ReplayButtonState.Right1;
|
||||
if (Actions.Contains(TaikoAction.RightRim)) state |= ReplayButtonState.Right2;
|
||||
if (Actions.Contains(TaikoAction.LeftCentre)) state |= ReplayButtonState.Left1;
|
||||
if (Actions.Contains(TaikoAction.RightCentre)) state |= ReplayButtonState.Left2;
|
||||
|
||||
return new LegacyReplayFrame(Time, null, null, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Taiko
|
||||
new KeyBinding(InputKey.K, TaikoAction.RightRim),
|
||||
};
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new TaikoModNightcore();
|
||||
@ -114,6 +114,7 @@ namespace osu.Game.Rulesets.Taiko
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new TaikoModRandom(),
|
||||
new TaikoModDifficultyAdjust(),
|
||||
};
|
||||
|
||||
|
@ -48,11 +48,11 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
switch (h)
|
||||
{
|
||||
case CentreHit centreHit:
|
||||
return new DrawableCentreHit(centreHit);
|
||||
|
||||
case RimHit rimHit:
|
||||
return new DrawableRimHit(rimHit);
|
||||
case Hit hit:
|
||||
if (hit.Type == HitType.Centre)
|
||||
return new DrawableCentreHit(hit);
|
||||
else
|
||||
return new DrawableRimHit(hit);
|
||||
|
||||
case DrumRoll drumRoll:
|
||||
return new DrawableDrumRoll(drumRoll);
|
||||
@ -65,5 +65,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
}
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new TaikoReplayRecorder(replay);
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -245,7 +245,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
if (!result.IsHit)
|
||||
break;
|
||||
|
||||
bool isRim = judgedObject.HitObject is RimHit;
|
||||
bool isRim = (judgedObject.HitObject as Hit)?.Type == HitType.Rim;
|
||||
|
||||
hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
|
||||
|
||||
|
23
osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs
Normal file
23
osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class TaikoReplayRecorder : ReplayRecorder<TaikoAction>
|
||||
{
|
||||
public TaikoReplayRecorder(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TaikoAction> actions, ReplayFrame previousFrame) =>
|
||||
new TaikoReplayFrame(Time.Current, actions.ToArray());
|
||||
}
|
||||
}
|
@ -26,34 +26,34 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
Assert.IsTrue(storyboard.HasDrawable);
|
||||
Assert.AreEqual(4, storyboard.Layers.Count());
|
||||
Assert.AreEqual(5, storyboard.Layers.Count());
|
||||
|
||||
StoryboardLayer background = storyboard.Layers.FirstOrDefault(l => l.Depth == 3);
|
||||
Assert.IsNotNull(background);
|
||||
Assert.AreEqual(16, background.Elements.Count);
|
||||
Assert.IsTrue(background.EnabledWhenFailing);
|
||||
Assert.IsTrue(background.EnabledWhenPassing);
|
||||
Assert.IsTrue(background.VisibleWhenFailing);
|
||||
Assert.IsTrue(background.VisibleWhenPassing);
|
||||
Assert.AreEqual("Background", background.Name);
|
||||
|
||||
StoryboardLayer fail = storyboard.Layers.FirstOrDefault(l => l.Depth == 2);
|
||||
Assert.IsNotNull(fail);
|
||||
Assert.AreEqual(0, fail.Elements.Count);
|
||||
Assert.IsTrue(fail.EnabledWhenFailing);
|
||||
Assert.IsFalse(fail.EnabledWhenPassing);
|
||||
Assert.IsTrue(fail.VisibleWhenFailing);
|
||||
Assert.IsFalse(fail.VisibleWhenPassing);
|
||||
Assert.AreEqual("Fail", fail.Name);
|
||||
|
||||
StoryboardLayer pass = storyboard.Layers.FirstOrDefault(l => l.Depth == 1);
|
||||
Assert.IsNotNull(pass);
|
||||
Assert.AreEqual(0, pass.Elements.Count);
|
||||
Assert.IsFalse(pass.EnabledWhenFailing);
|
||||
Assert.IsTrue(pass.EnabledWhenPassing);
|
||||
Assert.IsFalse(pass.VisibleWhenFailing);
|
||||
Assert.IsTrue(pass.VisibleWhenPassing);
|
||||
Assert.AreEqual("Pass", pass.Name);
|
||||
|
||||
StoryboardLayer foreground = storyboard.Layers.FirstOrDefault(l => l.Depth == 0);
|
||||
Assert.IsNotNull(foreground);
|
||||
Assert.AreEqual(151, foreground.Elements.Count);
|
||||
Assert.IsTrue(foreground.EnabledWhenFailing);
|
||||
Assert.IsTrue(foreground.EnabledWhenPassing);
|
||||
Assert.IsTrue(foreground.VisibleWhenFailing);
|
||||
Assert.IsTrue(foreground.VisibleWhenPassing);
|
||||
Assert.AreEqual("Foreground", foreground.Name);
|
||||
|
||||
int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite));
|
||||
|
@ -417,7 +417,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
[Test]
|
||||
public async Task TestImportWithDuplicateHashes()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateHashes)))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
282
osu.Game.Tests/Gameplay/TestSceneReplayRecorder.cs
Normal file
282
osu.Game.Tests/Gameplay/TestSceneReplayRecorder.cs
Normal file
@ -0,0 +1,282 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Tests.Visual.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
public class TestSceneReplayRecorder : OsuManualInputManagerTestScene
|
||||
{
|
||||
private TestRulesetInputManager playbackManager;
|
||||
private TestRulesetInputManager recordingManager;
|
||||
|
||||
private Replay replay;
|
||||
|
||||
private TestReplayRecorder recorder;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
replay = new Replay();
|
||||
|
||||
Add(new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
Recorder = recorder = new TestReplayRecorder(replay)
|
||||
{
|
||||
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Brown,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Recording",
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new TestInputConsumer()
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
playbackManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
|
||||
{
|
||||
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.DarkBlue,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Playback",
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new TestInputConsumer()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestBasic()
|
||||
{
|
||||
AddStep("move to center", () => InputManager.MoveMouseTo(recordingManager.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("one frame recorded", () => replay.Frames.Count == 1);
|
||||
AddAssert("position matches", () => playbackManager.ChildrenOfType<Box>().First().Position == recordingManager.ChildrenOfType<Box>().First().Position);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHighFrameRate()
|
||||
{
|
||||
ScheduledDelegate moveFunction = null;
|
||||
|
||||
AddStep("move to center", () => InputManager.MoveMouseTo(recordingManager.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("much move", () => moveFunction = Scheduler.AddDelayed(() =>
|
||||
InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(-1, 0)), 10, true));
|
||||
AddWaitStep("move", 10);
|
||||
AddStep("stop move", () => moveFunction.Cancel());
|
||||
AddAssert("at least 60 frames recorded", () => replay.Frames.Count > 60);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLimitedFrameRate()
|
||||
{
|
||||
ScheduledDelegate moveFunction = null;
|
||||
|
||||
AddStep("lower rate", () => recorder.RecordFrameRate = 2);
|
||||
AddStep("move to center", () => InputManager.MoveMouseTo(recordingManager.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("much move", () => moveFunction = Scheduler.AddDelayed(() =>
|
||||
InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(-1, 0)), 10, true));
|
||||
AddWaitStep("move", 10);
|
||||
AddStep("stop move", () => moveFunction.Cancel());
|
||||
AddAssert("less than 10 frames recorded", () => replay.Frames.Count < 10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLimitedFrameRateWithImportantFrames()
|
||||
{
|
||||
ScheduledDelegate moveFunction = null;
|
||||
|
||||
AddStep("lower rate", () => recorder.RecordFrameRate = 2);
|
||||
AddStep("move to center", () => InputManager.MoveMouseTo(recordingManager.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("much move with press", () => moveFunction = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(-1, 0));
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
}, 10, true));
|
||||
AddWaitStep("move", 10);
|
||||
AddStep("stop move", () => moveFunction.Cancel());
|
||||
AddAssert("at least 60 frames recorded", () => replay.Frames.Count > 60);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
playbackManager?.ReplayInputHandler.SetFrameFromTime(Time.Current - 100);
|
||||
}
|
||||
|
||||
public class TestFramedReplayInputHandler : FramedReplayInputHandler<TestReplayFrame>
|
||||
{
|
||||
public TestFramedReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<IInput> GetPendingInputs()
|
||||
{
|
||||
return new List<IInput>
|
||||
{
|
||||
new MousePositionAbsoluteInput
|
||||
{
|
||||
Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero)
|
||||
},
|
||||
new ReplayState<TestAction>
|
||||
{
|
||||
PressedActions = CurrentFrame?.Actions ?? new List<TestAction>()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class TestInputConsumer : CompositeDrawable, IKeyBindingHandler<TestAction>
|
||||
{
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
private readonly Box box;
|
||||
|
||||
public TestInputConsumer()
|
||||
{
|
||||
Size = new Vector2(30);
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
box = new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
{
|
||||
Position = e.MousePosition;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
public bool OnPressed(TestAction action)
|
||||
{
|
||||
box.Colour = Color4.White;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnReleased(TestAction action)
|
||||
{
|
||||
box.Colour = Color4.Black;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestRulesetInputManager : RulesetInputManager<TestAction>
|
||||
{
|
||||
public TestRulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
: base(ruleset, variant, unique)
|
||||
{
|
||||
}
|
||||
|
||||
protected override KeyBindingContainer<TestAction> CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
=> new TestKeyBindingContainer();
|
||||
|
||||
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
|
||||
{
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class TestReplayFrame : ReplayFrame
|
||||
{
|
||||
public Vector2 Position;
|
||||
|
||||
public List<TestAction> Actions = new List<TestAction>();
|
||||
|
||||
public TestReplayFrame(double time, Vector2 position, params TestAction[] actions)
|
||||
: base(time)
|
||||
{
|
||||
Position = position;
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
}
|
||||
|
||||
public enum TestAction
|
||||
{
|
||||
Down,
|
||||
}
|
||||
|
||||
internal class TestReplayRecorder : ReplayRecorder<TestAction>
|
||||
{
|
||||
public TestReplayRecorder(Replay target)
|
||||
: base(target)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TestAction> actions, ReplayFrame previousFrame)
|
||||
=> new TestReplayFrame(Time.Current, mousePosition, actions.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
221
osu.Game.Tests/Gameplay/TestSceneReplayRecording.cs
Normal file
221
osu.Game.Tests/Gameplay/TestSceneReplayRecording.cs
Normal file
@ -0,0 +1,221 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Tests.Visual.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
public class TestSceneReplayRecording : OsuTestScene
|
||||
{
|
||||
private readonly TestRulesetInputManager playbackManager;
|
||||
|
||||
private readonly TestRulesetInputManager recordingManager;
|
||||
|
||||
public TestSceneReplayRecording()
|
||||
{
|
||||
Replay replay = new Replay();
|
||||
|
||||
Add(new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
Recorder = new TestReplayRecorder(replay)
|
||||
{
|
||||
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos)
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Brown,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Recording",
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new TestConsumer()
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
playbackManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
|
||||
{
|
||||
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.DarkBlue,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Playback",
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new TestConsumer()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
playbackManager.ReplayInputHandler.SetFrameFromTime(Time.Current - 500);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestFramedReplayInputHandler : FramedReplayInputHandler<TestReplayFrame>
|
||||
{
|
||||
public TestFramedReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<IInput> GetPendingInputs()
|
||||
{
|
||||
return new List<IInput>
|
||||
{
|
||||
new MousePositionAbsoluteInput
|
||||
{
|
||||
Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero)
|
||||
},
|
||||
new ReplayState<TestAction>
|
||||
{
|
||||
PressedActions = CurrentFrame?.Actions ?? new List<TestAction>()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class TestConsumer : CompositeDrawable, IKeyBindingHandler<TestAction>
|
||||
{
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
private readonly Box box;
|
||||
|
||||
public TestConsumer()
|
||||
{
|
||||
Size = new Vector2(30);
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
box = new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
{
|
||||
Position = e.MousePosition;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
public bool OnPressed(TestAction action)
|
||||
{
|
||||
box.Colour = Color4.White;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnReleased(TestAction action)
|
||||
{
|
||||
box.Colour = Color4.Black;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestRulesetInputManager : RulesetInputManager<TestAction>
|
||||
{
|
||||
public TestRulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
: base(ruleset, variant, unique)
|
||||
{
|
||||
}
|
||||
|
||||
protected override KeyBindingContainer<TestAction> CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
=> new TestKeyBindingContainer();
|
||||
|
||||
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
|
||||
{
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class TestReplayFrame : ReplayFrame
|
||||
{
|
||||
public Vector2 Position;
|
||||
|
||||
public List<TestAction> Actions = new List<TestAction>();
|
||||
|
||||
public TestReplayFrame(double time, Vector2 position, params TestAction[] actions)
|
||||
: base(time)
|
||||
{
|
||||
Position = position;
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
}
|
||||
|
||||
public enum TestAction
|
||||
{
|
||||
Down,
|
||||
}
|
||||
|
||||
internal class TestReplayRecorder : ReplayRecorder<TestAction>
|
||||
{
|
||||
public TestReplayRecorder(Replay target)
|
||||
: base(target)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TestAction> actions, ReplayFrame previousFrame) =>
|
||||
new TestReplayFrame(Time.Current, mousePosition, actions.ToArray());
|
||||
}
|
||||
}
|
@ -236,8 +236,6 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => new[] { "test_file.osr" };
|
||||
|
||||
public override Stream GetUnderlyingStream() => new MemoryStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ using osu.Game.Screens;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Users;
|
||||
@ -36,7 +37,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneUserDimBackgrounds : ManualInputManagerTestScene
|
||||
public class TestSceneUserDimBackgrounds : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -203,7 +204,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the visual settings container removes user dim when suspending <see cref="Player"/> for <see cref="SoloResults"/>
|
||||
/// Check if the visual settings container removes user dim when suspending <see cref="Player"/> for <see cref="ResultsScreen"/>
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TransitionTest()
|
||||
@ -277,6 +278,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private void setupUserSettings()
|
||||
{
|
||||
AddUntilStep("Song select is current", () => songSelect.IsCurrentScreen());
|
||||
AddUntilStep("Song select has selection", () => songSelect.Carousel?.SelectedBeatmap != null);
|
||||
AddStep("Set default user settings", () =>
|
||||
{
|
||||
@ -335,7 +337,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen();
|
||||
}
|
||||
|
||||
private class FadeAccessibleResults : SoloResults
|
||||
private class FadeAccessibleResults : ResultsScreen
|
||||
{
|
||||
public FadeAccessibleResults(ScoreInfo score)
|
||||
: base(score)
|
||||
|
@ -12,7 +12,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Components
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneIdleTracker : ManualInputManagerTestScene
|
||||
public class TestSceneIdleTracker : OsuManualInputManagerTestScene
|
||||
{
|
||||
private IdleTrackingBox box1;
|
||||
private IdleTrackingBox box2;
|
||||
|
@ -3,27 +3,83 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
public class TestSceneBeatDivisorControl : OsuTestScene
|
||||
public class TestSceneBeatDivisorControl : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BindableBeatDivisor) };
|
||||
private BeatDivisorControl beatDivisorControl;
|
||||
private BindableBeatDivisor bindableBeatDivisor;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private SliderBar<int> tickSliderBar;
|
||||
private EquilateralTriangle tickMarkerHead;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Child = new BeatDivisorControl(new BindableBeatDivisor())
|
||||
Child = beatDivisorControl = new BeatDivisorControl(bindableBeatDivisor = new BindableBeatDivisor(16))
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(90, 90)
|
||||
};
|
||||
|
||||
tickSliderBar = beatDivisorControl.ChildrenOfType<SliderBar<int>>().Single();
|
||||
tickMarkerHead = tickSliderBar.ChildrenOfType<EquilateralTriangle>().Single();
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestBindableBeatDivisor()
|
||||
{
|
||||
AddRepeatStep("move previous", () => bindableBeatDivisor.Previous(), 4);
|
||||
AddAssert("divisor is 4", () => bindableBeatDivisor.Value == 4);
|
||||
AddRepeatStep("move next", () => bindableBeatDivisor.Next(), 3);
|
||||
AddAssert("divisor is 12", () => bindableBeatDivisor.Value == 12);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMouseInput()
|
||||
{
|
||||
AddStep("hold marker", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(tickMarkerHead.ScreenSpaceDrawQuad.Centre);
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
AddStep("move to 8 and release", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(tickSliderBar.ScreenSpaceDrawQuad.Centre);
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
AddAssert("divisor is 8", () => bindableBeatDivisor.Value == 8);
|
||||
AddStep("hold marker", () => InputManager.PressButton(MouseButton.Left));
|
||||
AddStep("move to 16", () => InputManager.MoveMouseTo(getPositionForDivisor(16)));
|
||||
AddStep("move to ~10 and release", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(getPositionForDivisor(10));
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
AddAssert("divisor clamped to 8", () => bindableBeatDivisor.Value == 8);
|
||||
}
|
||||
|
||||
private Vector2 getPositionForDivisor(int divisor)
|
||||
{
|
||||
var relativePosition = (float)Math.Clamp(divisor, 0, 16) / 16;
|
||||
var sliderDrawQuad = tickSliderBar.ScreenSpaceDrawQuad;
|
||||
return new Vector2(
|
||||
sliderDrawQuad.TopLeft.X + sliderDrawQuad.Width * relativePosition,
|
||||
sliderDrawQuad.Centre.Y
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
public class TestSceneZoomableScrollContainer : ManualInputManagerTestScene
|
||||
public class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene
|
||||
{
|
||||
private ZoomableScrollContainer scrollContainer;
|
||||
private Drawable innerBox;
|
||||
|
@ -18,7 +18,7 @@ using osuTK.Input;
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[Description("player pause/fail screens")]
|
||||
public class TestSceneGameplayMenuOverlay : ManualInputManagerTestScene
|
||||
public class TestSceneGameplayMenuOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(FailOverlay), typeof(PauseOverlay) };
|
||||
|
||||
|
@ -15,7 +15,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneHUDOverlay : ManualInputManagerTestScene
|
||||
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
private HUDOverlay hudOverlay;
|
||||
|
||||
|
@ -13,7 +13,7 @@ using osuTK.Input;
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[Description("'Hold to Quit' UI element")]
|
||||
public class TestSceneHoldForMenuButton : ManualInputManagerTestScene
|
||||
public class TestSceneHoldForMenuButton : OsuManualInputManagerTestScene
|
||||
{
|
||||
private bool exitAction;
|
||||
|
||||
|
@ -13,7 +13,7 @@ using osuTK.Input;
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneKeyCounter : ManualInputManagerTestScene
|
||||
public class TestSceneKeyCounter : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestScenePlayerLoader : ManualInputManagerTestScene
|
||||
public class TestScenePlayerLoader : OsuManualInputManagerTestScene
|
||||
{
|
||||
private TestPlayerLoader loader;
|
||||
private TestPlayerLoaderContainer container;
|
||||
|
@ -11,7 +11,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Ranking.Pages;
|
||||
using osu.Game.Screens.Ranking;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ using osuTK.Input;
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneSkipOverlay : ManualInputManagerTestScene
|
||||
public class TestSceneSkipOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
private SkipOverlay skip;
|
||||
private int requestCount;
|
||||
|
@ -64,6 +64,8 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
|
||||
introStack.Push(CreateScreen());
|
||||
});
|
||||
|
||||
AddUntilStep("wait for menu", () => introStack.CurrentScreen is MainMenu);
|
||||
}
|
||||
|
||||
protected abstract IScreen CreateScreen();
|
||||
|
@ -1,12 +1,15 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK.Graphics;
|
||||
@ -14,14 +17,14 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneLoaderAnimation : ScreenTestScene
|
||||
public class TestSceneLoader : ScreenTestScene
|
||||
{
|
||||
private TestLoader loader;
|
||||
|
||||
[Cached]
|
||||
private OsuLogo logo;
|
||||
|
||||
public TestSceneLoaderAnimation()
|
||||
public TestSceneLoader()
|
||||
{
|
||||
Child = logo = new OsuLogo
|
||||
{
|
||||
@ -42,33 +45,33 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
|
||||
LoadScreen(loader);
|
||||
});
|
||||
|
||||
AddAssert("spinner did not display", () => loader.LoadingSpinner?.Alpha == 0);
|
||||
|
||||
AddUntilStep("loaded", () => loader.ScreenLoaded);
|
||||
AddUntilStep("not current", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDelayedLoad()
|
||||
{
|
||||
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
|
||||
AddUntilStep("wait for logo visible", () => loader.Logo?.Alpha > 0);
|
||||
AddUntilStep("wait for spinner visible", () => loader.LoadingSpinner?.Alpha > 0);
|
||||
AddStep("finish loading", () => loader.AllowLoad.Set());
|
||||
AddUntilStep("loaded", () => loader.Logo != null && loader.ScreenLoaded);
|
||||
AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
|
||||
AddUntilStep("spinner gone", () => loader.LoadingSpinner?.Alpha == 0);
|
||||
AddUntilStep("loaded", () => loader.ScreenLoaded);
|
||||
AddUntilStep("not current", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
private class TestLoader : Loader
|
||||
{
|
||||
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim();
|
||||
|
||||
public OsuLogo Logo;
|
||||
public LoadingSpinner LoadingSpinner => this.ChildrenOfType<LoadingSpinner>().FirstOrDefault();
|
||||
private TestScreen screen;
|
||||
|
||||
public bool ScreenLoaded => screen.IsCurrentScreen();
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
Logo = logo;
|
||||
base.LogoArriving(logo, resuming);
|
||||
}
|
||||
|
||||
protected override OsuScreen CreateLoadableScreen() => screen = new TestScreen();
|
||||
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(AllowLoad);
|
||||
|
@ -20,7 +20,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneDrawableRoomPlaylist : ManualInputManagerTestScene
|
||||
public class TestSceneDrawableRoomPlaylist : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -1,106 +0,0 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Game.Screens.Multi.Ranking;
|
||||
using osu.Game.Screens.Multi.Ranking.Pages;
|
||||
using osu.Game.Screens.Multi.Ranking.Types;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchResults : MultiplayerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(MatchResults),
|
||||
typeof(RoomLeaderboardPageInfo),
|
||||
typeof(RoomLeaderboardPage)
|
||||
};
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
|
||||
if (beatmapInfo != null)
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
||||
|
||||
Room.RoomID.Value = 1;
|
||||
Room.Name.Value = "an awesome room";
|
||||
|
||||
LoadScreen(new TestMatchResults(new ScoreInfo
|
||||
{
|
||||
User = new User { Id = 10 },
|
||||
}));
|
||||
}
|
||||
|
||||
private class TestMatchResults : MatchResults
|
||||
{
|
||||
public TestMatchResults(ScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<IResultPageInfo> CreateResultPages() => new[] { new TestRoomLeaderboardPageInfo(Score, Beatmap.Value) };
|
||||
}
|
||||
|
||||
private class TestRoomLeaderboardPageInfo : RoomLeaderboardPageInfo
|
||||
{
|
||||
private readonly ScoreInfo score;
|
||||
private readonly WorkingBeatmap beatmap;
|
||||
|
||||
public TestRoomLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap)
|
||||
: base(score, beatmap)
|
||||
{
|
||||
this.score = score;
|
||||
this.beatmap = beatmap;
|
||||
}
|
||||
|
||||
public override ResultsPage CreatePage() => new TestRoomLeaderboardPage(score, beatmap);
|
||||
}
|
||||
|
||||
private class TestRoomLeaderboardPage : RoomLeaderboardPage
|
||||
{
|
||||
public TestRoomLeaderboardPage(ScoreInfo score, WorkingBeatmap beatmap)
|
||||
: base(score, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override MatchLeaderboard CreateLeaderboard() => new TestMatchLeaderboard();
|
||||
}
|
||||
|
||||
private class TestMatchLeaderboard : RoomLeaderboardPage.ResultsMatchLeaderboard
|
||||
{
|
||||
protected override APIRequest FetchScores(Action<IEnumerable<APIUserScoreAggregate>> scoresCallback)
|
||||
{
|
||||
var scores = Enumerable.Range(0, 50).Select(createRoomScore).ToArray();
|
||||
|
||||
scoresCallback?.Invoke(scores);
|
||||
ScoresLoaded?.Invoke(scores);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private APIUserScoreAggregate createRoomScore(int id) => new APIUserScoreAggregate
|
||||
{
|
||||
User = new User { Id = id, Username = $"User {id}" },
|
||||
Accuracy = 0.98,
|
||||
TotalScore = 987654,
|
||||
TotalAttempts = 13,
|
||||
CompletedBeatmaps = 5
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
/// <summary>
|
||||
/// A scene which tests full game flow.
|
||||
/// </summary>
|
||||
public abstract class OsuGameTestScene : ManualInputManagerTestScene
|
||||
public abstract class OsuGameTestScene : OsuManualInputManagerTestScene
|
||||
{
|
||||
private GameHost host;
|
||||
|
||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
API.Logout();
|
||||
|
||||
localUser = API.LocalUser.GetBoundCopy();
|
||||
localUser.BindValueChanged(user => { userPanelArea.Child = new UserPanel(user.NewValue) { Width = 200 }; }, true);
|
||||
localUser.BindValueChanged(user => { userPanelArea.Child = new UserGridPanel(user.NewValue) { Width = 200 }; }, true);
|
||||
|
||||
AddStep("logout", API.Logout);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneChatOverlay : ManualInputManagerTestScene
|
||||
public class TestSceneChatOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -38,8 +38,13 @@ namespace osu.Game.Tests.Visual.Online
|
||||
private TestChatOverlay chatOverlay;
|
||||
private ChannelManager channelManager;
|
||||
|
||||
private IEnumerable<Channel> visibleChannels => chatOverlay.ChannelTabControl.VisibleItems.Where(channel => channel.Name != "+");
|
||||
private IEnumerable<Channel> joinedChannels => chatOverlay.ChannelTabControl.Items.Where(channel => channel.Name != "+");
|
||||
private readonly List<Channel> channels;
|
||||
|
||||
private Channel currentChannel => channelManager.CurrentChannel.Value;
|
||||
private Channel nextChannel => joinedChannels.ElementAt(joinedChannels.ToList().IndexOf(currentChannel) + 1);
|
||||
private Channel previousChannel => joinedChannels.ElementAt(joinedChannels.ToList().IndexOf(currentChannel) - 1);
|
||||
private Channel channel1 => channels[0];
|
||||
private Channel channel2 => channels[1];
|
||||
|
||||
@ -49,7 +54,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
.Select(index => new Channel(new User())
|
||||
{
|
||||
Name = $"Channel no. {index}",
|
||||
Topic = index == 3 ? null : $"We talk about the number {index} here"
|
||||
Topic = index == 3 ? null : $"We talk about the number {index} here",
|
||||
Type = index % 2 == 0 ? ChannelType.PM : ChannelType.Temporary
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
@ -91,32 +97,15 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
|
||||
AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1]));
|
||||
|
||||
AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1);
|
||||
AddAssert("Current channel is channel 1", () => currentChannel == channel1);
|
||||
AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCloseChannelWhileSelectorClosed()
|
||||
{
|
||||
AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
|
||||
AddStep("Join channel 2", () => channelManager.JoinChannel(channel2));
|
||||
|
||||
AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2]));
|
||||
AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child));
|
||||
|
||||
AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1);
|
||||
|
||||
AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child));
|
||||
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSearchInSelector()
|
||||
{
|
||||
AddStep("search for 'no. 2'", () => chatOverlay.ChildrenOfType<SearchTextBox>().First().Text = "no. 2");
|
||||
AddUntilStep("only channel 2 visible", () =>
|
||||
AddStep("Search for 'no. 2'", () => chatOverlay.ChildrenOfType<SearchTextBox>().First().Text = "no. 2");
|
||||
AddUntilStep("Only channel 2 visible", () =>
|
||||
{
|
||||
var listItems = chatOverlay.ChildrenOfType<ChannelListItem>().Where(c => c.IsPresent);
|
||||
return listItems.Count() == 1 && listItems.Single().Channel == channel2;
|
||||
@ -126,24 +115,116 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestChannelShortcutKeys()
|
||||
{
|
||||
AddStep("join 10 channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
||||
AddStep("close channel selector", () =>
|
||||
AddStep("Join channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
||||
AddStep("Close channel selector", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.Escape);
|
||||
InputManager.ReleaseKey(Key.Escape);
|
||||
});
|
||||
AddUntilStep("wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
AddUntilStep("Wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
|
||||
for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex)
|
||||
{
|
||||
var oneBasedIndex = zeroBasedIndex + 1;
|
||||
var targetNumberKey = oneBasedIndex % 10;
|
||||
var targetChannel = channels[zeroBasedIndex];
|
||||
AddStep($"press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey));
|
||||
AddAssert($"channel #{oneBasedIndex} is selected", () => channelManager.CurrentChannel.Value == targetChannel);
|
||||
AddStep($"Press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey));
|
||||
AddAssert($"Channel #{oneBasedIndex} is selected", () => currentChannel == targetChannel);
|
||||
}
|
||||
}
|
||||
|
||||
private Channel expectedChannel;
|
||||
|
||||
[Test]
|
||||
public void TestCloseChannelBehaviour()
|
||||
{
|
||||
AddUntilStep("Join until dropdown has channels", () =>
|
||||
{
|
||||
if (visibleChannels.Count() < joinedChannels.Count())
|
||||
return true;
|
||||
|
||||
// Using temporary channels because they don't hide their names when not active
|
||||
channelManager.JoinChannel(new Channel
|
||||
{
|
||||
Name = $"Channel no. {joinedChannels.Count() + 11}",
|
||||
Type = ChannelType.Temporary
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
AddStep("Switch to last tab", () => clickDrawable(chatOverlay.TabMap[visibleChannels.Last()]));
|
||||
AddAssert("Last visible selected", () => currentChannel == visibleChannels.Last());
|
||||
|
||||
// Closing the last channel before dropdown
|
||||
AddStep("Close current channel", () =>
|
||||
{
|
||||
expectedChannel = nextChannel;
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(currentChannel);
|
||||
});
|
||||
AddAssert("Next channel selected", () => currentChannel == expectedChannel);
|
||||
AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
|
||||
// Depending on the window size, one more channel might need to be closed for the selectorTab to appear
|
||||
AddUntilStep("Close channels until selector visible", () =>
|
||||
{
|
||||
if (chatOverlay.ChannelTabControl.VisibleItems.Last().Name == "+")
|
||||
return true;
|
||||
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(visibleChannels.Last());
|
||||
return false;
|
||||
});
|
||||
AddAssert("Last visible selected", () => currentChannel == visibleChannels.Last());
|
||||
|
||||
// Closing the last channel with dropdown no longer present
|
||||
AddStep("Close last when selector next", () =>
|
||||
{
|
||||
expectedChannel = previousChannel;
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(currentChannel);
|
||||
});
|
||||
AddAssert("Previous channel selected", () => currentChannel == expectedChannel);
|
||||
|
||||
// Standard channel closing
|
||||
AddStep("Switch to previous channel", () => chatOverlay.ChannelTabControl.SwitchTab(-1));
|
||||
AddStep("Close current channel", () =>
|
||||
{
|
||||
expectedChannel = nextChannel;
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(currentChannel);
|
||||
});
|
||||
AddAssert("Next channel selected", () => currentChannel == expectedChannel);
|
||||
|
||||
// Selector reappearing after all channels closed
|
||||
AddUntilStep("Close all channels", () =>
|
||||
{
|
||||
if (!joinedChannels.Any())
|
||||
return true;
|
||||
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(joinedChannels.Last());
|
||||
return false;
|
||||
});
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChannelCloseButton()
|
||||
{
|
||||
AddStep("Join 2 channels", () =>
|
||||
{
|
||||
channelManager.JoinChannel(channel1);
|
||||
channelManager.JoinChannel(channel2);
|
||||
});
|
||||
|
||||
// PM channel close button only appears when active
|
||||
AddStep("Select PM channel", () => clickDrawable(chatOverlay.TabMap[channel2]));
|
||||
AddStep("Click PM close button", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child));
|
||||
AddAssert("PM channel closed", () => !channelManager.JoinedChannels.Contains(channel2));
|
||||
|
||||
// Non-PM chat channel close button only appears when hovered
|
||||
AddStep("Hover normal channel tab", () => InputManager.MoveMouseTo(chatOverlay.TabMap[channel1]));
|
||||
AddStep("Click normal close button", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child));
|
||||
AddAssert("All channels closed", () => !channelManager.JoinedChannels.Any());
|
||||
}
|
||||
|
||||
private void pressChannelHotkey(int number)
|
||||
{
|
||||
var channelKey = Key.Number0 + number;
|
||||
@ -187,6 +268,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value;
|
||||
|
||||
public new ChannelTabControl ChannelTabControl => base.ChannelTabControl;
|
||||
|
||||
public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay;
|
||||
|
||||
protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl();
|
||||
@ -196,12 +279,22 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private class TestTabControl : ChannelTabControl
|
||||
{
|
||||
protected override TabItem<Channel> CreateTabItem(Channel value) => new TestChannelTabItem(value);
|
||||
protected override TabItem<Channel> CreateTabItem(Channel value)
|
||||
{
|
||||
switch (value.Type)
|
||||
{
|
||||
case ChannelType.PM:
|
||||
return new TestPrivateChannelTabItem(value);
|
||||
|
||||
default:
|
||||
return new TestChannelTabItem(value);
|
||||
}
|
||||
}
|
||||
|
||||
public new IReadOnlyDictionary<Channel, TabItem<Channel>> TabMap => base.TabMap;
|
||||
}
|
||||
|
||||
private class TestChannelTabItem : PrivateChannelTabItem
|
||||
private class TestChannelTabItem : ChannelTabItem
|
||||
{
|
||||
public TestChannelTabItem(Channel channel)
|
||||
: base(channel)
|
||||
@ -210,5 +303,15 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
public new ClickableContainer CloseButton => base.CloseButton;
|
||||
}
|
||||
|
||||
private class TestPrivateChannelTabItem : PrivateChannelTabItem
|
||||
{
|
||||
public TestPrivateChannelTabItem(Channel channel)
|
||||
: base(channel)
|
||||
{
|
||||
}
|
||||
|
||||
public new ClickableContainer CloseButton => base.CloseButton;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
87
osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs
Normal file
87
osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs
Normal file
@ -0,0 +1,87 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Overlays.Dashboard.Friends;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneFriendDisplay : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(FriendDisplay),
|
||||
typeof(FriendOnlineStreamControl),
|
||||
typeof(UserListToolbar)
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
private FriendDisplay display;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Child = new BasicScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = display = new FriendDisplay()
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestOffline()
|
||||
{
|
||||
AddStep("Populate", () => display.Users = getUsers());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnline()
|
||||
{
|
||||
AddStep("Fetch online", () => display?.Fetch());
|
||||
}
|
||||
|
||||
private List<User> getUsers() => new List<User>
|
||||
{
|
||||
new User
|
||||
{
|
||||
Username = "flyte",
|
||||
Id = 3103765,
|
||||
IsOnline = true,
|
||||
CurrentModeRank = 1111,
|
||||
Country = new Country { FlagName = "JP" },
|
||||
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
|
||||
},
|
||||
new User
|
||||
{
|
||||
Username = "peppy",
|
||||
Id = 2,
|
||||
IsOnline = false,
|
||||
CurrentModeRank = 2222,
|
||||
Country = new Country { FlagName = "AU" },
|
||||
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||
IsSupporter = true,
|
||||
SupportLevel = 3,
|
||||
},
|
||||
new User
|
||||
{
|
||||
Username = "Evast",
|
||||
Id = 8195163,
|
||||
Country = new Country { FlagName = "BY" },
|
||||
CoverUrl = "https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg",
|
||||
IsOnline = false,
|
||||
LastVisit = DateTimeOffset.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -18,10 +18,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(UserPanel),
|
||||
typeof(SocialPanel),
|
||||
typeof(FilterControl),
|
||||
typeof(SocialGridPanel),
|
||||
typeof(SocialListPanel)
|
||||
typeof(UserGridPanel),
|
||||
typeof(UserListPanel)
|
||||
};
|
||||
|
||||
public TestSceneSocialOverlay()
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -15,9 +17,18 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[TestFixture]
|
||||
public class TestSceneUserPanel : OsuTestScene
|
||||
{
|
||||
private readonly Bindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(UserPanel),
|
||||
typeof(UserListPanel),
|
||||
typeof(UserGridPanel),
|
||||
};
|
||||
|
||||
private UserPanel peppy;
|
||||
private readonly Bindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
private readonly Bindable<UserStatus> status = new Bindable<UserStatus>();
|
||||
|
||||
private UserGridPanel peppy;
|
||||
private TestUserListPanel evast;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesetStore { get; set; }
|
||||
@ -25,24 +36,28 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
UserPanel flyte;
|
||||
UserGridPanel flyte;
|
||||
|
||||
activity.Value = null;
|
||||
status.Value = null;
|
||||
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Spacing = new Vector2(10f),
|
||||
Children = new[]
|
||||
Children = new Drawable[]
|
||||
{
|
||||
flyte = new UserPanel(new User
|
||||
flyte = new UserGridPanel(new User
|
||||
{
|
||||
Username = @"flyte",
|
||||
Id = 3103765,
|
||||
Country = new Country { FlagName = @"JP" },
|
||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
|
||||
}) { Width = 300 },
|
||||
peppy = new UserPanel(new User
|
||||
peppy = new UserGridPanel(new User
|
||||
{
|
||||
Username = @"peppy",
|
||||
Id = 2,
|
||||
@ -51,27 +66,40 @@ namespace osu.Game.Tests.Visual.Online
|
||||
IsSupporter = true,
|
||||
SupportLevel = 3,
|
||||
}) { Width = 300 },
|
||||
evast = new TestUserListPanel(new User
|
||||
{
|
||||
Username = @"Evast",
|
||||
Id = 8195163,
|
||||
Country = new Country { FlagName = @"BY" },
|
||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg",
|
||||
IsOnline = false,
|
||||
LastVisit = DateTimeOffset.Now
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
flyte.Status.Value = new UserStatusOnline();
|
||||
peppy.Status.Value = null;
|
||||
|
||||
peppy.Status.BindTo(status);
|
||||
peppy.Activity.BindTo(activity);
|
||||
|
||||
evast.Status.BindTo(status);
|
||||
evast.Activity.BindTo(activity);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestUserStatus()
|
||||
{
|
||||
AddStep("online", () => peppy.Status.Value = new UserStatusOnline());
|
||||
AddStep("do not disturb", () => peppy.Status.Value = new UserStatusDoNotDisturb());
|
||||
AddStep("offline", () => peppy.Status.Value = new UserStatusOffline());
|
||||
AddStep("null status", () => peppy.Status.Value = null);
|
||||
AddStep("online", () => status.Value = new UserStatusOnline());
|
||||
AddStep("do not disturb", () => status.Value = new UserStatusDoNotDisturb());
|
||||
AddStep("offline", () => status.Value = new UserStatusOffline());
|
||||
AddStep("null status", () => status.Value = null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUserActivity()
|
||||
{
|
||||
AddStep("set online status", () => peppy.Status.Value = new UserStatusOnline());
|
||||
AddStep("set online status", () => status.Value = new UserStatusOnline());
|
||||
|
||||
AddStep("idle", () => activity.Value = null);
|
||||
AddStep("spectating", () => activity.Value = new UserActivity.Spectating());
|
||||
@ -84,6 +112,29 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep("modding", () => activity.Value = new UserActivity.Modding());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUserActivityChange()
|
||||
{
|
||||
AddAssert("visit message is visible", () => evast.LastVisitMessage.IsPresent);
|
||||
AddStep("set online status", () => status.Value = new UserStatusOnline());
|
||||
AddAssert("visit message is not visible", () => !evast.LastVisitMessage.IsPresent);
|
||||
AddStep("set choosing activity", () => activity.Value = new UserActivity.ChoosingBeatmap());
|
||||
AddStep("set offline status", () => status.Value = new UserStatusOffline());
|
||||
AddAssert("visit message is visible", () => evast.LastVisitMessage.IsPresent);
|
||||
AddStep("set online status", () => status.Value = new UserStatusOnline());
|
||||
AddAssert("visit message is not visible", () => !evast.LastVisitMessage.IsPresent);
|
||||
}
|
||||
|
||||
private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.SoloGame(null, rulesetStore.GetRuleset(rulesetId));
|
||||
|
||||
private class TestUserListPanel : UserListPanel
|
||||
{
|
||||
public TestUserListPanel(User user)
|
||||
: base(user)
|
||||
{
|
||||
}
|
||||
|
||||
public new TextFlowContainer LastVisitMessage => base.LastVisitMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
165
osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
Normal file
165
osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
Normal file
@ -0,0 +1,165 @@
|
||||
// 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Expanded.Accuracy;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneAccuracyCircle : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(AccuracyCircle),
|
||||
typeof(RankBadge),
|
||||
typeof(RankNotch),
|
||||
typeof(RankText),
|
||||
typeof(SmoothCircularProgress)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestLowDRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.2;
|
||||
score.Rank = ScoreRank.D;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.5;
|
||||
score.Rank = ScoreRank.D;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.75;
|
||||
score.Rank = ScoreRank.C;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.85;
|
||||
score.Rank = ScoreRank.B;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestARank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.975;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAlmostSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.9999;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 1;
|
||||
score.Rank = ScoreRank.X;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
private void addCircleStep(ScoreInfo score) => AddStep("add panel", () =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 700),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#555"), Color4Extensions.FromHex("#333"))
|
||||
}
|
||||
}
|
||||
},
|
||||
new AccuracyCircle(score)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(230)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
private ScoreInfo createScore() => new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
},
|
||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||
TotalScore = 2845370,
|
||||
Accuracy = 0.95,
|
||||
MaxCombo = 999,
|
||||
Rank = ScoreRank.S,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics =
|
||||
{
|
||||
{ HitResult.Miss, 1 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Good, 100 },
|
||||
{ HitResult.Great, 300 },
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osu.Game.Screens.Ranking.Expanded.Accuracy;
|
||||
using osu.Game.Screens.Ranking.Expanded.Statistics;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneExpandedPanelMiddleContent : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private RulesetStore rulesetStore { get; set; }
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ExpandedPanelMiddleContent),
|
||||
typeof(AccuracyCircle),
|
||||
typeof(AccuracyStatistic),
|
||||
typeof(ComboStatistic),
|
||||
typeof(CounterStatistic),
|
||||
typeof(StarRatingDisplay),
|
||||
typeof(StatisticDisplay),
|
||||
typeof(TotalScoreCounter)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestMapWithKnownMapper()
|
||||
{
|
||||
var author = new User { Username = "mapper_name" };
|
||||
|
||||
AddStep("show example score", () => showPanel(createTestBeatmap(author), createTestScore()));
|
||||
|
||||
AddAssert("mapper name present", () => this.ChildrenOfType<OsuSpriteText>().Any(spriteText => spriteText.Text == "mapper_name"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMapWithUnknownMapper()
|
||||
{
|
||||
AddStep("show example score", () => showPanel(createTestBeatmap(null), createTestScore()));
|
||||
|
||||
AddAssert("mapped by text not present", () =>
|
||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text, "mapped", "by")));
|
||||
}
|
||||
|
||||
private void showPanel(WorkingBeatmap workingBeatmap, ScoreInfo score)
|
||||
{
|
||||
Child = new ExpandedPanelMiddleContentContainer(workingBeatmap, score);
|
||||
}
|
||||
|
||||
private WorkingBeatmap createTestBeatmap(User author)
|
||||
{
|
||||
var beatmap = new TestBeatmap(rulesetStore.GetRuleset(0));
|
||||
beatmap.Metadata.Author = author;
|
||||
|
||||
return new TestWorkingBeatmap(beatmap);
|
||||
}
|
||||
|
||||
private ScoreInfo createTestScore() => new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
},
|
||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||
TotalScore = 999999,
|
||||
Accuracy = 0.95,
|
||||
MaxCombo = 999,
|
||||
Rank = ScoreRank.S,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics =
|
||||
{
|
||||
{ HitResult.Miss, 1 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Good, 100 },
|
||||
{ HitResult.Great, 300 },
|
||||
}
|
||||
};
|
||||
|
||||
private bool containsAny(string text, params string[] stringsToMatch) => stringsToMatch.Any(text.Contains);
|
||||
|
||||
private class ExpandedPanelMiddleContentContainer : Container
|
||||
{
|
||||
[Cached]
|
||||
private Bindable<WorkingBeatmap> workingBeatmap { get; set; }
|
||||
|
||||
public ExpandedPanelMiddleContentContainer(WorkingBeatmap beatmap, ScoreInfo score)
|
||||
{
|
||||
workingBeatmap = new Bindable<WorkingBeatmap>(beatmap);
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
Size = new Vector2(500, 700);
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#444"),
|
||||
},
|
||||
new ExpandedPanelMiddleContent(score)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneExpandedPanelTopContent : OsuTestScene
|
||||
{
|
||||
public TestSceneExpandedPanelTopContent()
|
||||
{
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 200),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#444"),
|
||||
},
|
||||
new ExpandedPanelTopContent(new User { Id = 2, Username = "peppy" }),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -10,29 +10,27 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Pages;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneResults : ScreenTestScene
|
||||
public class TestSceneResultsScreen : ScreenTestScene
|
||||
{
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(Results),
|
||||
typeof(ResultsPage),
|
||||
typeof(ScoreResultsPage),
|
||||
typeof(ResultsScreen),
|
||||
typeof(RetryButton),
|
||||
typeof(ReplayDownloadButton),
|
||||
typeof(LocalLeaderboardPage),
|
||||
typeof(TestPlayer)
|
||||
};
|
||||
|
||||
@ -65,6 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Miss, 1 }
|
||||
},
|
||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
||||
User = new User
|
||||
{
|
||||
Username = "peppy",
|
||||
@ -119,7 +118,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSoloResults : SoloResults
|
||||
private class TestSoloResults : ResultsScreen
|
||||
{
|
||||
public HotkeyRetryOverlay RetryOverlay;
|
||||
|
143
osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs
Normal file
143
osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs
Normal file
@ -0,0 +1,143 @@
|
||||
// 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneScorePanel : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ScorePanel),
|
||||
typeof(PanelState),
|
||||
typeof(ExpandedPanelMiddleContent),
|
||||
typeof(ExpandedPanelTopContent),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestDRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.5;
|
||||
score.Rank = ScoreRank.D;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.75;
|
||||
score.Rank = ScoreRank.C;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.85;
|
||||
score.Rank = ScoreRank.B;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestARank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.975;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAlmostSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.9999;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 1;
|
||||
score.Rank = ScoreRank.X;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAllHitResults()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Statistics[HitResult.Perfect] = 350;
|
||||
score.Statistics[HitResult.Ok] = 200;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
|
||||
private void addPanelStep(ScoreInfo score) => AddStep("add panel", () =>
|
||||
{
|
||||
Child = new ScorePanel(score)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
State = PanelState.Expanded
|
||||
};
|
||||
});
|
||||
|
||||
private ScoreInfo createScore() => new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
},
|
||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||
TotalScore = 2845370,
|
||||
Accuracy = 0.95,
|
||||
MaxCombo = 999,
|
||||
Rank = ScoreRank.S,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics =
|
||||
{
|
||||
{ HitResult.Miss, 1 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Good, 100 },
|
||||
{ HitResult.Great, 300 },
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
32
osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs
Normal file
32
osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneStarRatingDisplay : OsuTestScene
|
||||
{
|
||||
public TestSceneStarRatingDisplay()
|
||||
{
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 1.23 }),
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 2.34 }),
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 3.45 }),
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 4.56 }),
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 5.67 }),
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 6.78 }),
|
||||
new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 10.11 }),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -227,6 +227,34 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
waitForSelection(set_count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectionEnteringFromEmptyRuleset()
|
||||
{
|
||||
var sets = new List<BeatmapSetInfo>();
|
||||
|
||||
AddStep("Create beatmaps for taiko only", () =>
|
||||
{
|
||||
sets.Clear();
|
||||
|
||||
var rulesetBeatmapSet = createTestBeatmapSet(1);
|
||||
var taikoRuleset = rulesets.AvailableRulesets.ElementAt(1);
|
||||
rulesetBeatmapSet.Beatmaps.ForEach(b =>
|
||||
{
|
||||
b.Ruleset = taikoRuleset;
|
||||
b.RulesetID = 1;
|
||||
});
|
||||
|
||||
sets.Add(rulesetBeatmapSet);
|
||||
});
|
||||
|
||||
loadBeatmaps(sets, () => new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) });
|
||||
|
||||
AddStep("Set non-empty mode filter", () =>
|
||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1) }, false));
|
||||
|
||||
AddAssert("Something is selected", () => carousel.SelectedBeatmap != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test sorting
|
||||
/// </summary>
|
||||
@ -399,27 +427,32 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("filter to ruleset 0", () =>
|
||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false));
|
||||
AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false));
|
||||
AddAssert("unfiltered beatmap selected", () => carousel.SelectedBeatmap.Equals(testMixed.Beatmaps[0]));
|
||||
AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmap.RulesetID == 0);
|
||||
|
||||
AddStep("remove mixed set", () =>
|
||||
{
|
||||
carousel.RemoveBeatmapSet(testMixed);
|
||||
testMixed = null;
|
||||
});
|
||||
var testSingle = createTestBeatmapSet(set_count + 2);
|
||||
testSingle.Beatmaps.ForEach(b =>
|
||||
BeatmapSetInfo testSingle = null;
|
||||
AddStep("add single ruleset beatmapset", () =>
|
||||
{
|
||||
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
|
||||
b.RulesetID = b.Ruleset.ID ?? 1;
|
||||
testSingle = createTestBeatmapSet(set_count + 2);
|
||||
testSingle.Beatmaps.ForEach(b =>
|
||||
{
|
||||
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
|
||||
b.RulesetID = b.Ruleset.ID ?? 1;
|
||||
});
|
||||
|
||||
carousel.UpdateBeatmapSet(testSingle);
|
||||
});
|
||||
AddStep("add single ruleset beatmapset", () => carousel.UpdateBeatmapSet(testSingle));
|
||||
AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testSingle.Beatmaps[0], false));
|
||||
checkNoSelection();
|
||||
AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCarouselRootIsRandom()
|
||||
public void TestCarouselRemembersSelection()
|
||||
{
|
||||
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
|
||||
|
||||
@ -429,12 +462,74 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
loadBeatmaps(manySets);
|
||||
|
||||
advanceSelection(direction: 1, diff: false);
|
||||
checkNonmatchingFilter();
|
||||
checkNonmatchingFilter();
|
||||
checkNonmatchingFilter();
|
||||
checkNonmatchingFilter();
|
||||
checkNonmatchingFilter();
|
||||
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 1);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
AddStep("Toggle non-matching filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false);
|
||||
});
|
||||
|
||||
AddStep("Restore no filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria(), false);
|
||||
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID);
|
||||
});
|
||||
}
|
||||
|
||||
// always returns to same selection as long as it's available.
|
||||
AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRandomFallbackOnNonMatchingPrevious()
|
||||
{
|
||||
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
|
||||
|
||||
AddStep("populate maps", () =>
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var set = createTestBeatmapSet(i);
|
||||
|
||||
foreach (var b in set.Beatmaps)
|
||||
{
|
||||
// all taiko except for first
|
||||
int ruleset = i > 0 ? 1 : 0;
|
||||
|
||||
b.Ruleset = rulesets.GetRuleset(ruleset);
|
||||
b.RulesetID = ruleset;
|
||||
}
|
||||
|
||||
manySets.Add(set);
|
||||
}
|
||||
});
|
||||
|
||||
loadBeatmaps(manySets);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
AddStep("Reset filter", () => carousel.Filter(new FilterCriteria(), false));
|
||||
|
||||
AddStep("select first beatmap", () => carousel.SelectBeatmap(manySets.First().Beatmaps.First()));
|
||||
|
||||
AddStep("Toggle non-matching filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false);
|
||||
});
|
||||
|
||||
AddAssert("selection lost", () => carousel.SelectedBeatmap == null);
|
||||
|
||||
AddStep("Restore different ruleset filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false);
|
||||
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID);
|
||||
});
|
||||
|
||||
AddAssert("selection changed", () => carousel.SelectedBeatmap != manySets.First().Beatmaps.First());
|
||||
}
|
||||
|
||||
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -484,7 +579,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
checkVisibleItemCount(true, 15);
|
||||
}
|
||||
|
||||
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null)
|
||||
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null, Func<FilterCriteria> initialCriteria = null)
|
||||
{
|
||||
createCarousel();
|
||||
|
||||
@ -499,7 +594,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
bool changed = false;
|
||||
AddStep($"Load {(beatmapSets.Count > 0 ? beatmapSets.Count.ToString() : "some")} beatmaps", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria());
|
||||
carousel.Filter(initialCriteria?.Invoke() ?? new FilterCriteria());
|
||||
carousel.BeatmapSetsChanged = () => changed = true;
|
||||
carousel.BeatmapSets = beatmapSets;
|
||||
});
|
||||
@ -593,16 +688,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddAssert("Selection is visible", selectedBeatmapVisible);
|
||||
}
|
||||
|
||||
private void checkNonmatchingFilter()
|
||||
{
|
||||
AddStep("Toggle non-matching filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { SearchText = "Dingo" }, false);
|
||||
carousel.Filter(new FilterCriteria(), false);
|
||||
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID);
|
||||
});
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createTestBeatmapSet(int id)
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
|
@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("import multi-ruleset map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
|
||||
manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait();
|
||||
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
|
||||
});
|
||||
}
|
||||
else
|
||||
@ -436,6 +436,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
changeRuleset(0);
|
||||
|
||||
// used for filter check below
|
||||
AddStep("allow convert display", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
|
||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||
|
||||
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nonono");
|
||||
@ -446,16 +449,28 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
BeatmapInfo target = null;
|
||||
|
||||
int targetRuleset = differentRuleset ? 1 : 0;
|
||||
|
||||
AddStep("select beatmap externally", () =>
|
||||
{
|
||||
target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == (differentRuleset ? 1 : 0)))
|
||||
.ElementAt(5).Beatmaps.First();
|
||||
target = manager.GetAllUsableBeatmapSets()
|
||||
.Where(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset))
|
||||
.ElementAt(5).Beatmaps.First(bi => bi.RulesetID == targetRuleset);
|
||||
|
||||
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
||||
});
|
||||
|
||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||
|
||||
AddAssert("selected only shows expected ruleset (plus converts)", () =>
|
||||
{
|
||||
var selectedPanel = songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmapSet>().First(s => s.Item.State.Value == CarouselItemState.Selected);
|
||||
|
||||
// special case for converts checked here.
|
||||
return selectedPanel.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>().All(i =>
|
||||
i.IsFiltered || i.Item.Beatmap.Ruleset.ID == targetRuleset || i.Item.Beatmap.Ruleset.ID == 0);
|
||||
});
|
||||
|
||||
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID);
|
||||
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
||||
|
||||
@ -557,6 +572,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
difficultyIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>()
|
||||
.First(icon => getDifficultyIconIndex(set, icon) != getCurrentBeatmapIndex());
|
||||
});
|
||||
|
||||
AddStep("Click on a difficulty", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(difficultyIcon);
|
||||
@ -564,6 +580,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon));
|
||||
|
||||
double? maxBPM = null;
|
||||
@ -576,16 +593,16 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
}
|
||||
}));
|
||||
|
||||
BeatmapInfo filteredBeatmap = null;
|
||||
DrawableCarouselBeatmapSet.FilterableDifficultyIcon filteredIcon = null;
|
||||
|
||||
AddStep("Get filtered icon", () =>
|
||||
{
|
||||
var filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM);
|
||||
filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.First(b => b.BPM < maxBPM);
|
||||
int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap);
|
||||
filteredIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>().ElementAt(filteredBeatmapIndex);
|
||||
});
|
||||
|
||||
int? previousID = null;
|
||||
AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmap.ID);
|
||||
AddStep("Click on a filtered difficulty", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(filteredIcon);
|
||||
@ -593,7 +610,101 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID);
|
||||
|
||||
AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDifficultyIconSelectingForDifferentRuleset()
|
||||
{
|
||||
changeRuleset(0);
|
||||
|
||||
createSongSelect();
|
||||
|
||||
AddStep("import multi-ruleset map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
|
||||
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
|
||||
});
|
||||
|
||||
DrawableCarouselBeatmapSet set = null;
|
||||
AddUntilStep("Find the DrawableCarouselBeatmapSet", () =>
|
||||
{
|
||||
set = songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmapSet>().FirstOrDefault();
|
||||
return set != null;
|
||||
});
|
||||
|
||||
DrawableCarouselBeatmapSet.FilterableDifficultyIcon difficultyIcon = null;
|
||||
AddStep("Find an icon for different ruleset", () =>
|
||||
{
|
||||
difficultyIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>()
|
||||
.First(icon => icon.Item.Beatmap.Ruleset.ID == 3);
|
||||
});
|
||||
|
||||
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
|
||||
|
||||
int previousSetID = 0;
|
||||
|
||||
AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID);
|
||||
|
||||
AddStep("Click on a difficulty", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(difficultyIcon);
|
||||
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
||||
|
||||
AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmap.BeatmapSet.ID == previousSetID);
|
||||
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGroupedDifficultyIconSelecting()
|
||||
{
|
||||
changeRuleset(0);
|
||||
|
||||
createSongSelect();
|
||||
|
||||
BeatmapSetInfo imported = null;
|
||||
|
||||
AddStep("import huge difficulty count map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
|
||||
imported = manager.Import(createTestBeatmapSet(usableRulesets, 50)).Result;
|
||||
});
|
||||
|
||||
AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First()));
|
||||
|
||||
DrawableCarouselBeatmapSet set = null;
|
||||
AddUntilStep("Find the DrawableCarouselBeatmapSet", () =>
|
||||
{
|
||||
set = songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmapSet>().FirstOrDefault();
|
||||
return set != null;
|
||||
});
|
||||
|
||||
DrawableCarouselBeatmapSet.FilterableGroupedDifficultyIcon groupIcon = null;
|
||||
AddStep("Find group icon for different ruleset", () =>
|
||||
{
|
||||
groupIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableGroupedDifficultyIcon>()
|
||||
.First(icon => icon.Items.First().Beatmap.Ruleset.ID == 3);
|
||||
});
|
||||
|
||||
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
|
||||
|
||||
AddStep("Click on group", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(groupIcon);
|
||||
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
||||
|
||||
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo == groupIcon.Items.First().Beatmap);
|
||||
}
|
||||
|
||||
private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info);
|
||||
@ -607,7 +718,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
|
||||
|
||||
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
|
||||
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
|
||||
|
||||
private static int importId;
|
||||
|
||||
@ -633,20 +744,22 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
|
||||
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
manager.Import(createTestBeatmapSet(i, usableRulesets)).Wait();
|
||||
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
|
||||
});
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createTestBeatmapSet(int setId, RulesetInfo[] rulesets)
|
||||
private BeatmapSetInfo createTestBeatmapSet(RulesetInfo[] rulesets, int countPerRuleset = 6)
|
||||
{
|
||||
int j = 0;
|
||||
RulesetInfo getRuleset() => rulesets[j++ % rulesets.Length];
|
||||
|
||||
int setId = getImportId();
|
||||
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < countPerRuleset; i++)
|
||||
{
|
||||
int beatmapId = setId * 10 + i;
|
||||
int beatmapId = setId * 1000 + i;
|
||||
|
||||
int length = RNG.Next(30000, 200000);
|
||||
double bpm = RNG.NextSingle(80, 200);
|
||||
|
@ -15,7 +15,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneCommentEditor : ManualInputManagerTestScene
|
||||
public class TestSceneCommentEditor : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCursors : ManualInputManagerTestScene
|
||||
public class TestSceneCursors : OsuManualInputManagerTestScene
|
||||
{
|
||||
private readonly MenuCursorContainer menuCursorContainer;
|
||||
private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6];
|
||||
|
@ -27,7 +27,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneDeleteLocalScore : ManualInputManagerTestScene
|
||||
public class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Home.Friends;
|
||||
using osu.Game.Overlays.Dashboard.Friends;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
@ -17,20 +17,20 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(FriendsOnlineStatusControl),
|
||||
typeof(FriendOnlineStreamControl),
|
||||
typeof(FriendsOnlineStatusItem),
|
||||
typeof(OverlayStreamControl<>),
|
||||
typeof(OverlayStreamItem<>),
|
||||
typeof(FriendsBundle)
|
||||
typeof(FriendStream)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
private FriendsOnlineStatusControl control;
|
||||
private FriendOnlineStreamControl control;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() => Child = control = new FriendsOnlineStatusControl
|
||||
public void SetUp() => Schedule(() => Child = control = new FriendOnlineStreamControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -55,9 +55,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
}
|
||||
}));
|
||||
|
||||
AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.All)?.Count == 3);
|
||||
AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Online)?.Count == 1);
|
||||
AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Offline)?.Count == 2);
|
||||
AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == OnlineStatus.All)?.Count == 3);
|
||||
AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == OnlineStatus.Online)?.Count == 1);
|
||||
AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == OnlineStatus.Offline)?.Count == 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneOsuHoverContainer : ManualInputManagerTestScene
|
||||
public class TestSceneOsuHoverContainer : OsuManualInputManagerTestScene
|
||||
{
|
||||
private OsuHoverTestContainer hoverContainer;
|
||||
private Box colourContainer;
|
||||
|
@ -12,7 +12,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneStatefulMenuItem : ManualInputManagerTestScene
|
||||
public class TestSceneStatefulMenuItem : OsuManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneSwitchButton : ManualInputManagerTestScene
|
||||
public class TestSceneSwitchButton : OsuManualInputManagerTestScene
|
||||
{
|
||||
private SwitchButton switchButton;
|
||||
|
||||
|
@ -8,7 +8,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Home.Friends;
|
||||
using osu.Game.Overlays.Dashboard.Friends;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
@ -6,7 +6,6 @@ using System.Linq;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Graphics.Video;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.IO;
|
||||
@ -51,8 +50,6 @@ namespace osu.Game.Tests
|
||||
|
||||
protected override Texture GetBackground() => null;
|
||||
|
||||
protected override VideoSprite GetVideo() => null;
|
||||
|
||||
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
||||
|
||||
protected override Track GetTrack() => trackStore.Get(firstAudioFile);
|
||||
|
@ -0,0 +1,40 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.Models;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Components
|
||||
{
|
||||
public class TestSceneRoundDisplay : TournamentTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableTournamentHeaderText),
|
||||
typeof(DrawableTournamentHeaderLogo),
|
||||
};
|
||||
|
||||
public TestSceneRoundDisplay()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new RoundDisplay(new TournamentMatch
|
||||
{
|
||||
Round =
|
||||
{
|
||||
Value = new TournamentRound
|
||||
{
|
||||
Name = { Value = "Test Round" }
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
Margin = new MarginPadding(20)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user