mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 03:13:22 +08:00
Merge remote-tracking branch 'origin/master' into layout-rework
This commit is contained in:
commit
da89798765
@ -54,6 +54,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.225.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -29,6 +29,12 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBananaShower()
|
||||
{
|
||||
AddUntilStep("player is done", () => !Player.ValidForResume);
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
@ -40,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
};
|
||||
|
||||
beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
|
||||
beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 3000, NewCombo = true });
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
56
osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
Normal file
56
osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public class TestSceneJuiceStream : PlayerTestScene
|
||||
{
|
||||
public TestSceneJuiceStream()
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJuiceStreamEndingCombo()
|
||||
{
|
||||
AddUntilStep("player is done", () => !Player.ValidForResume);
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 },
|
||||
Ruleset = ruleset
|
||||
},
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
new JuiceStream
|
||||
{
|
||||
X = 0.5f,
|
||||
Path = new SliderPath(PathType.Linear, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(0, 100)
|
||||
}),
|
||||
StartTime = 200
|
||||
},
|
||||
new Banana
|
||||
{
|
||||
X = 0.5f,
|
||||
StartTime = 1000,
|
||||
NewCombo = true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// 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.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
public override bool LastInCombo => true;
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
|
@ -7,6 +7,7 @@ using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
@ -19,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
/// </summary>
|
||||
private const float base_scoring_distance = 100;
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
public int RepeatCount { get; set; }
|
||||
|
||||
public double Velocity;
|
||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (fruit.HitObject.LastInCombo)
|
||||
{
|
||||
if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result))
|
||||
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
||||
runAfterLoaded(() => MovableCatcher.Explode());
|
||||
else
|
||||
MovableCatcher.Drop();
|
||||
|
@ -1,14 +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.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public class HoldNoteJudgement : ManiaJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// 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.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
public class BarLine : ManiaHitObject, IBarLine
|
||||
{
|
||||
public bool Major { get; set; }
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
}
|
||||
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
}
|
||||
protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
@ -103,7 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
}
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new HoldNoteJudgement();
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -1,14 +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.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Judgements
|
||||
{
|
||||
public class OsuSliderTailJudgement : OsuJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
private const int spacing = 32;
|
||||
private const double preempt = 800;
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
/// <summary>
|
||||
/// The start time of <see cref="Start"/>.
|
||||
/// </summary>
|
||||
@ -79,27 +81,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
drawableObject.HitObject.DefaultsApplied += scheduleRefresh;
|
||||
}
|
||||
|
||||
private void scheduleRefresh() => Scheduler.AddOnce(refresh);
|
||||
private void scheduleRefresh()
|
||||
{
|
||||
Scheduler.AddOnce(refresh);
|
||||
}
|
||||
|
||||
private void refresh()
|
||||
{
|
||||
ClearInternal();
|
||||
|
||||
if (End == null)
|
||||
return;
|
||||
|
||||
OsuHitObject osuStart = Start.HitObject;
|
||||
OsuHitObject osuEnd = End.HitObject;
|
||||
double startTime = osuStart.GetEndTime();
|
||||
|
||||
if (osuEnd.NewCombo)
|
||||
return;
|
||||
LifetimeStart = startTime;
|
||||
|
||||
if (osuStart is Spinner || osuEnd is Spinner)
|
||||
OsuHitObject osuEnd = End?.HitObject;
|
||||
|
||||
if (osuEnd == null || osuEnd.NewCombo || osuStart is Spinner || osuEnd is Spinner)
|
||||
{
|
||||
// ensure we always set a lifetime for full LifetimeManagementContainer benefits
|
||||
LifetimeEnd = LifetimeStart;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 startPosition = osuStart.EndPosition;
|
||||
Vector2 endPosition = osuEnd.Position;
|
||||
double startTime = osuStart.GetEndTime();
|
||||
double endTime = osuEnd.StartTime;
|
||||
|
||||
Vector2 distanceVector = endPosition - startPosition;
|
||||
@ -107,6 +113,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
|
||||
double duration = endTime - startTime;
|
||||
|
||||
double? firstTransformStartTime = null;
|
||||
double finalTransformEndTime = startTime;
|
||||
|
||||
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
|
||||
{
|
||||
float fraction = (float)d / distance;
|
||||
@ -125,16 +134,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
Scale = new Vector2(1.5f * osuEnd.Scale),
|
||||
});
|
||||
|
||||
if (firstTransformStartTime == null)
|
||||
firstTransformStartTime = fadeInTime;
|
||||
|
||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||
{
|
||||
fp.FadeIn(osuEnd.TimeFadeIn);
|
||||
fp.ScaleTo(osuEnd.Scale, osuEnd.TimeFadeIn, Easing.Out);
|
||||
fp.MoveTo(pointEndPosition, osuEnd.TimeFadeIn, Easing.Out);
|
||||
fp.Delay(fadeOutTime - fadeInTime).FadeOut(osuEnd.TimeFadeIn);
|
||||
}
|
||||
|
||||
fp.Expire(true);
|
||||
finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn;
|
||||
}
|
||||
}
|
||||
|
||||
// todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed.
|
||||
LifetimeStart = firstTransformStartTime ?? startTime;
|
||||
LifetimeEnd = finalTransformEndTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
/// <summary>
|
||||
/// Visualises connections between <see cref="DrawableOsuHitObject"/>s.
|
||||
/// </summary>
|
||||
public class FollowPointRenderer : CompositeDrawable
|
||||
public class FollowPointRenderer : LifetimeManagementContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// All the <see cref="FollowPointConnection"/>s contained by this <see cref="FollowPointRenderer"/>.
|
||||
@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
/// <returns>The index of <paramref name="connection"/> in <see cref="connections"/>.</returns>
|
||||
private void addConnection(FollowPointConnection connection)
|
||||
{
|
||||
AddInternal(connection);
|
||||
|
||||
// Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections
|
||||
int index = connections.AddInPlace(connection, Comparer<FollowPointConnection>.Create((g1, g2) => g1.StartTime.Value.CompareTo(g2.StartTime.Value)));
|
||||
|
||||
@ -74,6 +72,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
FollowPointConnection previousConnection = connections[index - 1];
|
||||
previousConnection.End = connection.Start;
|
||||
}
|
||||
|
||||
AddInternal(connection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
public void TestZeroTickTimeOffsets()
|
||||
{
|
||||
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted);
|
||||
AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0));
|
||||
AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
|
||||
}
|
||||
|
||||
protected override bool Autoplay => true;
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
public class BarLine : TaikoHitObject, IBarLine
|
||||
{
|
||||
public bool Major { get; set; }
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -54,5 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
Alpha = 0.75f
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,12 @@
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
public class SwellTick : TaikoHitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new TaikoSwellTickJudgement();
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
private class JudgeableHitObject : HitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new Judgement();
|
||||
protected override HitWindows CreateHitWindows() => new HitWindows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -78,7 +78,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHitObjectWithCombo : HitObject, IHasComboInformation
|
||||
private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation
|
||||
{
|
||||
public bool NewCombo { get; } = false;
|
||||
public int ComboOffset { get; } = 0;
|
||||
|
@ -20,6 +20,7 @@ using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.UI;
|
||||
@ -289,7 +290,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
#region HitObject
|
||||
|
||||
private class TestHitObject : HitObject, IHasEndTime
|
||||
private class TestHitObject : ConvertHitObject, IHasEndTime
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
|
@ -2,16 +2,17 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
@ -43,6 +44,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20);
|
||||
AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20);
|
||||
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
|
||||
|
||||
AddStep("Judgement barrage", () =>
|
||||
{
|
||||
int runCount = 0;
|
||||
|
||||
ScheduledDelegate del = null;
|
||||
|
||||
del = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
newJudgement(runCount++ / 10f);
|
||||
|
||||
if (runCount == 500)
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
del?.Cancel();
|
||||
}, 10, true);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -13,6 +13,8 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -30,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
private readonly BindableBool showDeleted = new BindableBool();
|
||||
private readonly Container content;
|
||||
|
||||
private TestCommentsPage commentsPage;
|
||||
|
||||
public TestSceneCommentsPage()
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
@ -57,15 +61,29 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AddStep("load comments", () => createPage(getCommentBundle()));
|
||||
AddStep("load empty comments", () => createPage(getEmptyCommentBundle()));
|
||||
[Test]
|
||||
public void TestAppendDuplicatedComment()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getCommentBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyBundle()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getEmptyCommentBundle()));
|
||||
AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0);
|
||||
}
|
||||
|
||||
private void createPage(CommentBundle commentBundle)
|
||||
{
|
||||
commentsPage = null;
|
||||
content.Clear();
|
||||
content.Add(new CommentsPage(commentBundle)
|
||||
content.Add(commentsPage = new TestCommentsPage(commentBundle)
|
||||
{
|
||||
ShowDeleted = { BindTarget = showDeleted }
|
||||
});
|
||||
@ -182,5 +200,33 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
private CommentBundle getCommentSubBundle() => new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>
|
||||
{
|
||||
new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "Simple test comment",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
private class TestCommentsPage : CommentsPage
|
||||
{
|
||||
public TestCommentsPage(CommentBundle commentBundle)
|
||||
: base(commentBundle)
|
||||
{
|
||||
}
|
||||
|
||||
public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle);
|
||||
|
||||
public int DictionaryLength => CommentDictionary.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
@ -194,7 +195,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
public new BufferedWedgeInfo Info => base.Info;
|
||||
}
|
||||
|
||||
private class TestHitObject : HitObject, IHasPosition
|
||||
private class TestHitObject : ConvertHitObject, IHasPosition
|
||||
{
|
||||
public float X { get; } = 0;
|
||||
public float Y { get; } = 0;
|
||||
|
@ -0,0 +1,57 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Home.Friends;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneUserListToolbar : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(UserSortTabControl),
|
||||
typeof(OverlaySortTabControl<>),
|
||||
typeof(OverlayPanelDisplayStyleControl),
|
||||
typeof(UserListToolbar),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
public TestSceneUserListToolbar()
|
||||
{
|
||||
UserListToolbar toolbar;
|
||||
OsuSpriteText sort;
|
||||
OsuSpriteText displayStyle;
|
||||
|
||||
Add(toolbar = new UserListToolbar
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sort = new OsuSpriteText(),
|
||||
displayStyle = new OsuSpriteText()
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.SortCriteria.BindValueChanged(criteria => sort.Text = $"Criteria: {criteria.NewValue}", true);
|
||||
toolbar.DisplayStyle.BindValueChanged(style => displayStyle.Text = $"Style: {style.NewValue}", true);
|
||||
}
|
||||
}
|
||||
}
|
@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
MainContents.Size = new Vector2(Math.Min(100, Math.Min(DrawWidth, DrawHeight) * 0.25f));
|
||||
MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
private void rotate()
|
||||
{
|
||||
spinner.Spin(spin_duration * 4, RotationDirection.Clockwise);
|
||||
spinner.Spin(spin_duration * 3.5f, RotationDirection.Clockwise);
|
||||
|
||||
MainContents.RotateTo(0).Then()
|
||||
.RotateTo(90, spin_duration, Easing.InOutQuart).Then()
|
||||
|
29
osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
Normal file
29
osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapSetLayoutSection : Container
|
||||
{
|
||||
public BeatmapSetLayoutSection()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -3,17 +3,14 @@
|
||||
|
||||
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.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
@ -43,14 +40,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = base_height;
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
public class ScoresContainer : CompositeDrawable
|
||||
public class ScoresContainer : BeatmapSetLayoutSection
|
||||
{
|
||||
private const int spacing = 15;
|
||||
|
||||
@ -34,7 +34,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private readonly LoadingLayer loading;
|
||||
private readonly LeaderboardModSelector modSelector;
|
||||
private readonly NoScoresPlaceholder noScoresPlaceholder;
|
||||
private readonly FillFlowContainer content;
|
||||
private readonly NotSupporterPlaceholder notSupporterPlaceholder;
|
||||
|
||||
[Resolved]
|
||||
@ -76,15 +75,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
public ScoresContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
InternalChildren = new Drawable[]
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
content = new FillFlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
@ -164,8 +161,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -223,7 +220,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending)
|
||||
{
|
||||
Scores = null;
|
||||
content.Hide();
|
||||
Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -237,7 +234,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
notSupporterPlaceholder.Hide();
|
||||
|
||||
content.Show();
|
||||
Show();
|
||||
loading.Show();
|
||||
|
||||
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
|
||||
@ -40,6 +41,7 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
OsuScrollContainer scroll;
|
||||
Info info;
|
||||
CommentsSection comments;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -51,29 +53,33 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollbarVisible = false,
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
Child = new ReverseChildIDFillFlowContainer<BeatmapSetLayoutSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
new ReverseChildIDFillFlowContainer<Drawable>
|
||||
new BeatmapSetLayoutSection
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
Header = new Header(),
|
||||
info = new Info()
|
||||
}
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Header = new Header(),
|
||||
info = new Info()
|
||||
}
|
||||
},
|
||||
},
|
||||
new ScoresContainer
|
||||
{
|
||||
Beatmap = { BindTarget = Header.Picker.Beatmap }
|
||||
}
|
||||
},
|
||||
comments = new CommentsSection()
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -81,6 +87,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
Header.BeatmapSet.BindTo(beatmapSet);
|
||||
info.BeatmapSet.BindTo(beatmapSet);
|
||||
comments.BeatmapSet.BindTo(beatmapSet);
|
||||
|
||||
Header.Picker.Beatmap.ValueChanged += b =>
|
||||
{
|
||||
@ -143,5 +150,30 @@ namespace osu.Game.Overlays
|
||||
beatmapSet.Value = set;
|
||||
Show();
|
||||
}
|
||||
|
||||
private class CommentsSection : BeatmapSetLayoutSection
|
||||
{
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
public CommentsSection()
|
||||
{
|
||||
CommentsContainer comments;
|
||||
|
||||
Add(comments = new CommentsContainer());
|
||||
|
||||
BeatmapSet.BindValueChanged(beatmapSet =>
|
||||
{
|
||||
if (beatmapSet.NewValue?.OnlineBeatmapSetID is int onlineBeatmapSetID)
|
||||
{
|
||||
Show();
|
||||
comments.ShowComments(CommentableType.Beatmapset, onlineBeatmapSetID);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using System.Net;
|
||||
using osuTK;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
@ -51,28 +52,27 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||
{
|
||||
foreach (var categoryEntries in Build.ChangelogEntries.GroupBy(b => b.Category).OrderBy(c => c.Key))
|
||||
{
|
||||
ChangelogEntries.Add(new OsuSpriteText
|
||||
{
|
||||
Text = categoryEntries.Key,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18),
|
||||
Margin = new MarginPadding { Top = 35, Bottom = 15 },
|
||||
});
|
||||
|
||||
var fontLarge = OsuFont.GetFont(size: 18);
|
||||
var fontMedium = OsuFont.GetFont(size: 14);
|
||||
var fontSmall = OsuFont.GetFont(size: 12);
|
||||
var fontLarge = OsuFont.GetFont(size: 16);
|
||||
var fontMedium = OsuFont.GetFont(size: 12);
|
||||
|
||||
foreach (APIChangelogEntry entry in categoryEntries)
|
||||
foreach (var entry in categoryEntries)
|
||||
{
|
||||
var entryColour = entry.Major ? colours.YellowLight : Color4.White;
|
||||
|
||||
LinkFlowContainer title;
|
||||
|
||||
Container titleContainer = new Container
|
||||
var titleContainer = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -83,9 +83,9 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreRight,
|
||||
Size = new Vector2(fontSmall.Size),
|
||||
Size = new Vector2(10),
|
||||
Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus,
|
||||
Colour = entryColour,
|
||||
Colour = entryColour.Opacity(0.5f),
|
||||
Margin = new MarginPadding { Right = 5 },
|
||||
},
|
||||
title = new LinkFlowContainer
|
||||
@ -123,10 +123,11 @@ namespace osu.Game.Overlays.Changelog
|
||||
});
|
||||
}
|
||||
|
||||
title.AddText(" by ", t =>
|
||||
title.AddText("by ", t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
t.Padding = new MarginPadding { Left = 10 };
|
||||
});
|
||||
|
||||
if (entry.GithubUser.UserId != null)
|
||||
@ -137,7 +138,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
Id = entry.GithubUser.UserId.Value
|
||||
}, t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -145,7 +146,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
title.AddText(entry.GithubUser.DisplayName, t =>
|
||||
{
|
||||
t.Font = fontSmall;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -162,7 +163,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
if (!string.IsNullOrEmpty(entry.MessageHtml))
|
||||
{
|
||||
TextFlowContainer message = new TextFlowContainer
|
||||
var message = new TextFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -171,8 +172,8 @@ namespace osu.Game.Overlays.Changelog
|
||||
// todo: use markdown parsing once API returns markdown
|
||||
message.AddText(WebUtility.HtmlDecode(Regex.Replace(entry.MessageHtml, @"<(.|\n)*?>", string.Empty)), t =>
|
||||
{
|
||||
t.Font = fontSmall;
|
||||
t.Colour = new Color4(235, 184, 254, 255);
|
||||
t.Font = fontMedium;
|
||||
t.Colour = colourProvider.Foreground1;
|
||||
});
|
||||
|
||||
ChangelogEntries.Add(message);
|
||||
|
@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Changelog
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Vertical;
|
||||
Padding = new MarginPadding { Bottom = 50 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
@ -24,13 +23,13 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
DateTime currentDate = DateTime.MinValue;
|
||||
var currentDate = DateTime.MinValue;
|
||||
|
||||
if (entries == null) return;
|
||||
|
||||
foreach (APIChangelogBuild build in entries)
|
||||
foreach (var build in entries)
|
||||
{
|
||||
if (build.CreatedAt.Date != currentDate)
|
||||
{
|
||||
@ -40,7 +39,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
Colour = new Color4(17, 17, 17, 255),
|
||||
Colour = colourProvider.Background6,
|
||||
Margin = new MarginPadding { Top = 30 },
|
||||
});
|
||||
}
|
||||
@ -49,10 +48,9 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Margin = new MarginPadding { Top = 15 },
|
||||
Text = build.CreatedAt.Date.ToString("dd MMM yyyy"),
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Text = build.CreatedAt.Date.ToString("dd MMMM yyyy"),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 24),
|
||||
Colour = OsuColour.FromHex(@"FD5"),
|
||||
});
|
||||
|
||||
currentDate = build.CreatedAt.Date;
|
||||
@ -68,7 +66,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = new Color4(32, 24, 35, 255),
|
||||
Colour = colourProvider.Background6,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@ -31,7 +32,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(CancellationToken? cancellation, IAPIProvider api)
|
||||
private void load(CancellationToken? cancellation, IAPIProvider api, OverlayColourProvider colourProvider)
|
||||
{
|
||||
bool complete = false;
|
||||
|
||||
@ -63,10 +64,14 @@ namespace osu.Game.Overlays.Changelog
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild },
|
||||
comments = new CommentsContainer
|
||||
new Box
|
||||
{
|
||||
Margin = new MarginPadding { Top = 10 }
|
||||
}
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
Colour = colourProvider.Background6,
|
||||
Margin = new MarginPadding { Top = 30 },
|
||||
},
|
||||
comments = new CommentsContainer()
|
||||
};
|
||||
|
||||
comments.ShowComments(CommentableType.Build, build.Id);
|
||||
@ -80,6 +85,8 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
}
|
||||
|
||||
private OsuSpriteText date;
|
||||
|
||||
protected override FillFlowContainer CreateHeader()
|
||||
{
|
||||
var fill = base.CreateHeader();
|
||||
@ -89,11 +96,10 @@ namespace osu.Game.Overlays.Changelog
|
||||
existing.Scale = new Vector2(1.25f);
|
||||
existing.Action = null;
|
||||
|
||||
existing.Add(new OsuSpriteText
|
||||
existing.Add(date = new OsuSpriteText
|
||||
{
|
||||
Text = Build.CreatedAt.Date.ToString("dd MMM yyyy"),
|
||||
Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14),
|
||||
Colour = OsuColour.FromHex(@"FD5"),
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
@ -113,6 +119,12 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
return fill;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
date.Colour = colourProvider.Light1;
|
||||
}
|
||||
}
|
||||
|
||||
private class NavigationIconButton : IconButton
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -16,99 +14,90 @@ using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class UpdateStreamBadge : TabItem<APIUpdateStream>
|
||||
{
|
||||
private const float badge_height = 66.5f;
|
||||
private const float badge_width = 100;
|
||||
private const float transition_duration = 100;
|
||||
|
||||
private readonly ExpandingBar expandingBar;
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
private readonly FillFlowContainer<SpriteText> text;
|
||||
|
||||
public readonly Bindable<APIUpdateStream> SelectedTab = new Bindable<APIUpdateStream>();
|
||||
|
||||
private readonly Container fadeContainer;
|
||||
private readonly APIUpdateStream stream;
|
||||
|
||||
private Container fadeContainer;
|
||||
private FillFlowContainer<SpriteText> text;
|
||||
private ExpandingBar expandingBar;
|
||||
|
||||
public UpdateStreamBadge(APIUpdateStream stream)
|
||||
: base(stream)
|
||||
{
|
||||
Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, badge_height);
|
||||
Padding = new MarginPadding(5);
|
||||
|
||||
Child = fadeContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new FillFlowContainer<SpriteText>
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.DisplayName,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12),
|
||||
Margin = new MarginPadding { Top = 6 },
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.DisplayVersion,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Light, size: 16),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.Users > 0 ? $"{stream.LatestBuild.Users:N0} {"user".Pluralize(stream.LatestBuild.Users == 1)} online" : null,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 10),
|
||||
Colour = new Color4(203, 164, 218, 255),
|
||||
},
|
||||
}
|
||||
},
|
||||
expandingBar = new ExpandingBar
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Colour = stream.Colour,
|
||||
ExpandedSize = 4,
|
||||
CollapsedSize = 2,
|
||||
IsCollapsed = true
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
SelectedTab.BindValueChanged(_ => updateState(), true);
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
sampleClick = audio.Samples.Get(@"UI/generic-select-soft");
|
||||
sampleHover = audio.Samples.Get(@"UI/generic-hover-soft");
|
||||
Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60);
|
||||
Padding = new MarginPadding(5);
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
fadeContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new FillFlowContainer<SpriteText>
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Margin = new MarginPadding { Top = 6 },
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.DisplayName,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.DisplayVersion,
|
||||
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null,
|
||||
Font = OsuFont.GetFont(size: 10),
|
||||
Colour = colourProvider.Foreground1
|
||||
},
|
||||
}
|
||||
},
|
||||
expandingBar = new ExpandingBar
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Colour = stream.Colour,
|
||||
ExpandedSize = 4,
|
||||
CollapsedSize = 2,
|
||||
IsCollapsed = true
|
||||
},
|
||||
}
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
|
||||
SelectedTab.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
sampleClick?.Play();
|
||||
return base.OnClick(e);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
sampleHover?.Play();
|
||||
updateState();
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
|
@ -8,34 +8,34 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class UpdateStreamBadgeArea : TabControl<APIUpdateStream>
|
||||
{
|
||||
public UpdateStreamBadgeArea()
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
AddInternal(new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.12f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background5,
|
||||
});
|
||||
}
|
||||
|
||||
public void Populate(List<APIUpdateStream> streams)
|
||||
{
|
||||
foreach (APIUpdateStream updateStream in streams)
|
||||
foreach (var updateStream in streams)
|
||||
AddItem(updateStream);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
foreach (var streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.EnableDim();
|
||||
|
||||
return base.OnHover(e);
|
||||
@ -43,7 +43,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
foreach (var streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.DisableDim();
|
||||
|
||||
base.OnHoverLost(e);
|
||||
|
@ -13,7 +13,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Online.API.Requests;
|
||||
@ -42,14 +41,14 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuColour colour)
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colour.PurpleDarkAlternative,
|
||||
Colour = ColourProvider.Background4,
|
||||
},
|
||||
new OsuScrollContainer
|
||||
{
|
||||
|
@ -109,6 +109,7 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
public enum CommentsSortCriteria
|
||||
{
|
||||
[System.ComponentModel.Description(@"Recent")]
|
||||
New,
|
||||
Old,
|
||||
Top
|
||||
|
@ -61,15 +61,15 @@ namespace osu.Game.Overlays.Comments
|
||||
return;
|
||||
}
|
||||
|
||||
appendComments(commentBundle);
|
||||
AppendComments(commentBundle);
|
||||
}
|
||||
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (commentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return commentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
return CommentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
@ -81,31 +81,28 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id);
|
||||
|
||||
request.Success += response => Schedule(() => appendComments(response));
|
||||
request.Success += response => Schedule(() => AppendComments(response));
|
||||
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
private readonly Dictionary<long, DrawableComment> commentDictionary = new Dictionary<long, DrawableComment>();
|
||||
protected readonly Dictionary<long, DrawableComment> CommentDictionary = new Dictionary<long, DrawableComment>();
|
||||
|
||||
/// <summary>
|
||||
/// Appends retrieved comments to the subtree rooted of comments in this page.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The bundle of comments to add.</param>
|
||||
private void appendComments([NotNull] CommentBundle bundle)
|
||||
protected void AppendComments([NotNull] CommentBundle bundle)
|
||||
{
|
||||
var orphaned = new List<Comment>();
|
||||
|
||||
foreach (var topLevel in bundle.Comments)
|
||||
addNewComment(topLevel);
|
||||
|
||||
foreach (var child in bundle.IncludedComments)
|
||||
foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
|
||||
{
|
||||
// Included comments can contain the parent comment, which already exists in the hierarchy.
|
||||
if (commentDictionary.ContainsKey(child.Id))
|
||||
// Exclude possible duplicated comments.
|
||||
if (CommentDictionary.ContainsKey(comment.Id))
|
||||
continue;
|
||||
|
||||
addNewComment(child);
|
||||
addNewComment(comment);
|
||||
}
|
||||
|
||||
// Comments whose parents were seen later than themselves can now be added.
|
||||
@ -121,7 +118,7 @@ namespace osu.Game.Overlays.Comments
|
||||
// Comments that have no parent are added as top-level comments to the flow.
|
||||
flow.Add(drawableComment);
|
||||
}
|
||||
else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
{
|
||||
// The comment's parent has already been seen, so the parent<-> child links can be added.
|
||||
comment.ParentComment = parentDrawable.Comment;
|
||||
|
45
osu.Game/Overlays/Home/Friends/UserListToolbar.cs
Normal file
45
osu.Game/Overlays/Home/Friends/UserListToolbar.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Framework.Bindables;
|
||||
|
||||
namespace osu.Game.Overlays.Home.Friends
|
||||
{
|
||||
public class UserListToolbar : CompositeDrawable
|
||||
{
|
||||
public Bindable<UserSortCriteria> SortCriteria => sortControl.Current;
|
||||
|
||||
public Bindable<OverlayPanelDisplayStyle> DisplayStyle => styleControl.Current;
|
||||
|
||||
private readonly UserSortTabControl sortControl;
|
||||
private readonly OverlayPanelDisplayStyleControl styleControl;
|
||||
|
||||
public UserListToolbar()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
AddInternal(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sortControl = new UserSortTabControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
styleControl = new OverlayPanelDisplayStyleControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
19
osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
Normal file
19
osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
Normal file
@ -0,0 +1,19 @@
|
||||
// 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.ComponentModel;
|
||||
|
||||
namespace osu.Game.Overlays.Home.Friends
|
||||
{
|
||||
public class UserSortTabControl : OverlaySortTabControl<UserSortCriteria>
|
||||
{
|
||||
}
|
||||
|
||||
public enum UserSortCriteria
|
||||
{
|
||||
[Description(@"Recently Active")]
|
||||
LastVisit,
|
||||
Rank,
|
||||
Username
|
||||
}
|
||||
}
|
101
osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
Normal file
101
osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Allocation;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlayPanelDisplayStyleControl : OsuTabControl<OverlayPanelDisplayStyle>
|
||||
{
|
||||
protected override Dropdown<OverlayPanelDisplayStyle> CreateDropdown() => null;
|
||||
|
||||
protected override TabItem<OverlayPanelDisplayStyle> CreateTabItem(OverlayPanelDisplayStyle value) => new PanelDisplayTabItem(value);
|
||||
|
||||
protected override bool AddEnumEntriesAutomatically => false;
|
||||
|
||||
public OverlayPanelDisplayStyleControl()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Card)
|
||||
{
|
||||
Icon = FontAwesome.Solid.Square
|
||||
});
|
||||
AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.List)
|
||||
{
|
||||
Icon = FontAwesome.Solid.Bars
|
||||
});
|
||||
}
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal
|
||||
};
|
||||
|
||||
private class PanelDisplayTabItem : TabItem<OverlayPanelDisplayStyle>, IHasTooltip
|
||||
{
|
||||
public IconUsage Icon
|
||||
{
|
||||
set => icon.Icon = value;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
public string TooltipText => $@"{Value} view";
|
||||
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public PanelDisplayTabItem(OverlayPanelDisplayStyle value)
|
||||
: base(value)
|
||||
{
|
||||
Size = new Vector2(11);
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateState();
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
updateState();
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void updateState() => icon.Colour = Active.Value || IsHovered ? colourProvider.Light1 : Color4.White;
|
||||
}
|
||||
}
|
||||
|
||||
public enum OverlayPanelDisplayStyle
|
||||
{
|
||||
Card,
|
||||
List
|
||||
}
|
||||
}
|
@ -15,6 +15,8 @@ using osu.Game.Graphics.Sprites;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using osu.Framework.Extensions;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
@ -132,7 +134,7 @@ namespace osu.Game.Overlays
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = value.ToString()
|
||||
Text = (value as Enum)?.GetDescription() ?? value.ToString()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -138,6 +138,12 @@ namespace osu.Game.Overlays
|
||||
Country.Value = requested;
|
||||
}
|
||||
|
||||
public void ShowSpotlights()
|
||||
{
|
||||
Scope.Value = RankingsScope.Spotlights;
|
||||
Show();
|
||||
}
|
||||
|
||||
private void loadNewContent()
|
||||
{
|
||||
loading.Show();
|
||||
|
@ -1,11 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
namespace osu.Game.Rulesets.Judgements
|
||||
{
|
||||
public class TaikoSwellTickJudgement : TaikoJudgement
|
||||
public class IgnoreJudgement : Judgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Judgements
|
||||
return -DEFAULT_MAX_HEALTH_INCREASE * 0.01;
|
||||
|
||||
case HitResult.Good:
|
||||
return DEFAULT_MAX_HEALTH_INCREASE * 0.3;
|
||||
return DEFAULT_MAX_HEALTH_INCREASE * 0.5;
|
||||
|
||||
case HitResult.Great:
|
||||
return DEFAULT_MAX_HEALTH_INCREASE;
|
||||
|
@ -99,12 +99,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
{
|
||||
var judgement = HitObject.CreateJudgement();
|
||||
|
||||
if (judgement != null)
|
||||
{
|
||||
Result = CreateResult(judgement);
|
||||
if (Result == null)
|
||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||
}
|
||||
Result = CreateResult(judgement);
|
||||
if (Result == null)
|
||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||
|
||||
loadSamples();
|
||||
}
|
||||
@ -265,7 +262,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue)
|
||||
if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue || HitObject.HitWindows == null)
|
||||
Expire();
|
||||
}
|
||||
else
|
||||
|
@ -144,9 +144,9 @@ namespace osu.Game.Rulesets.Objects
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="Judgement"/> that represents the scoring information for this <see cref="HitObject"/>.
|
||||
/// May be null.
|
||||
/// </summary>
|
||||
public virtual Judgement CreateJudgement() => null;
|
||||
[NotNull]
|
||||
public virtual Judgement CreateJudgement() => new Judgement();
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertHit : HitObject, IHasCombo, IHasXPosition
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasCombo, IHasXPosition
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition, IHasCombo
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition, IHasCombo
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
|
18
osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs
Normal file
18
osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// 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.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
/// <summary>
|
||||
/// A hit object only used for conversion, not actual gameplay.
|
||||
/// </summary>
|
||||
internal abstract class ConvertHitObject : HitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
internal abstract class ConvertSlider : HitObject, IHasCurve, IHasLegacyLastTickOffset
|
||||
internal abstract class ConvertSlider : ConvertHitObject, IHasCurve, IHasLegacyLastTickOffset
|
||||
{
|
||||
/// <summary>
|
||||
/// Scoring distance with a speed-adjusted beat length of 1 second.
|
||||
|
@ -2,17 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
{
|
||||
/// <summary>
|
||||
/// Legacy osu!mania Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertHit : HitObject, IHasXPosition
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasXPosition
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
{
|
||||
internal sealed class ConvertHold : HitObject, IHasXPosition, IHasEndTime
|
||||
internal sealed class ConvertHold : ConvertHitObject, IHasXPosition, IHasEndTime
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
||||
public double EndTime { get; set; }
|
||||
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
{
|
||||
@ -12,7 +11,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,18 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
{
|
||||
/// <summary>
|
||||
/// Legacy osu!mania Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
public float X { get; set; }
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
|
||||
{
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasPosition, IHasCombo
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
@ -22,8 +21,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
|
||||
public float Y => Position.Y;
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
@ -1,15 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
{
|
||||
/// <summary>
|
||||
/// Legacy osu!taiko Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertHit : HitObject
|
||||
internal sealed class ConvertHit : ConvertHitObject
|
||||
{
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -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 osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
{
|
||||
/// <summary>
|
||||
@ -10,6 +8,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
/// </summary>
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider
|
||||
{
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,16 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
{
|
||||
/// <summary>
|
||||
/// Legacy osu!taiko Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -125,8 +125,6 @@ namespace osu.Game.Rulesets.Scoring
|
||||
simulate(nested);
|
||||
|
||||
var judgement = obj.CreateJudgement();
|
||||
if (judgement == null)
|
||||
return;
|
||||
|
||||
var result = CreateResult(obj, judgement);
|
||||
if (result == null)
|
||||
|
@ -1,9 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Game.Screens.Charts
|
||||
{
|
||||
public class ChartInfo : ScreenWhiteBox
|
||||
{
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Screens.Charts
|
||||
{
|
||||
public class ChartListing : ScreenWhiteBox
|
||||
{
|
||||
protected override IEnumerable<Type> PossibleChildren => new[]
|
||||
{
|
||||
typeof(ChartInfo)
|
||||
};
|
||||
}
|
||||
}
|
@ -93,15 +93,15 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
EditorMenuBar menuBar;
|
||||
|
||||
var fileMenuItems = new List<MenuItem>();
|
||||
var fileMenuItems = new List<MenuItem>
|
||||
{
|
||||
new EditorMenuItem("Save", MenuItemType.Standard, saveBeatmap)
|
||||
};
|
||||
|
||||
if (RuntimeInfo.IsDesktop)
|
||||
{
|
||||
fileMenuItems.Add(new EditorMenuItem("Save", MenuItemType.Standard, saveBeatmap));
|
||||
fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap));
|
||||
fileMenuItems.Add(new EditorMenuItemSpacer());
|
||||
}
|
||||
|
||||
fileMenuItems.Add(new EditorMenuItemSpacer());
|
||||
fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit));
|
||||
|
||||
AddInternal(new OsuContextMenuContainer
|
||||
|
@ -18,7 +18,6 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Charts;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Multi;
|
||||
using osu.Game.Screens.Select;
|
||||
@ -73,7 +72,7 @@ namespace osu.Game.Screens.Menu
|
||||
private SongTicker songTicker;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(DirectOverlay direct, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics)
|
||||
private void load(DirectOverlay direct, SettingsOverlay settings, RankingsOverlay rankings, OsuConfigManager config, SessionStatics statics)
|
||||
{
|
||||
holdDelay = config.GetBindable<float>(OsuSetting.UIHoldActivationDelay);
|
||||
loginDisplayed = statics.GetBindable<bool>(Static.LoginOverlayDisplayed);
|
||||
@ -101,7 +100,6 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
buttons = new ButtonSystem
|
||||
{
|
||||
OnChart = delegate { this.Push(new ChartListing()); },
|
||||
OnEdit = delegate { this.Push(new Editor()); },
|
||||
OnSolo = onSolo,
|
||||
OnMulti = delegate { this.Push(new Multiplayer()); },
|
||||
@ -136,6 +134,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
buttons.OnSettings = () => settings?.ToggleVisibility();
|
||||
buttons.OnDirect = () => direct?.ToggleVisibility();
|
||||
buttons.OnChart = () => rankings?.ShowSpotlights();
|
||||
|
||||
LoadComponentAsync(background = new BackgroundScreenDefault());
|
||||
preloadSongSelect();
|
||||
|
@ -15,7 +15,6 @@ using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@ -63,15 +62,9 @@ namespace osu.Game.Screens.Play
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
loading.Show();
|
||||
backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
{
|
||||
loading.Hide();
|
||||
backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +131,7 @@ namespace osu.Game.Screens.Play
|
||||
Anchor = Anchor.Centre,
|
||||
FillMode = FillMode.Fill,
|
||||
},
|
||||
loading = new LoadingSpinner { Scale = new Vector2(1.3f) }
|
||||
loading = new LoadingLayer(backgroundSprite)
|
||||
}
|
||||
},
|
||||
new OsuSpriteText
|
||||
|
@ -207,11 +207,27 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
private double floatingAverage;
|
||||
private Container colourBars;
|
||||
|
||||
private const int max_concurrent_judgements = 50;
|
||||
|
||||
public override void OnNewJudgement(JudgementResult judgement)
|
||||
{
|
||||
if (!judgement.IsHit)
|
||||
return;
|
||||
|
||||
if (judgementsContainer.Count > max_concurrent_judgements)
|
||||
{
|
||||
const double quick_fade_time = 100;
|
||||
|
||||
// check with a bit of lenience to avoid precision error in comparison.
|
||||
var old = judgementsContainer.FirstOrDefault(j => j.LifetimeEnd > Clock.CurrentTime + quick_fade_time * 1.1);
|
||||
|
||||
if (old != null)
|
||||
{
|
||||
old.ClearTransforms();
|
||||
old.FadeOut(quick_fade_time).Expire();
|
||||
}
|
||||
}
|
||||
|
||||
judgementsContainer.Add(new JudgementLine
|
||||
{
|
||||
Y = getRelativeJudgementPosition(judgement.TimeOffset),
|
||||
@ -228,7 +244,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
|
||||
private class JudgementLine : CompositeDrawable
|
||||
{
|
||||
private const int judgement_fade_duration = 10000;
|
||||
private const int judgement_fade_duration = 5000;
|
||||
|
||||
public JudgementLine()
|
||||
{
|
||||
@ -255,7 +271,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
Width = 0;
|
||||
|
||||
this.ResizeWidthTo(1, 200, Easing.OutElasticHalf);
|
||||
this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration, Easing.OutQuint).Expire();
|
||||
this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration).Expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.225.0" />
|
||||
<PackageReference Include="Sentry" Version="2.0.3" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
|
@ -74,7 +74,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.225.0" />
|
||||
</ItemGroup>
|
||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
@ -82,7 +82,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.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.225.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user