mirror of
https://github.com/ppy/osu
synced 2024-12-28 18:02:53 +00:00
Merge branch 'master' into i-has-curve-with-repeats
This commit is contained in:
commit
0ef971be28
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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>
|
||||
</Project>
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -19,8 +18,7 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
||||
public abstract class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene, IManiaHitObjectComposer
|
||||
public abstract class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene
|
||||
{
|
||||
private readonly Column column;
|
||||
|
||||
|
@ -4,15 +4,13 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Mania.Edit;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
||||
public abstract class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene, IManiaHitObjectComposer
|
||||
public abstract class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene
|
||||
{
|
||||
[Cached(Type = typeof(IAdjustableClock))]
|
||||
private readonly IAdjustableClock clock = new StopwatchClock();
|
||||
|
@ -2,23 +2,27 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Edit;
|
||||
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.Screens.Edit;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[Cached(typeof(IManiaHitObjectComposer))]
|
||||
public class TestSceneManiaBeatSnapGrid : EditorClockTestScene, IManiaHitObjectComposer
|
||||
public class TestSceneManiaBeatSnapGrid : EditorClockTestScene
|
||||
{
|
||||
[Cached(typeof(IScrollingInfo))]
|
||||
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
|
||||
@ -50,7 +54,10 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
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 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 tailPiece;
|
||||
|
||||
[Resolved]
|
||||
private IManiaHitObjectComposer composer { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IScrollingInfo scrollingInfo { get; set; }
|
||||
|
||||
|
@ -18,9 +18,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
[Resolved]
|
||||
private IScrollingInfo scrollingInfo { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IManiaHitObjectComposer composer { get; set; }
|
||||
|
||||
protected ManiaSelectionBlueprint(DrawableHitObject 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.Game.Beatmaps;
|
||||
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.Drawables;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
@ -63,9 +65,9 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
private (double start, double end)? selectionTimeRange;
|
||||
|
||||
[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)
|
||||
{
|
||||
|
@ -20,8 +20,7 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
||||
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>, IManiaHitObjectComposer
|
||||
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>
|
||||
{
|
||||
private DrawableManiaEditRuleset drawableRuleset;
|
||||
private ManiaBeatSnapGrid beatSnapGrid;
|
||||
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer 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;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
private IScrollingInfo scrollingInfo { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IManiaHitObjectComposer composer { get; set; }
|
||||
private HitObjectComposer composer { get; set; }
|
||||
|
||||
public override bool HandleMovement(MoveSelectionEvent moveEvent)
|
||||
{
|
||||
@ -31,7 +32,9 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -50,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
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>())
|
||||
obj.Column += columnDelta;
|
||||
|
@ -12,6 +12,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
||||
{
|
||||
protected new T HitObject => (T)DrawableObject.HitObject;
|
||||
|
||||
protected override bool AlwaysShowWhenSelected => true;
|
||||
|
||||
protected OsuSelectionBlueprint(DrawableHitObject drawableObject)
|
||||
: base(drawableObject)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using osu.Game.Rulesets.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);
|
||||
|
||||
|
@ -156,7 +156,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
// 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));
|
||||
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
@ -166,7 +166,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
imported.Hash += "-changed";
|
||||
manager.Update(imported);
|
||||
|
||||
Assert.AreEqual(0, itemAddRemoveFireCount -= 2);
|
||||
Assert.AreEqual(0, itemAddRemoveFireCount -= 1);
|
||||
|
||||
checkBeatmapSetCount(osu, 1);
|
||||
checkBeatmapCount(osu, 12);
|
||||
|
@ -28,6 +28,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep(@"locally available state", () => downloadButton.SetDownloadState(DownloadState.LocallyAvailable));
|
||||
AddStep(@"not downloaded state", () => downloadButton.SetDownloadState(DownloadState.NotDownloaded));
|
||||
createButton(false);
|
||||
createButtonNoScore();
|
||||
}
|
||||
|
||||
private void createButton(bool withReplay)
|
||||
@ -40,6 +41,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
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)
|
||||
|
@ -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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -14,10 +13,7 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
@ -37,7 +33,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
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"));
|
||||
}
|
||||
@ -45,7 +41,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
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", () =>
|
||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text, "mapped", "by")));
|
||||
@ -66,29 +62,6 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
return new TestWorkingBeatmap(beatmap);
|
||||
}
|
||||
|
||||
private ScoreInfo createTestScore() => new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
},
|
||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||
TotalScore = 999999,
|
||||
Accuracy = 0.95,
|
||||
MaxCombo = 999,
|
||||
Rank = ScoreRank.S,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics =
|
||||
{
|
||||
{ HitResult.Miss, 1 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Good, 100 },
|
||||
{ HitResult.Great, 300 },
|
||||
}
|
||||
};
|
||||
|
||||
private bool containsAny(string text, params string[] stringsToMatch) => stringsToMatch.Any(text.Contains);
|
||||
|
||||
private class ExpandedPanelMiddleContentContainer : Container
|
||||
|
@ -5,8 +5,8 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -11,13 +9,10 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
@ -41,26 +36,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
||||
}
|
||||
|
||||
private TestSoloResults createResultsScreen() => new TestSoloResults(new ScoreInfo
|
||||
{
|
||||
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",
|
||||
}
|
||||
});
|
||||
private TestSoloResults createResultsScreen() => new TestSoloResults(new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||
|
||||
[Test]
|
||||
public void ResultsWithoutPlayer()
|
||||
|
@ -1,28 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneScorePanel : OsuTestScene
|
||||
{
|
||||
private ScorePanel panel;
|
||||
|
||||
[Test]
|
||||
public void TestDRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.5;
|
||||
score.Rank = ScoreRank.D;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.5, Rank = ScoreRank.D };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -30,9 +25,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestCRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.75;
|
||||
score.Rank = ScoreRank.C;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.75, Rank = ScoreRank.C };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -40,9 +33,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestBRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.85;
|
||||
score.Rank = ScoreRank.B;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.85, Rank = ScoreRank.B };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -50,9 +41,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestARank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -60,9 +49,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.975;
|
||||
score.Rank = ScoreRank.S;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.975, Rank = ScoreRank.S };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -70,9 +57,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAlmostSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.9999;
|
||||
score.Rank = ScoreRank.S;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.9999, Rank = ScoreRank.S };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -80,9 +65,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 1;
|
||||
score.Rank = ScoreRank.X;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 1, Rank = ScoreRank.X };
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -90,44 +73,42 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAllHitResults()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Statistics[HitResult.Perfect] = 350;
|
||||
score.Statistics[HitResult.Ok] = 200;
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Statistics = { [HitResult.Perfect] = 350, [HitResult.Ok] = 200 } };
|
||||
|
||||
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,
|
||||
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; }
|
||||
|
||||
/// <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.
|
||||
/// </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>
|
||||
/// Fired when a <typeparamref name="TModel"/> is removed from the database.
|
||||
@ -90,7 +90,7 @@ namespace osu.Game.Database
|
||||
ContextFactory = contextFactory;
|
||||
|
||||
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));
|
||||
|
||||
exportStorage = storage.GetStorageForDirectory("exports");
|
||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Database
|
||||
public interface IModelManager<TModel>
|
||||
where TModel : class
|
||||
{
|
||||
IBindable<WeakReference<TModel>> ItemAdded { get; }
|
||||
IBindable<WeakReference<TModel>> ItemUpdated { get; }
|
||||
|
||||
IBindable<WeakReference<TModel>> ItemRemoved { get; }
|
||||
}
|
||||
|
@ -16,7 +16,14 @@ namespace osu.Game.Database
|
||||
public abstract class MutableDatabaseBackedStore<T> : DatabaseBackedStore
|
||||
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;
|
||||
|
||||
protected MutableDatabaseBackedStore(IDatabaseContextFactory contextFactory, Storage storage = null)
|
||||
@ -41,7 +48,7 @@ namespace osu.Game.Database
|
||||
context.Attach(item);
|
||||
}
|
||||
|
||||
ItemAdded?.Invoke(item);
|
||||
ItemUpdated?.Invoke(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -53,8 +60,7 @@ namespace osu.Game.Database
|
||||
using (var usage = ContextFactory.GetForWrite())
|
||||
usage.Context.Update(item);
|
||||
|
||||
ItemRemoved?.Invoke(item);
|
||||
ItemAdded?.Invoke(item);
|
||||
ItemUpdated?.Invoke(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -91,7 +97,7 @@ namespace osu.Game.Database
|
||||
item.DeletePending = false;
|
||||
}
|
||||
|
||||
ItemAdded?.Invoke(item);
|
||||
ItemUpdated?.Invoke(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,15 @@ namespace osu.Game.Online.API.Requests
|
||||
|
||||
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.ruleset = ruleset;
|
||||
@ -36,8 +44,8 @@ namespace osu.Game.Online.API.Requests
|
||||
SearchCategory = searchCategory;
|
||||
SortCriteria = sortCriteria;
|
||||
SortDirection = sortDirection;
|
||||
Genre = SearchGenre.Any;
|
||||
Language = SearchLanguage.Any;
|
||||
Genre = genre;
|
||||
Language = language;
|
||||
}
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Online
|
||||
Model.Value = model;
|
||||
}
|
||||
|
||||
private IBindable<WeakReference<TModel>> managerAdded;
|
||||
private IBindable<WeakReference<TModel>> managedUpdated;
|
||||
private IBindable<WeakReference<TModel>> managerRemoved;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadFailed;
|
||||
@ -56,8 +56,8 @@ namespace osu.Game.Online
|
||||
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||
managerDownloadFailed = manager.DownloadFailed.GetBoundCopy();
|
||||
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||
managerAdded = manager.ItemAdded.GetBoundCopy();
|
||||
managerAdded.BindValueChanged(itemAdded);
|
||||
managedUpdated = manager.ItemUpdated.GetBoundCopy();
|
||||
managedUpdated.BindValueChanged(itemUpdated);
|
||||
managerRemoved = manager.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
}
|
||||
@ -128,7 +128,7 @@ namespace osu.Game.Online
|
||||
|
||||
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))
|
||||
setDownloadStateFromManager(item, DownloadState.LocallyAvailable);
|
||||
|
@ -192,7 +192,7 @@ namespace osu.Game
|
||||
ScoreManager.Delete(getBeatmapScores(item), true);
|
||||
});
|
||||
|
||||
BeatmapManager.ItemAdded.BindValueChanged(i =>
|
||||
BeatmapManager.ItemUpdated.BindValueChanged(i =>
|
||||
{
|
||||
if (i.NewValue.TryGetTarget(out var item))
|
||||
ScoreManager.Undelete(getBeatmapScores(item), true);
|
||||
@ -229,8 +229,8 @@ namespace osu.Game
|
||||
|
||||
FileStore.Cleanup();
|
||||
|
||||
if (API is APIAccess apiAcces)
|
||||
AddInternal(apiAcces);
|
||||
if (API is APIAccess apiAccess)
|
||||
AddInternal(apiAccess);
|
||||
AddInternal(RulesetConfigCache);
|
||||
|
||||
GlobalActionContainer globalBinding;
|
||||
|
@ -177,7 +177,9 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
lastResponse?.Cursor,
|
||||
searchControl.Category.Value,
|
||||
sortControl.Current.Value,
|
||||
sortControl.SortDirection.Value);
|
||||
sortControl.SortDirection.Value,
|
||||
searchControl.Genre.Value,
|
||||
searchControl.Language.Value);
|
||||
|
||||
getSetsRequest.Success += response =>
|
||||
{
|
||||
@ -186,6 +188,9 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
if (sets.Count == 0)
|
||||
noMoreResults = true;
|
||||
|
||||
if (CurrentPage == 0)
|
||||
searchControl.BeatmapSet = sets.FirstOrDefault();
|
||||
|
||||
lastResponse = response;
|
||||
getSetsRequest = null;
|
||||
|
||||
|
@ -60,14 +60,14 @@ namespace osu.Game.Overlays
|
||||
[Resolved(canBeNull: true)]
|
||||
private OnScreenDisplay onScreenDisplay { get; set; }
|
||||
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerAdded;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
managerAdded = beatmaps.ItemAdded.GetBoundCopy();
|
||||
managerAdded.BindValueChanged(beatmapAdded);
|
||||
managerUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||
managerRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(beatmapRemoved);
|
||||
|
||||
@ -98,14 +98,14 @@ namespace osu.Game.Overlays
|
||||
/// </summary>
|
||||
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))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (!beatmapSets.Contains(set))
|
||||
beatmapSets.Add(set);
|
||||
beatmapSets.Remove(set);
|
||||
beatmapSets.Add(set);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
|
||||
private IBindable<WeakReference<SkinInfo>> managerAdded;
|
||||
private IBindable<WeakReference<SkinInfo>> managerUpdated;
|
||||
private IBindable<WeakReference<SkinInfo>> managerRemoved;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
},
|
||||
};
|
||||
|
||||
managerAdded = skins.ItemAdded.GetBoundCopy();
|
||||
managerAdded.BindValueChanged(itemAdded);
|
||||
managerUpdated = skins.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(itemUpdated);
|
||||
|
||||
managerRemoved = skins.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
@ -92,10 +92,10 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
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))
|
||||
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)
|
||||
|
@ -48,6 +48,8 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
||||
|
||||
public override Playfield Playfield => drawableRulesetWrapper.Playfield;
|
||||
|
||||
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
||||
|
||||
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
||||
@ -102,6 +104,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
{
|
||||
Name = "Content",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
// layers below playfield
|
||||
@ -260,11 +263,13 @@ namespace osu.Game.Rulesets.Edit
|
||||
[Cached(typeof(IPositionSnapProvider))]
|
||||
public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
||||
{
|
||||
internal HitObjectComposer()
|
||||
protected HitObjectComposer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
public abstract Playfield Playfield { get; }
|
||||
|
||||
/// <summary>
|
||||
/// All the <see cref="DrawableHitObject"/>s.
|
||||
/// </summary>
|
||||
|
@ -15,7 +15,12 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// </summary>
|
||||
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)
|
||||
: base(drawableObject.HitObject)
|
||||
|
@ -44,6 +44,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private IPositionSnapProvider snapProvider { get; set; }
|
||||
|
||||
|
@ -32,14 +32,14 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
Text = "Start";
|
||||
}
|
||||
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerAdded;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
managerAdded = beatmaps.ItemAdded.GetBoundCopy();
|
||||
managerAdded.BindValueChanged(beatmapAdded);
|
||||
managerUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||
managerRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(beatmapRemoved);
|
||||
|
||||
@ -61,7 +61,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
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))
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Screens.Multi.Match
|
||||
private LeaderboardChatDisplay leaderboardChatDisplay;
|
||||
private MatchSettingsOverlay settingsOverlay;
|
||||
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerAdded;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||
|
||||
public MatchSubScreen(Room room)
|
||||
{
|
||||
@ -183,8 +183,8 @@ namespace osu.Game.Screens.Multi.Match
|
||||
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
|
||||
SelectedItem.Value = playlist.FirstOrDefault();
|
||||
|
||||
managerAdded = beatmapManager.ItemAdded.GetBoundCopy();
|
||||
managerAdded.BindValueChanged(beatmapAdded);
|
||||
managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||
}
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
@ -217,7 +217,7 @@ namespace osu.Game.Screens.Multi.Match
|
||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
||||
}
|
||||
|
||||
private void beatmapAdded(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
|
@ -479,7 +479,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
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
|
||||
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Screens.Play
|
||||
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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -13,6 +14,8 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
public class ReplayDownloadButton : DownloadTrackingComposite<ScoreInfo, ScoreManager>
|
||||
{
|
||||
public Bindable<ScoreInfo> Score => Model;
|
||||
|
||||
private DownloadButton button;
|
||||
private ShakeContainer shakeContainer;
|
||||
|
||||
@ -23,7 +26,7 @@ namespace osu.Game.Screens.Ranking
|
||||
if (State.Value == DownloadState.LocallyAvailable)
|
||||
return ReplayAvailability.Local;
|
||||
|
||||
if (!string.IsNullOrEmpty(Model.Value.Hash))
|
||||
if (!string.IsNullOrEmpty(Model.Value?.Hash))
|
||||
return ReplayAvailability.Online;
|
||||
|
||||
return ReplayAvailability.NotAvailable;
|
||||
|
@ -2,7 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -10,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Play;
|
||||
@ -17,7 +20,7 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
public class ResultsScreen : OsuScreen
|
||||
public abstract class ResultsScreen : OsuScreen
|
||||
{
|
||||
protected const float BACKGROUND_BLUR = 20;
|
||||
|
||||
@ -28,19 +31,26 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
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)]
|
||||
private Player player { get; set; }
|
||||
|
||||
public readonly ScoreInfo Score;
|
||||
|
||||
private readonly bool allowRetry;
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private Drawable bottomPanel;
|
||||
private ScorePanelList panels;
|
||||
|
||||
public ResultsScreen(ScoreInfo score, bool allowRetry = true)
|
||||
protected ResultsScreen(ScoreInfo score, bool allowRetry = true)
|
||||
{
|
||||
Score = score;
|
||||
this.allowRetry = allowRetry;
|
||||
|
||||
SelectedScore.Value = score;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -48,47 +58,68 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
FillFlowContainer buttons;
|
||||
|
||||
InternalChildren = new[]
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
new ResultsScrollContainer
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
Child = new ScorePanel(Score)
|
||||
new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
State = PanelState.Expanded
|
||||
new ResultsScrollContainer
|
||||
{
|
||||
Child = panels = new ScorePanelList
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
SelectedScore = { BindTarget = SelectedScore }
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
bottomPanel = new Container
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = TwoLayerButton.SIZE_EXTENDED.Y,
|
||||
Alpha = 0,
|
||||
Children = new Drawable[]
|
||||
new[]
|
||||
{
|
||||
new Box
|
||||
bottomPanel = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#333")
|
||||
},
|
||||
buttons = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(5),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = TwoLayerButton.SIZE_EXTENDED.Y,
|
||||
Alpha = 0,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ReplayDownloadButton(Score) { Width = 300 },
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#333")
|
||||
},
|
||||
buttons = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(5),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
@ -142,7 +194,7 @@ namespace osu.Game.Screens.Ranking
|
||||
protected override void 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.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Contracted;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -21,12 +23,12 @@ namespace osu.Game.Screens.Ranking
|
||||
/// <summary>
|
||||
/// Width of the panel when contracted.
|
||||
/// </summary>
|
||||
private const float contracted_width = 160;
|
||||
public const float CONTRACTED_WIDTH = 130;
|
||||
|
||||
/// <summary>
|
||||
/// Height of the panel when contracted.
|
||||
/// </summary>
|
||||
private const float contracted_height = 320;
|
||||
private const float contracted_height = 355;
|
||||
|
||||
/// <summary>
|
||||
/// Width of the panel when expanded.
|
||||
@ -46,7 +48,7 @@ namespace osu.Game.Screens.Ranking
|
||||
/// <summary>
|
||||
/// Height of the top layer when the panel is contracted.
|
||||
/// </summary>
|
||||
private const float contracted_top_layer_height = 40;
|
||||
private const float contracted_top_layer_height = 30;
|
||||
|
||||
/// <summary>
|
||||
/// 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_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_middle_layer_colour = Color4Extensions.FromHex("#444");
|
||||
private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#353535");
|
||||
|
||||
public event Action<PanelState> StateChanged;
|
||||
public readonly ScoreInfo Score;
|
||||
|
||||
private readonly ScoreInfo score;
|
||||
private Container content;
|
||||
|
||||
private Container topLayerContainer;
|
||||
private Drawable topLayerBackground;
|
||||
@ -89,47 +92,54 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
public ScorePanel(ScoreInfo score)
|
||||
{
|
||||
this.score = score;
|
||||
Score = score;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChild = content = new Container
|
||||
{
|
||||
topLayerContainer = new Container
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(40),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Name = "Top layer",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 120,
|
||||
Children = new Drawable[]
|
||||
topLayerContainer = new Container
|
||||
{
|
||||
new Container
|
||||
Name = "Top layer",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Alpha = 0,
|
||||
Height = 120,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CornerRadius = 20,
|
||||
CornerExponent = 2.5f,
|
||||
Masking = true,
|
||||
Child = topLayerBackground = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
topLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
},
|
||||
middleLayerContainer = new Container
|
||||
{
|
||||
Name = "Middle layer",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CornerRadius = 20,
|
||||
CornerExponent = 2.5f,
|
||||
Masking = true,
|
||||
Child = topLayerBackground = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
topLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
},
|
||||
middleLayerContainer = new Container
|
||||
{
|
||||
new Container
|
||||
Name = "Middle layer",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CornerRadius = 20,
|
||||
CornerExponent = 2.5f,
|
||||
Masking = true,
|
||||
Child = middleLayerBackground = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
middleLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CornerRadius = 20,
|
||||
CornerExponent = 2.5f,
|
||||
Masking = true,
|
||||
Child = middleLayerBackground = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
middleLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -174,34 +184,40 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
topLayerContainer.MoveToY(0, resize_duration, Easing.OutQuint);
|
||||
middleLayerContainer.MoveToY(0, resize_duration, Easing.OutQuint);
|
||||
|
||||
topLayerContent?.FadeOut(content_fade_duration).Expire();
|
||||
middleLayerContent?.FadeOut(content_fade_duration).Expire();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
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);
|
||||
middleLayerBackground.FadeColour(expanded_middle_layer_colour, resize_duration, Easing.OutQuint);
|
||||
|
||||
topLayerContentContainer.Add(middleLayerContent = new ExpandedPanelTopContent(score.User).With(d => d.Alpha = 0));
|
||||
middleLayerContentContainer.Add(topLayerContent = new ExpandedPanelMiddleContent(score).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));
|
||||
break;
|
||||
|
||||
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);
|
||||
middleLayerBackground.FadeColour(contracted_middle_layer_colour, resize_duration, Easing.OutQuint);
|
||||
|
||||
middleLayerContentContainer.Add(topLayerContent = new ContractedPanelMiddleContent(Score).With(d => d.Alpha = 0));
|
||||
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)
|
||||
{
|
||||
case PanelState.Expanded:
|
||||
@ -219,5 +235,13 @@ namespace osu.Game.Screens.Ranking
|
||||
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 IBindable<WeakReference<BeatmapSetInfo>> itemAdded;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> itemUpdated;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> itemRemoved;
|
||||
private IBindable<WeakReference<BeatmapInfo>> itemHidden;
|
||||
private IBindable<WeakReference<BeatmapInfo>> itemRestored;
|
||||
@ -166,8 +166,8 @@ namespace osu.Game.Screens.Select
|
||||
RightClickScrollingEnabled.ValueChanged += enabled => scroll.RightMouseScrollbar = enabled.NewValue;
|
||||
RightClickScrollingEnabled.TriggerChange();
|
||||
|
||||
itemAdded = beatmaps.ItemAdded.GetBoundCopy();
|
||||
itemAdded.BindValueChanged(beatmapAdded);
|
||||
itemUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||
itemUpdated.BindValueChanged(beatmapUpdated);
|
||||
itemRemoved = beatmaps.ItemRemoved.GetBoundCopy();
|
||||
itemRemoved.BindValueChanged(beatmapRemoved);
|
||||
itemHidden = beatmaps.BeatmapHidden.GetBoundCopy();
|
||||
@ -582,7 +582,7 @@ namespace osu.Game.Screens.Select
|
||||
RemoveBeatmapSet(item);
|
||||
}
|
||||
|
||||
private void beatmapAdded(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
UpdateBeatmapSet(item);
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private IBindable<WeakReference<ScoreInfo>> itemAdded;
|
||||
private IBindable<WeakReference<ScoreInfo>> itemUpdated;
|
||||
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
|
||||
|
||||
public TopLocalRank(BeatmapInfo beatmap)
|
||||
@ -40,8 +40,8 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
itemAdded = scores.ItemAdded.GetBoundCopy();
|
||||
itemAdded.BindValueChanged(scoreChanged);
|
||||
itemUpdated = scores.ItemUpdated.GetBoundCopy();
|
||||
itemUpdated.BindValueChanged(scoreChanged);
|
||||
|
||||
itemRemoved = scores.ItemRemoved.GetBoundCopy();
|
||||
itemRemoved.BindValueChanged(scoreChanged);
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
|
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.Core" Version="2.2.6" />
|
||||
<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="Sentry" Version="2.1.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
<!-- 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.Core" Version="2.2.6" />
|
||||
<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="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user