mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 07:22:55 +08:00
Merge branch 'master' into i-has-curve-with-repeats
This commit is contained in:
commit
0ef971be28
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.525.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.528.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Edit;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -19,8 +18,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
public abstract class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene
|
||||||
public abstract class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene, IManiaHitObjectComposer
|
|
||||||
{
|
{
|
||||||
private readonly Column column;
|
private readonly Column column;
|
||||||
|
|
||||||
|
@ -4,15 +4,13 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Mania.Edit;
|
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
public abstract class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene
|
||||||
public abstract class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene, IManiaHitObjectComposer
|
|
||||||
{
|
{
|
||||||
[Cached(Type = typeof(IAdjustableClock))]
|
[Cached(Type = typeof(IAdjustableClock))]
|
||||||
private readonly IAdjustableClock clock = new StopwatchClock();
|
private readonly IAdjustableClock clock = new StopwatchClock();
|
||||||
|
@ -2,23 +2,27 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Edit;
|
using osu.Game.Rulesets.Mania.Edit;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[Cached(typeof(IManiaHitObjectComposer))]
|
public class TestSceneManiaBeatSnapGrid : EditorClockTestScene
|
||||||
public class TestSceneManiaBeatSnapGrid : EditorClockTestScene, IManiaHitObjectComposer
|
|
||||||
{
|
{
|
||||||
[Cached(typeof(IScrollingInfo))]
|
[Cached(typeof(IScrollingInfo))]
|
||||||
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
|
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
|
||||||
@ -50,7 +54,10 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
Clock = new FramedClock(new StopwatchClock())
|
Clock = new FramedClock(new StopwatchClock())
|
||||||
},
|
},
|
||||||
beatSnapGrid = new ManiaBeatSnapGrid()
|
new TestHitObjectComposer(Playfield)
|
||||||
|
{
|
||||||
|
Child = beatSnapGrid = new ManiaBeatSnapGrid()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,4 +74,51 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
public ManiaPlayfield Playfield { get; }
|
public ManiaPlayfield Playfield { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TestHitObjectComposer : HitObjectComposer
|
||||||
|
{
|
||||||
|
public override Playfield Playfield { get; }
|
||||||
|
public override IEnumerable<DrawableHitObject> HitObjects => Enumerable.Empty<DrawableHitObject>();
|
||||||
|
public override bool CursorInPlacementArea => false;
|
||||||
|
|
||||||
|
public TestHitObjectComposer(Playfield playfield)
|
||||||
|
{
|
||||||
|
Playfield = playfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Child
|
||||||
|
{
|
||||||
|
set => InternalChild = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetBeatSnapDistanceAt(double referenceTime)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float DurationToDistance(double referenceTime, double duration)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double DistanceToDuration(double referenceTime, float distance)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetSnappedDurationFromDistance(double referenceTime, float distance)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetSnappedDistanceFromDistance(double referenceTime, float distance)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
private readonly EditNotePiece headPiece;
|
private readonly EditNotePiece headPiece;
|
||||||
private readonly EditNotePiece tailPiece;
|
private readonly EditNotePiece tailPiece;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IManiaHitObjectComposer composer { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IScrollingInfo scrollingInfo { get; set; }
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
|
|
||||||
|
@ -18,9 +18,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IScrollingInfo scrollingInfo { get; set; }
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IManiaHitObjectComposer composer { get; set; }
|
|
||||||
|
|
||||||
protected ManiaSelectionBlueprint(DrawableHitObject drawableObject)
|
protected ManiaSelectionBlueprint(DrawableHitObject drawableObject)
|
||||||
: base(drawableObject)
|
: base(drawableObject)
|
||||||
{
|
{
|
||||||
|
@ -1,12 +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 osu.Game.Rulesets.Mania.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit
|
|
||||||
{
|
|
||||||
public interface IManiaHitObjectComposer
|
|
||||||
{
|
|
||||||
ManiaPlayfield Playfield { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,8 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -63,9 +65,9 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
private (double start, double end)? selectionTimeRange;
|
private (double start, double end)? selectionTimeRange;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IManiaHitObjectComposer composer)
|
private void load(HitObjectComposer composer)
|
||||||
{
|
{
|
||||||
foreach (var stage in composer.Playfield.Stages)
|
foreach (var stage in ((ManiaPlayfield)composer.Playfield).Stages)
|
||||||
{
|
{
|
||||||
foreach (var column in stage.Columns)
|
foreach (var column in stage.Columns)
|
||||||
{
|
{
|
||||||
|
@ -20,8 +20,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit
|
namespace osu.Game.Rulesets.Mania.Edit
|
||||||
{
|
{
|
||||||
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>
|
||||||
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>, IManiaHitObjectComposer
|
|
||||||
{
|
{
|
||||||
private DrawableManiaEditRuleset drawableRuleset;
|
private DrawableManiaEditRuleset drawableRuleset;
|
||||||
private ManiaBeatSnapGrid beatSnapGrid;
|
private ManiaBeatSnapGrid beatSnapGrid;
|
||||||
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
public ManiaPlayfield Playfield => ((ManiaPlayfield)drawableRuleset.Playfield);
|
public new ManiaPlayfield Playfield => ((ManiaPlayfield)drawableRuleset.Playfield);
|
||||||
|
|
||||||
public IScrollingInfo ScrollingInfo => drawableRuleset.ScrollingInfo;
|
public IScrollingInfo ScrollingInfo => drawableRuleset.ScrollingInfo;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
private IScrollingInfo scrollingInfo { get; set; }
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IManiaHitObjectComposer composer { get; set; }
|
private HitObjectComposer composer { get; set; }
|
||||||
|
|
||||||
public override bool HandleMovement(MoveSelectionEvent moveEvent)
|
public override bool HandleMovement(MoveSelectionEvent moveEvent)
|
||||||
{
|
{
|
||||||
@ -31,7 +32,9 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
|
|
||||||
private void performColumnMovement(int lastColumn, MoveSelectionEvent moveEvent)
|
private void performColumnMovement(int lastColumn, MoveSelectionEvent moveEvent)
|
||||||
{
|
{
|
||||||
var currentColumn = composer.Playfield.GetColumnByPosition(moveEvent.ScreenSpacePosition);
|
var maniaPlayfield = ((ManiaHitObjectComposer)composer).Playfield;
|
||||||
|
|
||||||
|
var currentColumn = maniaPlayfield.GetColumnByPosition(moveEvent.ScreenSpacePosition);
|
||||||
if (currentColumn == null)
|
if (currentColumn == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -50,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
maxColumn = obj.Column;
|
maxColumn = obj.Column;
|
||||||
}
|
}
|
||||||
|
|
||||||
columnDelta = Math.Clamp(columnDelta, -minColumn, composer.Playfield.TotalColumns - 1 - maxColumn);
|
columnDelta = Math.Clamp(columnDelta, -minColumn, maniaPlayfield.TotalColumns - 1 - maxColumn);
|
||||||
|
|
||||||
foreach (var obj in SelectedHitObjects.OfType<ManiaHitObject>())
|
foreach (var obj in SelectedHitObjects.OfType<ManiaHitObject>())
|
||||||
obj.Column += columnDelta;
|
obj.Column += columnDelta;
|
||||||
|
@ -12,6 +12,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
|||||||
{
|
{
|
||||||
protected new T HitObject => (T)DrawableObject.HitObject;
|
protected new T HitObject => (T)DrawableObject.HitObject;
|
||||||
|
|
||||||
|
protected override bool AlwaysShowWhenSelected => true;
|
||||||
|
|
||||||
protected OsuSelectionBlueprint(DrawableHitObject drawableObject)
|
protected OsuSelectionBlueprint(DrawableHitObject drawableObject)
|
||||||
: base(drawableObject)
|
: base(drawableObject)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
{
|
{
|
||||||
internal class OsuScoreProcessor : ScoreProcessor
|
public class OsuScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement);
|
protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement);
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
// ReSharper disable once AccessToModifiedClosure
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
manager.ItemAdded.BindValueChanged(_ => Interlocked.Increment(ref itemAddRemoveFireCount));
|
manager.ItemUpdated.BindValueChanged(_ => Interlocked.Increment(ref itemAddRemoveFireCount));
|
||||||
manager.ItemRemoved.BindValueChanged(_ => Interlocked.Increment(ref itemAddRemoveFireCount));
|
manager.ItemRemoved.BindValueChanged(_ => Interlocked.Increment(ref itemAddRemoveFireCount));
|
||||||
|
|
||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
@ -166,7 +166,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
imported.Hash += "-changed";
|
imported.Hash += "-changed";
|
||||||
manager.Update(imported);
|
manager.Update(imported);
|
||||||
|
|
||||||
Assert.AreEqual(0, itemAddRemoveFireCount -= 2);
|
Assert.AreEqual(0, itemAddRemoveFireCount -= 1);
|
||||||
|
|
||||||
checkBeatmapSetCount(osu, 1);
|
checkBeatmapSetCount(osu, 1);
|
||||||
checkBeatmapCount(osu, 12);
|
checkBeatmapCount(osu, 12);
|
||||||
|
@ -28,6 +28,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep(@"locally available state", () => downloadButton.SetDownloadState(DownloadState.LocallyAvailable));
|
AddStep(@"locally available state", () => downloadButton.SetDownloadState(DownloadState.LocallyAvailable));
|
||||||
AddStep(@"not downloaded state", () => downloadButton.SetDownloadState(DownloadState.NotDownloaded));
|
AddStep(@"not downloaded state", () => downloadButton.SetDownloadState(DownloadState.NotDownloaded));
|
||||||
createButton(false);
|
createButton(false);
|
||||||
|
createButtonNoScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createButton(bool withReplay)
|
private void createButton(bool withReplay)
|
||||||
@ -40,6 +41,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createButtonNoScore()
|
||||||
|
{
|
||||||
|
AddStep("create button with null score", () =>
|
||||||
|
{
|
||||||
|
Child = downloadButton = new TestReplayDownloadButton(null)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScoreInfo getScoreInfo(bool replayAvailable)
|
private ScoreInfo getScoreInfo(bool replayAvailable)
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.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.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Ranking;
|
||||||
|
using osu.Game.Screens.Ranking.Contracted;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
|
{
|
||||||
|
public class TestSceneContractedPanelMiddleContent : OsuTestScene
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesetStore { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestShowPanel()
|
||||||
|
{
|
||||||
|
AddStep("show example score", () => showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new TestScoreInfo(new OsuRuleset().RulesetInfo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPanel(WorkingBeatmap workingBeatmap, ScoreInfo score)
|
||||||
|
{
|
||||||
|
Child = new ContractedPanelMiddleContentContainer(workingBeatmap, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ContractedPanelMiddleContentContainer : Container
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private Bindable<WorkingBeatmap> workingBeatmap { get; set; }
|
||||||
|
|
||||||
|
public ContractedPanelMiddleContentContainer(WorkingBeatmap beatmap, ScoreInfo score)
|
||||||
|
{
|
||||||
|
workingBeatmap = new Bindable<WorkingBeatmap>(beatmap);
|
||||||
|
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Size = new Vector2(ScorePanel.CONTRACTED_WIDTH, 460);
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4Extensions.FromHex("#353535"),
|
||||||
|
},
|
||||||
|
new ContractedPanelMiddleContent(score),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -14,10 +13,7 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
using osu.Game.Screens.Ranking.Expanded;
|
||||||
@ -37,7 +33,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
{
|
{
|
||||||
var author = new User { Username = "mapper_name" };
|
var author = new User { Username = "mapper_name" };
|
||||||
|
|
||||||
AddStep("show example score", () => showPanel(createTestBeatmap(author), createTestScore()));
|
AddStep("show example score", () => showPanel(createTestBeatmap(author), new TestScoreInfo(new OsuRuleset().RulesetInfo)));
|
||||||
|
|
||||||
AddAssert("mapper name present", () => this.ChildrenOfType<OsuSpriteText>().Any(spriteText => spriteText.Text == "mapper_name"));
|
AddAssert("mapper name present", () => this.ChildrenOfType<OsuSpriteText>().Any(spriteText => spriteText.Text == "mapper_name"));
|
||||||
}
|
}
|
||||||
@ -45,7 +41,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestMapWithUnknownMapper()
|
public void TestMapWithUnknownMapper()
|
||||||
{
|
{
|
||||||
AddStep("show example score", () => showPanel(createTestBeatmap(null), createTestScore()));
|
AddStep("show example score", () => showPanel(createTestBeatmap(null), new TestScoreInfo(new OsuRuleset().RulesetInfo)));
|
||||||
|
|
||||||
AddAssert("mapped by text not present", () =>
|
AddAssert("mapped by text not present", () =>
|
||||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text, "mapped", "by")));
|
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text, "mapped", "by")));
|
||||||
@ -66,29 +62,6 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
return new TestWorkingBeatmap(beatmap);
|
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 bool containsAny(string text, params string[] stringsToMatch) => stringsToMatch.Any(text.Contains);
|
||||||
|
|
||||||
private class ExpandedPanelMiddleContentContainer : Container
|
private class ExpandedPanelMiddleContentContainer : Container
|
||||||
|
@ -5,8 +5,8 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
using osu.Game.Screens.Ranking.Expanded;
|
||||||
using osu.Game.Users;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Ranking
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4Extensions.FromHex("#444"),
|
Colour = Color4Extensions.FromHex("#444"),
|
||||||
},
|
},
|
||||||
new ExpandedPanelTopContent(new User { Id = 2, Username = "peppy" }),
|
new ExpandedPanelTopContent(new TestScoreInfo(new OsuRuleset().RulesetInfo).User),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -11,13 +9,10 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Tests.Beatmaps;
|
|
||||||
using osu.Game.Users;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Ranking
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
{
|
{
|
||||||
@ -41,26 +36,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestSoloResults createResultsScreen() => new TestSoloResults(new ScoreInfo
|
private TestSoloResults createResultsScreen() => new TestSoloResults(new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||||
{
|
|
||||||
TotalScore = 2845370,
|
|
||||||
Accuracy = 0.98,
|
|
||||||
MaxCombo = 123,
|
|
||||||
Rank = ScoreRank.A,
|
|
||||||
Date = DateTimeOffset.Now,
|
|
||||||
Statistics = new Dictionary<HitResult, int>
|
|
||||||
{
|
|
||||||
{ HitResult.Great, 50 },
|
|
||||||
{ HitResult.Good, 20 },
|
|
||||||
{ HitResult.Meh, 50 },
|
|
||||||
{ HitResult.Miss, 1 }
|
|
||||||
},
|
|
||||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
|
||||||
User = new User
|
|
||||||
{
|
|
||||||
Username = "peppy",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ResultsWithoutPlayer()
|
public void ResultsWithoutPlayer()
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Tests.Beatmaps;
|
|
||||||
using osu.Game.Users;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Ranking
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
{
|
{
|
||||||
public class TestSceneScorePanel : OsuTestScene
|
public class TestSceneScorePanel : OsuTestScene
|
||||||
{
|
{
|
||||||
|
private ScorePanel panel;
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDRank()
|
public void TestDRank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.5, Rank = ScoreRank.D };
|
||||||
score.Accuracy = 0.5;
|
|
||||||
score.Rank = ScoreRank.D;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -30,9 +25,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCRank()
|
public void TestCRank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.75, Rank = ScoreRank.C };
|
||||||
score.Accuracy = 0.75;
|
|
||||||
score.Rank = ScoreRank.C;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -40,9 +33,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBRank()
|
public void TestBRank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.85, Rank = ScoreRank.B };
|
||||||
score.Accuracy = 0.85;
|
|
||||||
score.Rank = ScoreRank.B;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -50,9 +41,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestARank()
|
public void TestARank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||||
score.Accuracy = 0.925;
|
|
||||||
score.Rank = ScoreRank.A;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -60,9 +49,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestSRank()
|
public void TestSRank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.975, Rank = ScoreRank.S };
|
||||||
score.Accuracy = 0.975;
|
|
||||||
score.Rank = ScoreRank.S;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -70,9 +57,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestAlmostSSRank()
|
public void TestAlmostSSRank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.9999, Rank = ScoreRank.S };
|
||||||
score.Accuracy = 0.9999;
|
|
||||||
score.Rank = ScoreRank.S;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -80,9 +65,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestSSRank()
|
public void TestSSRank()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 1, Rank = ScoreRank.X };
|
||||||
score.Accuracy = 1;
|
|
||||||
score.Rank = ScoreRank.X;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
@ -90,44 +73,42 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestAllHitResults()
|
public void TestAllHitResults()
|
||||||
{
|
{
|
||||||
var score = createScore();
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Statistics = { [HitResult.Perfect] = 350, [HitResult.Ok] = 200 } };
|
||||||
score.Statistics[HitResult.Perfect] = 350;
|
|
||||||
score.Statistics[HitResult.Ok] = 200;
|
|
||||||
|
|
||||||
addPanelStep(score);
|
addPanelStep(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPanelStep(ScoreInfo score) => AddStep("add panel", () =>
|
[Test]
|
||||||
|
public void TestContractedPanel()
|
||||||
{
|
{
|
||||||
Child = new ScorePanel(score)
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||||
|
|
||||||
|
addPanelStep(score, PanelState.Contracted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestExpandAndContract()
|
||||||
|
{
|
||||||
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||||
|
|
||||||
|
addPanelStep(score, PanelState.Contracted);
|
||||||
|
AddWaitStep("wait for transition", 10);
|
||||||
|
|
||||||
|
AddStep("expand panel", () => panel.State = PanelState.Expanded);
|
||||||
|
AddWaitStep("wait for transition", 10);
|
||||||
|
|
||||||
|
AddStep("contract panel", () => panel.State = PanelState.Contracted);
|
||||||
|
AddWaitStep("wait for transition", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPanelStep(ScoreInfo score, PanelState state = PanelState.Expanded) => AddStep("add panel", () =>
|
||||||
|
{
|
||||||
|
Child = panel = new ScorePanel(score)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
State = PanelState.Expanded
|
State = state
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
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 },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
208
osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs
Normal file
208
osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Ranking;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
|
{
|
||||||
|
public class TestSceneScorePanelList : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
private ScorePanelList list;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestEmptyList()
|
||||||
|
{
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestEmptyListWithSelectedScore()
|
||||||
|
{
|
||||||
|
createListStep(() => new ScorePanelList
|
||||||
|
{
|
||||||
|
SelectedScore = { Value = new TestScoreInfo(new OsuRuleset().RulesetInfo) }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddPanelAfterSelectingScore()
|
||||||
|
{
|
||||||
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
createListStep(() => new ScorePanelList
|
||||||
|
{
|
||||||
|
SelectedScore = { Value = score }
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("add panel", () => list.AddScore(score));
|
||||||
|
|
||||||
|
assertScoreState(score, true);
|
||||||
|
assertExpandedPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddPanelBeforeSelectingScore()
|
||||||
|
{
|
||||||
|
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
|
||||||
|
AddStep("add panel", () => list.AddScore(score));
|
||||||
|
|
||||||
|
assertScoreState(score, false);
|
||||||
|
assertFirstPanelCentred();
|
||||||
|
|
||||||
|
AddStep("select score", () => list.SelectedScore.Value = score);
|
||||||
|
|
||||||
|
assertScoreState(score, true);
|
||||||
|
assertExpandedPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddManyNonExpandedPanels()
|
||||||
|
{
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
|
||||||
|
AddStep("add many scores", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertFirstPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddManyScoresAfterExpandedPanel()
|
||||||
|
{
|
||||||
|
var initialScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
|
||||||
|
AddStep("add initial panel and select", () =>
|
||||||
|
{
|
||||||
|
list.AddScore(initialScore);
|
||||||
|
list.SelectedScore.Value = initialScore;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("add many scores", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore - i - 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
assertScoreState(initialScore, true);
|
||||||
|
assertExpandedPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddManyScoresBeforeExpandedPanel()
|
||||||
|
{
|
||||||
|
var initialScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
|
||||||
|
AddStep("add initial panel and select", () =>
|
||||||
|
{
|
||||||
|
list.AddScore(initialScore);
|
||||||
|
list.SelectedScore.Value = initialScore;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("add scores", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore + i + 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
assertScoreState(initialScore, true);
|
||||||
|
assertExpandedPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddManyPanelsOnBothSidesOfExpandedPanel()
|
||||||
|
{
|
||||||
|
var initialScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
|
||||||
|
AddStep("add initial panel and select", () =>
|
||||||
|
{
|
||||||
|
list.AddScore(initialScore);
|
||||||
|
list.SelectedScore.Value = initialScore;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("add scores after", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore - i - 1 });
|
||||||
|
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore + i + 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
assertScoreState(initialScore, true);
|
||||||
|
assertExpandedPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSelectMultipleScores()
|
||||||
|
{
|
||||||
|
var firstScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
var secondScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
createListStep(() => new ScorePanelList());
|
||||||
|
|
||||||
|
AddStep("add scores and select first", () =>
|
||||||
|
{
|
||||||
|
list.AddScore(firstScore);
|
||||||
|
list.AddScore(secondScore);
|
||||||
|
list.SelectedScore.Value = firstScore;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertScoreState(firstScore, true);
|
||||||
|
assertScoreState(secondScore, false);
|
||||||
|
|
||||||
|
AddStep("select second score", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(list.ChildrenOfType<ScorePanel>().Single(p => p.Score == secondScore));
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertScoreState(firstScore, false);
|
||||||
|
assertScoreState(secondScore, true);
|
||||||
|
assertExpandedPanelCentred();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createListStep(Func<ScorePanelList> creationFunc)
|
||||||
|
{
|
||||||
|
AddStep("create list", () => Child = list = creationFunc().With(d =>
|
||||||
|
{
|
||||||
|
d.Anchor = Anchor.Centre;
|
||||||
|
d.Origin = Anchor.Centre;
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => list.IsLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertExpandedPanelCentred() => AddUntilStep("expanded panel centred", () =>
|
||||||
|
{
|
||||||
|
var expandedPanel = list.ChildrenOfType<ScorePanel>().Single(p => p.State == PanelState.Expanded);
|
||||||
|
return Precision.AlmostEquals(expandedPanel.ScreenSpaceDrawQuad.Centre.X, list.ScreenSpaceDrawQuad.Centre.X, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void assertFirstPanelCentred()
|
||||||
|
=> AddUntilStep("first panel centred", () => Precision.AlmostEquals(list.ChildrenOfType<ScorePanel>().First().ScreenSpaceDrawQuad.Centre.X, list.ScreenSpaceDrawQuad.Centre.X, 1));
|
||||||
|
|
||||||
|
private void assertScoreState(ScoreInfo score, bool expanded)
|
||||||
|
=> AddUntilStep($"score expanded = {expanded}", () => (list.ChildrenOfType<ScorePanel>().Single(p => p.Score == score).State == PanelState.Expanded) == expanded);
|
||||||
|
}
|
||||||
|
}
|
@ -55,12 +55,12 @@ namespace osu.Game.Database
|
|||||||
public Action<Notification> PostNotification { protected get; set; }
|
public Action<Notification> PostNotification { protected get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when a new <typeparamref name="TModel"/> becomes available in the database.
|
/// Fired when a new or updated <typeparamref name="TModel"/> becomes available in the database.
|
||||||
/// This is not guaranteed to run on the update thread.
|
/// This is not guaranteed to run on the update thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IBindable<WeakReference<TModel>> ItemAdded => itemAdded;
|
public IBindable<WeakReference<TModel>> ItemUpdated => itemUpdated;
|
||||||
|
|
||||||
private readonly Bindable<WeakReference<TModel>> itemAdded = new Bindable<WeakReference<TModel>>();
|
private readonly Bindable<WeakReference<TModel>> itemUpdated = new Bindable<WeakReference<TModel>>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when a <typeparamref name="TModel"/> is removed from the database.
|
/// Fired when a <typeparamref name="TModel"/> is removed from the database.
|
||||||
@ -90,7 +90,7 @@ namespace osu.Game.Database
|
|||||||
ContextFactory = contextFactory;
|
ContextFactory = contextFactory;
|
||||||
|
|
||||||
ModelStore = modelStore;
|
ModelStore = modelStore;
|
||||||
ModelStore.ItemAdded += item => handleEvent(() => itemAdded.Value = new WeakReference<TModel>(item));
|
ModelStore.ItemUpdated += item => handleEvent(() => itemUpdated.Value = new WeakReference<TModel>(item));
|
||||||
ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference<TModel>(item));
|
ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference<TModel>(item));
|
||||||
|
|
||||||
exportStorage = storage.GetStorageForDirectory("exports");
|
exportStorage = storage.GetStorageForDirectory("exports");
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Database
|
|||||||
public interface IModelManager<TModel>
|
public interface IModelManager<TModel>
|
||||||
where TModel : class
|
where TModel : class
|
||||||
{
|
{
|
||||||
IBindable<WeakReference<TModel>> ItemAdded { get; }
|
IBindable<WeakReference<TModel>> ItemUpdated { get; }
|
||||||
|
|
||||||
IBindable<WeakReference<TModel>> ItemRemoved { get; }
|
IBindable<WeakReference<TModel>> ItemRemoved { get; }
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,14 @@ namespace osu.Game.Database
|
|||||||
public abstract class MutableDatabaseBackedStore<T> : DatabaseBackedStore
|
public abstract class MutableDatabaseBackedStore<T> : DatabaseBackedStore
|
||||||
where T : class, IHasPrimaryKey, ISoftDelete
|
where T : class, IHasPrimaryKey, ISoftDelete
|
||||||
{
|
{
|
||||||
public event Action<T> ItemAdded;
|
/// <summary>
|
||||||
|
/// Fired when an item was added or updated.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<T> ItemUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when an item was removed.
|
||||||
|
/// </summary>
|
||||||
public event Action<T> ItemRemoved;
|
public event Action<T> ItemRemoved;
|
||||||
|
|
||||||
protected MutableDatabaseBackedStore(IDatabaseContextFactory contextFactory, Storage storage = null)
|
protected MutableDatabaseBackedStore(IDatabaseContextFactory contextFactory, Storage storage = null)
|
||||||
@ -41,7 +48,7 @@ namespace osu.Game.Database
|
|||||||
context.Attach(item);
|
context.Attach(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemAdded?.Invoke(item);
|
ItemUpdated?.Invoke(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -53,8 +60,7 @@ namespace osu.Game.Database
|
|||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
usage.Context.Update(item);
|
usage.Context.Update(item);
|
||||||
|
|
||||||
ItemRemoved?.Invoke(item);
|
ItemUpdated?.Invoke(item);
|
||||||
ItemAdded?.Invoke(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -91,7 +97,7 @@ namespace osu.Game.Database
|
|||||||
item.DeletePending = false;
|
item.DeletePending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemAdded?.Invoke(item);
|
ItemUpdated?.Invoke(item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,15 @@ namespace osu.Game.Online.API.Requests
|
|||||||
|
|
||||||
private string directionString => SortDirection == SortDirection.Descending ? @"desc" : @"asc";
|
private string directionString => SortDirection == SortDirection.Descending ? @"desc" : @"asc";
|
||||||
|
|
||||||
public SearchBeatmapSetsRequest(string query, RulesetInfo ruleset, Cursor cursor = null, SearchCategory searchCategory = SearchCategory.Any, SortCriteria sortCriteria = SortCriteria.Ranked, SortDirection sortDirection = SortDirection.Descending)
|
public SearchBeatmapSetsRequest(
|
||||||
|
string query,
|
||||||
|
RulesetInfo ruleset,
|
||||||
|
Cursor cursor = null,
|
||||||
|
SearchCategory searchCategory = SearchCategory.Any,
|
||||||
|
SortCriteria sortCriteria = SortCriteria.Ranked,
|
||||||
|
SortDirection sortDirection = SortDirection.Descending,
|
||||||
|
SearchGenre genre = SearchGenre.Any,
|
||||||
|
SearchLanguage language = SearchLanguage.Any)
|
||||||
{
|
{
|
||||||
this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query);
|
this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query);
|
||||||
this.ruleset = ruleset;
|
this.ruleset = ruleset;
|
||||||
@ -36,8 +44,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
SearchCategory = searchCategory;
|
SearchCategory = searchCategory;
|
||||||
SortCriteria = sortCriteria;
|
SortCriteria = sortCriteria;
|
||||||
SortDirection = sortDirection;
|
SortDirection = sortDirection;
|
||||||
Genre = SearchGenre.Any;
|
Genre = genre;
|
||||||
Language = SearchLanguage.Any;
|
Language = language;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Online
|
|||||||
Model.Value = model;
|
Model.Value = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBindable<WeakReference<TModel>> managerAdded;
|
private IBindable<WeakReference<TModel>> managedUpdated;
|
||||||
private IBindable<WeakReference<TModel>> managerRemoved;
|
private IBindable<WeakReference<TModel>> managerRemoved;
|
||||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadBegan;
|
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadBegan;
|
||||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadFailed;
|
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadFailed;
|
||||||
@ -56,8 +56,8 @@ namespace osu.Game.Online
|
|||||||
managerDownloadBegan.BindValueChanged(downloadBegan);
|
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||||
managerDownloadFailed = manager.DownloadFailed.GetBoundCopy();
|
managerDownloadFailed = manager.DownloadFailed.GetBoundCopy();
|
||||||
managerDownloadFailed.BindValueChanged(downloadFailed);
|
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||||
managerAdded = manager.ItemAdded.GetBoundCopy();
|
managedUpdated = manager.ItemUpdated.GetBoundCopy();
|
||||||
managerAdded.BindValueChanged(itemAdded);
|
managedUpdated.BindValueChanged(itemUpdated);
|
||||||
managerRemoved = manager.ItemRemoved.GetBoundCopy();
|
managerRemoved = manager.ItemRemoved.GetBoundCopy();
|
||||||
managerRemoved.BindValueChanged(itemRemoved);
|
managerRemoved.BindValueChanged(itemRemoved);
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ namespace osu.Game.Online
|
|||||||
|
|
||||||
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||||
|
|
||||||
private void itemAdded(ValueChangedEvent<WeakReference<TModel>> weakItem)
|
private void itemUpdated(ValueChangedEvent<WeakReference<TModel>> weakItem)
|
||||||
{
|
{
|
||||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
setDownloadStateFromManager(item, DownloadState.LocallyAvailable);
|
setDownloadStateFromManager(item, DownloadState.LocallyAvailable);
|
||||||
|
@ -192,7 +192,7 @@ namespace osu.Game
|
|||||||
ScoreManager.Delete(getBeatmapScores(item), true);
|
ScoreManager.Delete(getBeatmapScores(item), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
BeatmapManager.ItemAdded.BindValueChanged(i =>
|
BeatmapManager.ItemUpdated.BindValueChanged(i =>
|
||||||
{
|
{
|
||||||
if (i.NewValue.TryGetTarget(out var item))
|
if (i.NewValue.TryGetTarget(out var item))
|
||||||
ScoreManager.Undelete(getBeatmapScores(item), true);
|
ScoreManager.Undelete(getBeatmapScores(item), true);
|
||||||
@ -229,8 +229,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
FileStore.Cleanup();
|
FileStore.Cleanup();
|
||||||
|
|
||||||
if (API is APIAccess apiAcces)
|
if (API is APIAccess apiAccess)
|
||||||
AddInternal(apiAcces);
|
AddInternal(apiAccess);
|
||||||
AddInternal(RulesetConfigCache);
|
AddInternal(RulesetConfigCache);
|
||||||
|
|
||||||
GlobalActionContainer globalBinding;
|
GlobalActionContainer globalBinding;
|
||||||
|
@ -177,7 +177,9 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
lastResponse?.Cursor,
|
lastResponse?.Cursor,
|
||||||
searchControl.Category.Value,
|
searchControl.Category.Value,
|
||||||
sortControl.Current.Value,
|
sortControl.Current.Value,
|
||||||
sortControl.SortDirection.Value);
|
sortControl.SortDirection.Value,
|
||||||
|
searchControl.Genre.Value,
|
||||||
|
searchControl.Language.Value);
|
||||||
|
|
||||||
getSetsRequest.Success += response =>
|
getSetsRequest.Success += response =>
|
||||||
{
|
{
|
||||||
@ -186,6 +188,9 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
if (sets.Count == 0)
|
if (sets.Count == 0)
|
||||||
noMoreResults = true;
|
noMoreResults = true;
|
||||||
|
|
||||||
|
if (CurrentPage == 0)
|
||||||
|
searchControl.BeatmapSet = sets.FirstOrDefault();
|
||||||
|
|
||||||
lastResponse = response;
|
lastResponse = response;
|
||||||
getSetsRequest = null;
|
getSetsRequest = null;
|
||||||
|
|
||||||
|
@ -60,14 +60,14 @@ namespace osu.Game.Overlays
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OnScreenDisplay onScreenDisplay { get; set; }
|
private OnScreenDisplay onScreenDisplay { get; set; }
|
||||||
|
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerAdded;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
managerAdded = beatmaps.ItemAdded.GetBoundCopy();
|
managerUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||||
managerAdded.BindValueChanged(beatmapAdded);
|
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||||
managerRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
managerRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
||||||
managerRemoved.BindValueChanged(beatmapRemoved);
|
managerRemoved.BindValueChanged(beatmapRemoved);
|
||||||
|
|
||||||
@ -98,13 +98,13 @@ namespace osu.Game.Overlays
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPlaying => current?.Track.IsRunning ?? false;
|
public bool IsPlaying => current?.Track.IsRunning ?? false;
|
||||||
|
|
||||||
private void beatmapAdded(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||||
{
|
{
|
||||||
if (weakSet.NewValue.TryGetTarget(out var set))
|
if (weakSet.NewValue.TryGetTarget(out var set))
|
||||||
{
|
{
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
if (!beatmapSets.Contains(set))
|
beatmapSets.Remove(set);
|
||||||
beatmapSets.Add(set);
|
beatmapSets.Add(set);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skins { get; set; }
|
private SkinManager skins { get; set; }
|
||||||
|
|
||||||
private IBindable<WeakReference<SkinInfo>> managerAdded;
|
private IBindable<WeakReference<SkinInfo>> managerUpdated;
|
||||||
private IBindable<WeakReference<SkinInfo>> managerRemoved;
|
private IBindable<WeakReference<SkinInfo>> managerRemoved;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
managerAdded = skins.ItemAdded.GetBoundCopy();
|
managerUpdated = skins.ItemUpdated.GetBoundCopy();
|
||||||
managerAdded.BindValueChanged(itemAdded);
|
managerUpdated.BindValueChanged(itemUpdated);
|
||||||
|
|
||||||
managerRemoved = skins.ItemRemoved.GetBoundCopy();
|
managerRemoved = skins.ItemRemoved.GetBoundCopy();
|
||||||
managerRemoved.BindValueChanged(itemRemoved);
|
managerRemoved.BindValueChanged(itemRemoved);
|
||||||
@ -92,10 +92,10 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
dropdownBindable.BindValueChanged(skin => configBindable.Value = skin.NewValue.ID);
|
dropdownBindable.BindValueChanged(skin => configBindable.Value = skin.NewValue.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void itemAdded(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
|
private void itemUpdated(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
|
||||||
{
|
{
|
||||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
Schedule(() => skinDropdown.Items = skinDropdown.Items.Append(item).ToArray());
|
Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => !i.Equals(item)).Append(item).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void itemRemoved(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
|
private void itemRemoved(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
|
||||||
|
@ -48,6 +48,8 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
||||||
|
|
||||||
|
public override Playfield Playfield => drawableRulesetWrapper.Playfield;
|
||||||
|
|
||||||
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
||||||
|
|
||||||
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
@ -102,6 +104,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
Name = "Content",
|
Name = "Content",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
// layers below playfield
|
// layers below playfield
|
||||||
@ -260,11 +263,13 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
[Cached(typeof(IPositionSnapProvider))]
|
[Cached(typeof(IPositionSnapProvider))]
|
||||||
public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
||||||
{
|
{
|
||||||
internal HitObjectComposer()
|
protected HitObjectComposer()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract Playfield Playfield { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All the <see cref="DrawableHitObject"/>s.
|
/// All the <see cref="DrawableHitObject"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -15,7 +15,12 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly DrawableHitObject DrawableObject;
|
public readonly DrawableHitObject DrawableObject;
|
||||||
|
|
||||||
protected override bool ShouldBeAlive => (DrawableObject.IsAlive && DrawableObject.IsPresent) || State == SelectionState.Selected;
|
/// <summary>
|
||||||
|
/// Whether the blueprint should be shown even when the <see cref="DrawableObject"/> is not alive.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool AlwaysShowWhenSelected => false;
|
||||||
|
|
||||||
|
protected override bool ShouldBeAlive => (DrawableObject.IsAlive && DrawableObject.IsPresent) || (AlwaysShowWhenSelected && State == SelectionState.Selected);
|
||||||
|
|
||||||
protected OverlaySelectionBlueprint(DrawableHitObject drawableObject)
|
protected OverlaySelectionBlueprint(DrawableHitObject drawableObject)
|
||||||
: base(drawableObject.HitObject)
|
: base(drawableObject.HitObject)
|
||||||
|
@ -44,6 +44,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
||||||
|
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private IPositionSnapProvider snapProvider { get; set; }
|
private IPositionSnapProvider snapProvider { get; set; }
|
||||||
|
|
||||||
|
@ -32,14 +32,14 @@ namespace osu.Game.Screens.Multi.Match.Components
|
|||||||
Text = "Start";
|
Text = "Start";
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerAdded;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
managerAdded = beatmaps.ItemAdded.GetBoundCopy();
|
managerUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||||
managerAdded.BindValueChanged(beatmapAdded);
|
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||||
managerRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
managerRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
||||||
managerRemoved.BindValueChanged(beatmapRemoved);
|
managerRemoved.BindValueChanged(beatmapRemoved);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
|||||||
hasBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId) != null;
|
hasBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapAdded(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||||
{
|
{
|
||||||
if (weakSet.NewValue.TryGetTarget(out var set))
|
if (weakSet.NewValue.TryGetTarget(out var set))
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Screens.Multi.Match
|
|||||||
private LeaderboardChatDisplay leaderboardChatDisplay;
|
private LeaderboardChatDisplay leaderboardChatDisplay;
|
||||||
private MatchSettingsOverlay settingsOverlay;
|
private MatchSettingsOverlay settingsOverlay;
|
||||||
|
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerAdded;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||||
|
|
||||||
public MatchSubScreen(Room room)
|
public MatchSubScreen(Room room)
|
||||||
{
|
{
|
||||||
@ -183,8 +183,8 @@ namespace osu.Game.Screens.Multi.Match
|
|||||||
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
|
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
|
||||||
SelectedItem.Value = playlist.FirstOrDefault();
|
SelectedItem.Value = playlist.FirstOrDefault();
|
||||||
|
|
||||||
managerAdded = beatmapManager.ItemAdded.GetBoundCopy();
|
managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy();
|
||||||
managerAdded.BindValueChanged(beatmapAdded);
|
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnExiting(IScreen next)
|
public override bool OnExiting(IScreen next)
|
||||||
@ -217,7 +217,7 @@ namespace osu.Game.Screens.Multi.Match
|
|||||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapAdded(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||||
{
|
{
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
|
@ -479,7 +479,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value;
|
protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value;
|
||||||
|
|
||||||
protected virtual ResultsScreen CreateResults(ScoreInfo score) => new ResultsScreen(score);
|
protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score);
|
||||||
|
|
||||||
#region Fail Logic
|
#region Fail Logic
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Screens.Play
|
|||||||
this.Push(CreateResults(DrawableRuleset.ReplayScore.ScoreInfo));
|
this.Push(CreateResults(DrawableRuleset.ReplayScore.ScoreInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ResultsScreen CreateResults(ScoreInfo score) => new ResultsScreen(score, false);
|
protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, false);
|
||||||
|
|
||||||
protected override ScoreInfo CreateScore() => score.ScoreInfo;
|
protected override ScoreInfo CreateScore() => score.ScoreInfo;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,222 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Leaderboards;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Game.Users.Drawables;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Ranking.Contracted
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The content that appears in the middle of a contracted <see cref="ScorePanel"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class ContractedPanelMiddleContent : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly ScoreInfo score;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ContractedPanelMiddleContent"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="score">The <see cref="ScoreInfo"/> to display.</param>
|
||||||
|
public ContractedPanelMiddleContent(ScoreInfo score)
|
||||||
|
{
|
||||||
|
this.score = score;
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
CornerExponent = 2.5f,
|
||||||
|
CornerRadius = 20,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Colour = Color4.Black.Opacity(0.25f),
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Radius = 1,
|
||||||
|
Offset = new Vector2(0, 4)
|
||||||
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4Extensions.FromHex("444")
|
||||||
|
},
|
||||||
|
new UserCoverBackground
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
User = score.User,
|
||||||
|
Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0.5f), Color4Extensions.FromHex("#444").Opacity(0))
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(10),
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new UpdateableAvatar(score.User)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Size = new Vector2(110),
|
||||||
|
Masking = true,
|
||||||
|
CornerExponent = 2.5f,
|
||||||
|
CornerRadius = 20,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Colour = Color4.Black.Opacity(0.25f),
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Radius = 8,
|
||||||
|
Offset = new Vector2(0, 4),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Text = score.UserString,
|
||||||
|
Font = OsuFont.GetFont(size: 16, weight: FontWeight.SemiBold)
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 5),
|
||||||
|
ChildrenEnumerable = score.SortedStatistics.Select(s => createStatistic(s.Key.GetDescription(), s.Value.ToString()))
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Margin = new MarginPadding { Top = 10 },
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 5),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
createStatistic("Max Combo", $"x{score.MaxCombo}"),
|
||||||
|
createStatistic("Accuracy", $"{score.Accuracy.FormatAccuracy()}"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ModDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
ExpansionMode = ExpansionMode.AlwaysExpanded,
|
||||||
|
DisplayUnrankedText = false,
|
||||||
|
Current = { Value = score.Mods },
|
||||||
|
Scale = new Vector2(0.5f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Vertical = 5 },
|
||||||
|
Child = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Text = score.TotalScore.ToString("N0"),
|
||||||
|
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, fixedWidth: true),
|
||||||
|
Spacing = new Vector2(-1, 0)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Top = 2 },
|
||||||
|
Child = new DrawableRank(score.Rank)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 45),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable createStatistic(string key, string value) => new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Text = key,
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Text = value,
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
Colour = Color4Extensions.FromHex("#FFDD55")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -13,6 +14,8 @@ namespace osu.Game.Screens.Ranking
|
|||||||
{
|
{
|
||||||
public class ReplayDownloadButton : DownloadTrackingComposite<ScoreInfo, ScoreManager>
|
public class ReplayDownloadButton : DownloadTrackingComposite<ScoreInfo, ScoreManager>
|
||||||
{
|
{
|
||||||
|
public Bindable<ScoreInfo> Score => Model;
|
||||||
|
|
||||||
private DownloadButton button;
|
private DownloadButton button;
|
||||||
private ShakeContainer shakeContainer;
|
private ShakeContainer shakeContainer;
|
||||||
|
|
||||||
@ -23,7 +26,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
if (State.Value == DownloadState.LocallyAvailable)
|
if (State.Value == DownloadState.LocallyAvailable)
|
||||||
return ReplayAvailability.Local;
|
return ReplayAvailability.Local;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Model.Value.Hash))
|
if (!string.IsNullOrEmpty(Model.Value?.Hash))
|
||||||
return ReplayAvailability.Online;
|
return ReplayAvailability.Online;
|
||||||
|
|
||||||
return ReplayAvailability.NotAvailable;
|
return ReplayAvailability.NotAvailable;
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -10,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -17,7 +20,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Ranking
|
namespace osu.Game.Screens.Ranking
|
||||||
{
|
{
|
||||||
public class ResultsScreen : OsuScreen
|
public abstract class ResultsScreen : OsuScreen
|
||||||
{
|
{
|
||||||
protected const float BACKGROUND_BLUR = 20;
|
protected const float BACKGROUND_BLUR = 20;
|
||||||
|
|
||||||
@ -28,19 +31,26 @@ namespace osu.Game.Screens.Ranking
|
|||||||
|
|
||||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
|
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
|
||||||
|
|
||||||
|
public readonly Bindable<ScoreInfo> SelectedScore = new Bindable<ScoreInfo>();
|
||||||
|
|
||||||
|
public readonly ScoreInfo Score;
|
||||||
|
private readonly bool allowRetry;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private Player player { get; set; }
|
private Player player { get; set; }
|
||||||
|
|
||||||
public readonly ScoreInfo Score;
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
private readonly bool allowRetry;
|
|
||||||
|
|
||||||
private Drawable bottomPanel;
|
private Drawable bottomPanel;
|
||||||
|
private ScorePanelList panels;
|
||||||
|
|
||||||
public ResultsScreen(ScoreInfo score, bool allowRetry = true)
|
protected ResultsScreen(ScoreInfo score, bool allowRetry = true)
|
||||||
{
|
{
|
||||||
Score = score;
|
Score = score;
|
||||||
this.allowRetry = allowRetry;
|
this.allowRetry = allowRetry;
|
||||||
|
|
||||||
|
SelectedScore.Value = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -48,17 +58,24 @@ namespace osu.Game.Screens.Ranking
|
|||||||
{
|
{
|
||||||
FillFlowContainer buttons;
|
FillFlowContainer buttons;
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChild = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new ResultsScrollContainer
|
new ResultsScrollContainer
|
||||||
{
|
{
|
||||||
Child = new ScorePanel(Score)
|
Child = panels = new ScorePanelList
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
SelectedScore = { BindTarget = SelectedScore }
|
||||||
State = PanelState.Expanded
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
new[]
|
||||||
|
{
|
||||||
bottomPanel = new Container
|
bottomPanel = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
@ -82,13 +99,27 @@ namespace osu.Game.Screens.Ranking
|
|||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new ReplayDownloadButton(Score) { Width = 300 },
|
new ReplayDownloadButton(null)
|
||||||
|
{
|
||||||
|
Score = { BindTarget = SelectedScore },
|
||||||
|
Width = 300
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.AutoSize)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Score != null)
|
||||||
|
panels.AddScore(Score);
|
||||||
|
|
||||||
if (player != null && allowRetry)
|
if (player != null && allowRetry)
|
||||||
{
|
{
|
||||||
buttons.Add(new RetryButton { Width = 300 });
|
buttons.Add(new RetryButton { Width = 300 });
|
||||||
@ -105,6 +136,27 @@ namespace osu.Game.Screens.Ranking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var req = FetchScores(scores => Schedule(() =>
|
||||||
|
{
|
||||||
|
foreach (var s in scores)
|
||||||
|
panels.AddScore(s);
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (req != null)
|
||||||
|
api.Queue(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a fetch/refresh of scores to be displayed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="scoresCallback">A callback which should be called when fetching is completed. Scheduling is not required.</param>
|
||||||
|
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
|
||||||
|
protected virtual APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback) => null;
|
||||||
|
|
||||||
public override void OnEntering(IScreen last)
|
public override void OnEntering(IScreen last)
|
||||||
{
|
{
|
||||||
base.OnEntering(last);
|
base.OnEntering(last);
|
||||||
@ -142,7 +194,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
content.Height = Math.Max(768, DrawHeight);
|
content.Height = Math.Max(768 - TwoLayerButton.SIZE_EXTENDED.Y, DrawHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Ranking.Contracted;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
using osu.Game.Screens.Ranking.Expanded;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -21,12 +23,12 @@ namespace osu.Game.Screens.Ranking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the panel when contracted.
|
/// Width of the panel when contracted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const float contracted_width = 160;
|
public const float CONTRACTED_WIDTH = 130;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Height of the panel when contracted.
|
/// Height of the panel when contracted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const float contracted_height = 320;
|
private const float contracted_height = 355;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the panel when expanded.
|
/// Width of the panel when expanded.
|
||||||
@ -46,7 +48,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Height of the top layer when the panel is contracted.
|
/// Height of the top layer when the panel is contracted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const float contracted_top_layer_height = 40;
|
private const float contracted_top_layer_height = 30;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Duration for the panel to resize into its expanded/contracted size.
|
/// Duration for the panel to resize into its expanded/contracted size.
|
||||||
@ -71,11 +73,12 @@ namespace osu.Game.Screens.Ranking
|
|||||||
private static readonly ColourInfo expanded_top_layer_colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#444"), Color4Extensions.FromHex("#333"));
|
private static readonly ColourInfo expanded_top_layer_colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#444"), Color4Extensions.FromHex("#333"));
|
||||||
private static readonly ColourInfo expanded_middle_layer_colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#555"), Color4Extensions.FromHex("#333"));
|
private static readonly ColourInfo expanded_middle_layer_colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#555"), Color4Extensions.FromHex("#333"));
|
||||||
private static readonly Color4 contracted_top_layer_colour = Color4Extensions.FromHex("#353535");
|
private static readonly Color4 contracted_top_layer_colour = Color4Extensions.FromHex("#353535");
|
||||||
private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#444");
|
private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#353535");
|
||||||
|
|
||||||
public event Action<PanelState> StateChanged;
|
public event Action<PanelState> StateChanged;
|
||||||
|
public readonly ScoreInfo Score;
|
||||||
|
|
||||||
private readonly ScoreInfo score;
|
private Container content;
|
||||||
|
|
||||||
private Container topLayerContainer;
|
private Container topLayerContainer;
|
||||||
private Drawable topLayerBackground;
|
private Drawable topLayerBackground;
|
||||||
@ -89,18 +92,24 @@ namespace osu.Game.Screens.Ranking
|
|||||||
|
|
||||||
public ScorePanel(ScoreInfo score)
|
public ScorePanel(ScoreInfo score)
|
||||||
{
|
{
|
||||||
this.score = score;
|
Score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChild = content = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(40),
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
topLayerContainer = new Container
|
topLayerContainer = new Container
|
||||||
{
|
{
|
||||||
Name = "Top layer",
|
Name = "Top layer",
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Alpha = 0,
|
||||||
Height = 120,
|
Height = 120,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -132,6 +141,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
middleLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
|
middleLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,34 +184,40 @@ namespace osu.Game.Screens.Ranking
|
|||||||
|
|
||||||
private void updateState()
|
private void updateState()
|
||||||
{
|
{
|
||||||
topLayerContainer.MoveToY(0, resize_duration, Easing.OutQuint);
|
|
||||||
middleLayerContainer.MoveToY(0, resize_duration, Easing.OutQuint);
|
|
||||||
|
|
||||||
topLayerContent?.FadeOut(content_fade_duration).Expire();
|
topLayerContent?.FadeOut(content_fade_duration).Expire();
|
||||||
middleLayerContent?.FadeOut(content_fade_duration).Expire();
|
middleLayerContent?.FadeOut(content_fade_duration).Expire();
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case PanelState.Expanded:
|
case PanelState.Expanded:
|
||||||
this.ResizeTo(new Vector2(EXPANDED_WIDTH, expanded_height), resize_duration, Easing.OutQuint);
|
Size = new Vector2(EXPANDED_WIDTH, expanded_height);
|
||||||
|
|
||||||
topLayerBackground.FadeColour(expanded_top_layer_colour, resize_duration, Easing.OutQuint);
|
topLayerBackground.FadeColour(expanded_top_layer_colour, resize_duration, Easing.OutQuint);
|
||||||
middleLayerBackground.FadeColour(expanded_middle_layer_colour, resize_duration, Easing.OutQuint);
|
middleLayerBackground.FadeColour(expanded_middle_layer_colour, resize_duration, Easing.OutQuint);
|
||||||
|
|
||||||
topLayerContentContainer.Add(middleLayerContent = new ExpandedPanelTopContent(score.User).With(d => d.Alpha = 0));
|
topLayerContentContainer.Add(middleLayerContent = new ExpandedPanelTopContent(Score.User).With(d => d.Alpha = 0));
|
||||||
middleLayerContentContainer.Add(topLayerContent = new ExpandedPanelMiddleContent(score).With(d => d.Alpha = 0));
|
middleLayerContentContainer.Add(topLayerContent = new ExpandedPanelMiddleContent(Score).With(d => d.Alpha = 0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PanelState.Contracted:
|
case PanelState.Contracted:
|
||||||
this.ResizeTo(new Vector2(contracted_width, contracted_height), resize_duration, Easing.OutQuint);
|
Size = new Vector2(CONTRACTED_WIDTH, contracted_height);
|
||||||
|
|
||||||
topLayerBackground.FadeColour(contracted_top_layer_colour, resize_duration, Easing.OutQuint);
|
topLayerBackground.FadeColour(contracted_top_layer_colour, resize_duration, Easing.OutQuint);
|
||||||
middleLayerBackground.FadeColour(contracted_middle_layer_colour, resize_duration, Easing.OutQuint);
|
middleLayerBackground.FadeColour(contracted_middle_layer_colour, resize_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
middleLayerContentContainer.Add(topLayerContent = new ContractedPanelMiddleContent(Score).With(d => d.Alpha = 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (BeginDelayedSequence(resize_duration + top_layer_expand_delay, true))
|
content.ResizeTo(Size, resize_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
bool topLayerExpanded = topLayerContainer.Y < 0;
|
||||||
|
|
||||||
|
// If the top layer was already expanded, then we don't need to wait for the resize and can instead transform immediately. This looks better when changing the panel state.
|
||||||
|
using (BeginDelayedSequence(topLayerExpanded ? 0 : resize_duration + top_layer_expand_delay, true))
|
||||||
{
|
{
|
||||||
|
topLayerContainer.FadeIn();
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case PanelState.Expanded:
|
case PanelState.Expanded:
|
||||||
@ -219,5 +235,13 @@ namespace osu.Game.Screens.Ranking
|
|||||||
middleLayerContent?.FadeIn(content_fade_duration);
|
middleLayerContent?.FadeIn(content_fade_duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnClick(ClickEvent e)
|
||||||
|
{
|
||||||
|
if (State == PanelState.Contracted)
|
||||||
|
State = PanelState.Expanded;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
185
osu.Game/Screens/Ranking/ScorePanelList.cs
Normal file
185
osu.Game/Screens/Ranking/ScorePanelList.cs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
// 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 osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Ranking
|
||||||
|
{
|
||||||
|
public class ScorePanelList : CompositeDrawable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Normal spacing between all panels.
|
||||||
|
/// </summary>
|
||||||
|
private const float panel_spacing = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spacing around both sides of the expanded panel. This is added on top of <see cref="panel_spacing"/>.
|
||||||
|
/// </summary>
|
||||||
|
private const float expanded_panel_spacing = 15;
|
||||||
|
|
||||||
|
public readonly Bindable<ScoreInfo> SelectedScore = new Bindable<ScoreInfo>();
|
||||||
|
|
||||||
|
private readonly Flow flow;
|
||||||
|
private readonly Scroll scroll;
|
||||||
|
private ScorePanel expandedPanel;
|
||||||
|
|
||||||
|
public ScorePanelList()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChild = scroll = new Scroll
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = flow = new Flow
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(panel_spacing, 0),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
SelectedScore.BindValueChanged(selectedScoreChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a <see cref="ScoreInfo"/> to this list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="score">The <see cref="ScoreInfo"/> to add.</param>
|
||||||
|
public void AddScore(ScoreInfo score)
|
||||||
|
{
|
||||||
|
flow.Add(new ScorePanel(score)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}.With(p =>
|
||||||
|
{
|
||||||
|
p.StateChanged += s =>
|
||||||
|
{
|
||||||
|
if (s == PanelState.Expanded)
|
||||||
|
SelectedScore.Value = p.Score;
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (SelectedScore.Value == score)
|
||||||
|
selectedScoreChanged(new ValueChangedEvent<ScoreInfo>(SelectedScore.Value, SelectedScore.Value));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done.
|
||||||
|
// But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel.
|
||||||
|
if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score))
|
||||||
|
{
|
||||||
|
// A somewhat hacky property is used here because we need to:
|
||||||
|
// 1) Scroll after the scroll container's visible range is updated.
|
||||||
|
// 2) Scroll before the scroll container's scroll position is updated.
|
||||||
|
// Without this, we would have a 1-frame positioning error which looks very jarring.
|
||||||
|
scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Brings a <see cref="ScoreInfo"/> to the centre of the screen and expands it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="score">The <see cref="ScoreInfo"/> to present.</param>
|
||||||
|
private void selectedScoreChanged(ValueChangedEvent<ScoreInfo> score)
|
||||||
|
{
|
||||||
|
// Contract the old panel.
|
||||||
|
foreach (var p in flow.Where(p => p.Score == score.OldValue))
|
||||||
|
{
|
||||||
|
p.State = PanelState.Contracted;
|
||||||
|
p.Margin = new MarginPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the panel corresponding to the new score.
|
||||||
|
expandedPanel = flow.SingleOrDefault(p => p.Score == score.NewValue);
|
||||||
|
|
||||||
|
if (expandedPanel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Expand the new panel.
|
||||||
|
expandedPanel.State = PanelState.Expanded;
|
||||||
|
expandedPanel.Margin = new MarginPadding { Horizontal = expanded_panel_spacing };
|
||||||
|
|
||||||
|
// Scroll to the new panel. This is done manually since we need:
|
||||||
|
// 1) To scroll after the scroll container's visible range is updated.
|
||||||
|
// 2) To account for the centre anchor/origins of panels.
|
||||||
|
// In the end, it's easier to compute the scroll position manually.
|
||||||
|
float scrollOffset = flow.GetPanelIndex(expandedPanel.Score) * (ScorePanel.CONTRACTED_WIDTH + panel_spacing);
|
||||||
|
scroll.ScrollTo(scrollOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
float offset = DrawWidth / 2f;
|
||||||
|
|
||||||
|
// Add padding to both sides such that the centre of an expanded panel on either side is in the middle of the screen.
|
||||||
|
|
||||||
|
if (SelectedScore.Value != null)
|
||||||
|
{
|
||||||
|
// The expanded panel has extra padding applied to it, so it needs to be included into the offset.
|
||||||
|
offset -= ScorePanel.EXPANDED_WIDTH / 2f + expanded_panel_spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
offset -= ScorePanel.CONTRACTED_WIDTH / 2f;
|
||||||
|
|
||||||
|
flow.Padding = new MarginPadding { Horizontal = offset };
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Flow : FillFlowContainer<ScorePanel>
|
||||||
|
{
|
||||||
|
public override IEnumerable<Drawable> FlowingChildren => applySorting(AliveInternalChildren);
|
||||||
|
|
||||||
|
public int GetPanelIndex(ScoreInfo score) => applySorting(Children).TakeWhile(s => s.Score != score).Count();
|
||||||
|
|
||||||
|
private IEnumerable<ScorePanel> applySorting(IEnumerable<Drawable> drawables) => drawables.OfType<ScorePanel>()
|
||||||
|
.OrderByDescending(s => s.Score.TotalScore)
|
||||||
|
.ThenBy(s => s.Score.OnlineScoreID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Scroll : OsuScrollContainer
|
||||||
|
{
|
||||||
|
public new float Target => base.Target;
|
||||||
|
|
||||||
|
public Scroll()
|
||||||
|
: base(Direction.Horizontal)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target that will be scrolled to instantaneously next frame.
|
||||||
|
/// </summary>
|
||||||
|
public float? InstantScrollTarget;
|
||||||
|
|
||||||
|
protected override void UpdateAfterChildren()
|
||||||
|
{
|
||||||
|
if (InstantScrollTarget != null)
|
||||||
|
{
|
||||||
|
ScrollTo(InstantScrollTarget.Value, false);
|
||||||
|
InstantScrollTarget = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.UpdateAfterChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HandlePositionalInput => false;
|
||||||
|
|
||||||
|
public override bool HandleNonPositionalInput => false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
osu.Game/Screens/Ranking/SoloResultsScreen.cs
Normal file
32
osu.Game/Screens/Ranking/SoloResultsScreen.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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Ranking
|
||||||
|
{
|
||||||
|
public class SoloResultsScreen : ResultsScreen
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
|
public SoloResultsScreen(ScoreInfo score, bool allowRetry = true)
|
||||||
|
: base(score, allowRetry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback)
|
||||||
|
{
|
||||||
|
var req = new GetScoresRequest(Score.Beatmap, Score.Ruleset);
|
||||||
|
req.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => s.OnlineScoreID != Score.OnlineScoreID).Select(s => s.CreateScoreInfo(rulesets)));
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -131,7 +131,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private CarouselRoot root;
|
private CarouselRoot root;
|
||||||
|
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> itemAdded;
|
private IBindable<WeakReference<BeatmapSetInfo>> itemUpdated;
|
||||||
private IBindable<WeakReference<BeatmapSetInfo>> itemRemoved;
|
private IBindable<WeakReference<BeatmapSetInfo>> itemRemoved;
|
||||||
private IBindable<WeakReference<BeatmapInfo>> itemHidden;
|
private IBindable<WeakReference<BeatmapInfo>> itemHidden;
|
||||||
private IBindable<WeakReference<BeatmapInfo>> itemRestored;
|
private IBindable<WeakReference<BeatmapInfo>> itemRestored;
|
||||||
@ -166,8 +166,8 @@ namespace osu.Game.Screens.Select
|
|||||||
RightClickScrollingEnabled.ValueChanged += enabled => scroll.RightMouseScrollbar = enabled.NewValue;
|
RightClickScrollingEnabled.ValueChanged += enabled => scroll.RightMouseScrollbar = enabled.NewValue;
|
||||||
RightClickScrollingEnabled.TriggerChange();
|
RightClickScrollingEnabled.TriggerChange();
|
||||||
|
|
||||||
itemAdded = beatmaps.ItemAdded.GetBoundCopy();
|
itemUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||||
itemAdded.BindValueChanged(beatmapAdded);
|
itemUpdated.BindValueChanged(beatmapUpdated);
|
||||||
itemRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
itemRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
||||||
itemRemoved.BindValueChanged(beatmapRemoved);
|
itemRemoved.BindValueChanged(beatmapRemoved);
|
||||||
itemHidden = beatmaps.BeatmapHidden.GetBoundCopy();
|
itemHidden = beatmaps.BeatmapHidden.GetBoundCopy();
|
||||||
@ -582,7 +582,7 @@ namespace osu.Game.Screens.Select
|
|||||||
RemoveBeatmapSet(item);
|
RemoveBeatmapSet(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapAdded(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||||
{
|
{
|
||||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
UpdateBeatmapSet(item);
|
UpdateBeatmapSet(item);
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
private IBindable<WeakReference<ScoreInfo>> itemAdded;
|
private IBindable<WeakReference<ScoreInfo>> itemUpdated;
|
||||||
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
|
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
|
||||||
|
|
||||||
public TopLocalRank(BeatmapInfo beatmap)
|
public TopLocalRank(BeatmapInfo beatmap)
|
||||||
@ -40,8 +40,8 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
itemAdded = scores.ItemAdded.GetBoundCopy();
|
itemUpdated = scores.ItemUpdated.GetBoundCopy();
|
||||||
itemAdded.BindValueChanged(scoreChanged);
|
itemUpdated.BindValueChanged(scoreChanged);
|
||||||
|
|
||||||
itemRemoved = scores.ItemRemoved.GetBoundCopy();
|
itemRemoved = scores.ItemRemoved.GetBoundCopy();
|
||||||
itemRemoved.BindValueChanged(scoreChanged);
|
itemRemoved.BindValueChanged(scoreChanged);
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void PresentScore(ScoreInfo score) =>
|
protected void PresentScore(ScoreInfo score) =>
|
||||||
FinaliseSelection(score.Beatmap, score.Ruleset, () => this.Push(new ResultsScreen(score)));
|
FinaliseSelection(score.Beatmap, score.Ruleset, () => this.Push(new SoloResultsScreen(score)));
|
||||||
|
|
||||||
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
|
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
|
||||||
|
|
||||||
|
52
osu.Game/Tests/TestScoreInfo.cs
Normal file
52
osu.Game/Tests/TestScoreInfo.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests
|
||||||
|
{
|
||||||
|
public class TestScoreInfo : ScoreInfo
|
||||||
|
{
|
||||||
|
public TestScoreInfo(RulesetInfo ruleset)
|
||||||
|
{
|
||||||
|
User = new User
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Username = "peppy",
|
||||||
|
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||||
|
};
|
||||||
|
|
||||||
|
Beatmap = new TestBeatmap(ruleset).BeatmapInfo;
|
||||||
|
Ruleset = ruleset;
|
||||||
|
RulesetID = ruleset.ID ?? 0;
|
||||||
|
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() };
|
||||||
|
|
||||||
|
TotalScore = 2845370;
|
||||||
|
Accuracy = 0.95;
|
||||||
|
MaxCombo = 999;
|
||||||
|
Rank = ScoreRank.S;
|
||||||
|
Date = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
Statistics[HitResult.Miss] = 1;
|
||||||
|
Statistics[HitResult.Meh] = 50;
|
||||||
|
Statistics[HitResult.Good] = 100;
|
||||||
|
Statistics[HitResult.Great] = 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestModHardRock : ModHardRock
|
||||||
|
{
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestModDoubleTime : ModDoubleTime
|
||||||
|
{
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.525.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.528.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||||
<PackageReference Include="Sentry" Version="2.1.1" />
|
<PackageReference Include="Sentry" Version="2.1.1" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.525.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.528.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.525.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.528.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user