mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 03:02:54 +08:00
Merge branch 'master' into morth-taiko-changes
This commit is contained in:
commit
d700ae55fb
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.812.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.903.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.907.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
|
||||||
@ -23,19 +22,19 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
{
|
{
|
||||||
Name = @"Fruit Count",
|
Name = @"Fruit Count",
|
||||||
Content = fruits.ToString(),
|
Content = fruits.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Juice Stream Count",
|
Name = @"Juice Stream Count",
|
||||||
Content = juiceStreams.ToString(),
|
Content = juiceStreams.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Banana Shower Count",
|
Name = @"Banana Shower Count",
|
||||||
Content = bananaShowers.ToString(),
|
Content = bananaShowers.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,11 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class CatchRuleset : Ruleset, ILegacyRuleset
|
public class CatchRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
||||||
|
@ -14,11 +14,13 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
[TestCase("basic")]
|
[TestCase("basic")]
|
||||||
|
[TestCase("zero-length-slider")]
|
||||||
public void Test(string name) => base.Test(name);
|
public void Test(string name) => base.Test(name);
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
@ -41,14 +40,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Note Count",
|
Name = @"Note Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
Content = notes.ToString(),
|
Content = notes.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Hold Note Count",
|
Name = @"Hold Note Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
Content = holdnotes.ToString(),
|
Content = holdnotes.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using osu.Game.Rulesets.Mania.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -167,8 +166,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
var positionData = original as IHasPosition;
|
var positionData = original as IHasPosition;
|
||||||
|
|
||||||
for (double time = original.StartTime; !Precision.DefinitelyBigger(time, generator.EndTime); time += generator.SegmentDuration)
|
for (int i = 0; i <= generator.SpanCount; i++)
|
||||||
{
|
{
|
||||||
|
double time = original.StartTime + generator.SegmentDuration * i;
|
||||||
|
|
||||||
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
||||||
computeDensity(time);
|
computeDensity(time);
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
public readonly double EndTime;
|
public readonly double EndTime;
|
||||||
public readonly double SegmentDuration;
|
public readonly double SegmentDuration;
|
||||||
|
public readonly int SpanCount;
|
||||||
private readonly int spanCount;
|
|
||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
|
|
||||||
@ -42,20 +41,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
var distanceData = hitObject as IHasDistance;
|
var distanceData = hitObject as IHasDistance;
|
||||||
var repeatsData = hitObject as IHasRepeats;
|
var repeatsData = hitObject as IHasRepeats;
|
||||||
|
|
||||||
spanCount = repeatsData?.SpanCount() ?? 1;
|
SpanCount = repeatsData?.SpanCount() ?? 1;
|
||||||
|
|
||||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
||||||
|
|
||||||
// The true distance, accounting for any repeats
|
// The true distance, accounting for any repeats
|
||||||
double distance = (distanceData?.Distance ?? 0) * spanCount;
|
double distance = (distanceData?.Distance ?? 0) * SpanCount;
|
||||||
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
||||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
EndTime = hitObject.StartTime + osuDuration;
|
EndTime = hitObject.StartTime + osuDuration;
|
||||||
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
|
SegmentDuration = (EndTime - HitObject.StartTime) / SpanCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Pattern> Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
@ -96,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spanCount > 1)
|
if (SpanCount > 1)
|
||||||
{
|
{
|
||||||
if (SegmentDuration <= 90)
|
if (SegmentDuration <= 90)
|
||||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||||
@ -104,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (SegmentDuration <= 120)
|
if (SegmentDuration <= 120)
|
||||||
{
|
{
|
||||||
convertType |= PatternType.ForceNotStack;
|
convertType |= PatternType.ForceNotStack;
|
||||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
return generateRandomNotes(HitObject.StartTime, SpanCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SegmentDuration <= 160)
|
if (SegmentDuration <= 160)
|
||||||
@ -117,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (duration >= 4000)
|
if (duration >= 4000)
|
||||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
||||||
|
|
||||||
if (SegmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
if (SegmentDuration > 400 && SpanCount < TotalColumns - 1 - RandomStart)
|
||||||
return generateTiledHoldNotes(HitObject.StartTime);
|
return generateTiledHoldNotes(HitObject.StartTime);
|
||||||
|
|
||||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||||
@ -251,7 +250,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
bool increasing = Random.NextDouble() > 0.5;
|
bool increasing = Random.NextDouble() > 0.5;
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, column, startTime, startTime);
|
addToPattern(pattern, column, startTime, startTime);
|
||||||
startTime += SegmentDuration;
|
startTime += SegmentDuration;
|
||||||
@ -302,7 +301,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
|
||||||
@ -393,7 +392,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
int columnRepeat = Math.Min(SpanCount, TotalColumns);
|
||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
@ -447,7 +446,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var rowPattern = new Pattern();
|
var rowPattern = new Pattern();
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
if (!(ignoreHead && startTime == HitObject.StartTime))
|
if (!(ignoreHead && startTime == HitObject.StartTime))
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
@ -14,6 +16,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new HoldNotePlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new HoldNotePlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new NotePlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new NotePlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
@ -35,7 +34,6 @@ using osu.Game.Screens.Ranking.Statistics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class ManiaRuleset : Ruleset, ILegacyRuleset
|
public class ManiaRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"RandomW": 3083084786,
|
||||||
|
"RandomX": 273326509,
|
||||||
|
"RandomY": 273553282,
|
||||||
|
"RandomZ": 2659838971,
|
||||||
|
"StartTime": 4836,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 4836,
|
||||||
|
"EndTime": 4836,
|
||||||
|
"Column": 0
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StackLeniency: 0.7
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
HPDrainRate:1
|
||||||
|
CircleSize:4
|
||||||
|
OverallDifficulty:1
|
||||||
|
ApproachRate:9
|
||||||
|
SliderMultiplier:2.5
|
||||||
|
SliderTickRate:0.5
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
34,431.654676258993,4,1,0,50,1,0
|
||||||
|
4782,-66.6666666666667,4,1,0,20,0,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
15,199,4836,22,0,L,1,46.8750017881394
|
@ -12,6 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
@ -23,19 +22,19 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
{
|
{
|
||||||
Name = @"Circle Count",
|
Name = @"Circle Count",
|
||||||
Content = circles.ToString(),
|
Content = circles.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Slider Count",
|
Name = @"Slider Count",
|
||||||
Content = sliders.ToString(),
|
Content = sliders.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Spinner Count",
|
Name = @"Spinner Count",
|
||||||
Content = spinners.ToString(),
|
Content = spinners.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new HitCirclePlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new HitCirclePlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -38,6 +39,13 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new SpinnerCompositionTool()
|
new SpinnerCompositionTool()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly BindableBool distanceSnapToggle = new BindableBool(true) { Description = "Distance Snap" };
|
||||||
|
|
||||||
|
protected override IEnumerable<BindableBool> Toggles => new[]
|
||||||
|
{
|
||||||
|
distanceSnapToggle
|
||||||
|
};
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
@ -45,6 +53,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid();
|
EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid();
|
||||||
EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid();
|
EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid();
|
||||||
|
distanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
||||||
@ -87,6 +96,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
distanceSnapGridContainer.Clear();
|
distanceSnapGridContainer.Clear();
|
||||||
distanceSnapGridCache.Invalidate();
|
distanceSnapGridCache.Invalidate();
|
||||||
|
distanceSnapGrid = null;
|
||||||
|
|
||||||
|
if (!distanceSnapToggle.Value)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (BlueprintContainer.CurrentTool)
|
switch (BlueprintContainer.CurrentTool)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new SliderPlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new SliderPlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new SpinnerPlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new SpinnerPlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,12 @@ using osu.Game.Scoring;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Statistics;
|
using osu.Game.Rulesets.Osu.Statistics;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class OsuRuleset : Ruleset, ILegacyRuleset
|
public class OsuRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
||||||
|
@ -18,6 +18,10 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
||||||
|
|
||||||
|
protected new float CalculatedBorderPortion
|
||||||
|
// Roughly matches osu!stable's slider border portions.
|
||||||
|
=> base.CalculatedBorderPortion * 0.77f;
|
||||||
|
|
||||||
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
||||||
|
|
||||||
protected override Color4 ColourAt(float position)
|
protected override Color4 ColourAt(float position)
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Taiko.Tests
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
@ -22,20 +21,20 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Hit Count",
|
Name = @"Hit Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles),
|
||||||
Content = hits.ToString(),
|
Content = hits.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Drumroll Count",
|
Name = @"Drumroll Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||||
Content = drumrolls.ToString(),
|
Content = drumrolls.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
},
|
},
|
||||||
new BeatmapStatistic
|
new BeatmapStatistic
|
||||||
{
|
{
|
||||||
Name = @"Swell Count",
|
Name = @"Swell Count",
|
||||||
|
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners),
|
||||||
Content = swells.ToString(),
|
Content = swells.ToString(),
|
||||||
Icon = FontAwesome.Regular.Circle
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new DrumRollPlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new DrumRollPlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new HitPlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new HitPlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||||
@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners);
|
||||||
|
|
||||||
public override PlacementBlueprint CreatePlacementBlueprint() => new SwellPlacementBlueprint();
|
public override PlacementBlueprint CreatePlacementBlueprint() => new SwellPlacementBlueprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ using osu.Game.Rulesets.Taiko.Scoring;
|
|||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Taiko.Edit;
|
using osu.Game.Rulesets.Taiko.Edit;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
@ -32,7 +31,6 @@ using osu.Game.Skinning;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class TaikoRuleset : Ruleset, ILegacyRuleset
|
public class TaikoRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
||||||
|
@ -10,6 +10,7 @@ using System.Text;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
@ -19,6 +20,7 @@ using osu.Game.Rulesets.Catch;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Taiko;
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.Formats
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
@ -26,18 +28,33 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LegacyBeatmapEncoderTest
|
public class LegacyBeatmapEncoderTest
|
||||||
{
|
{
|
||||||
private static IEnumerable<string> allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
private static readonly DllResourceStore beatmaps_resource_store = TestResources.GetStore();
|
||||||
|
|
||||||
|
private static IEnumerable<string> allBeatmaps = beatmaps_resource_store.GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
||||||
|
|
||||||
[TestCaseSource(nameof(allBeatmaps))]
|
[TestCaseSource(nameof(allBeatmaps))]
|
||||||
public void TestEncodeDecodeStability(string name)
|
public void TestEncodeDecodeStability(string name)
|
||||||
{
|
{
|
||||||
var decoded = decodeFromLegacy(TestResources.GetStore().GetStream(name));
|
var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name);
|
||||||
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded));
|
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name);
|
||||||
|
|
||||||
sort(decoded);
|
sort(decoded.beatmap);
|
||||||
sort(decodedAfterEncode);
|
sort(decodedAfterEncode.beatmap);
|
||||||
|
|
||||||
Assert.That(decodedAfterEncode.Serialize(), Is.EqualTo(decoded.Serialize()));
|
Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(decoded.beatmap.Serialize()));
|
||||||
|
Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b)
|
||||||
|
{
|
||||||
|
// equal to null, no need to SequenceEqual
|
||||||
|
if (a.ComboColours == null && b.ComboColours == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (a.ComboColours == null || b.ComboColours == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return a.ComboColours.SequenceEqual(b.ComboColours);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sort(IBeatmap beatmap)
|
private void sort(IBeatmap beatmap)
|
||||||
@ -50,18 +67,31 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap decodeFromLegacy(Stream stream)
|
private (IBeatmap beatmap, TestLegacySkin beatmapSkin) decodeFromLegacy(Stream stream, string name)
|
||||||
{
|
{
|
||||||
using (var reader = new LineBufferedReader(stream))
|
using (var reader = new LineBufferedReader(stream))
|
||||||
return convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader));
|
{
|
||||||
|
var beatmap = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader);
|
||||||
|
var beatmapSkin = new TestLegacySkin(beatmaps_resource_store, name);
|
||||||
|
return (convert(beatmap), beatmapSkin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream encodeToLegacy(IBeatmap beatmap)
|
private class TestLegacySkin : LegacySkin
|
||||||
{
|
{
|
||||||
|
public TestLegacySkin(IResourceStore<byte[]> storage, string fileName)
|
||||||
|
: base(new SkinInfo { Name = "Test Skin", Creator = "Craftplacer" }, storage, null, fileName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap)
|
||||||
|
{
|
||||||
|
var (beatmap, beatmapSkin) = fullBeatmap;
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
|
|
||||||
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
new LegacyBeatmapEncoder(beatmap).Encode(writer);
|
new LegacyBeatmapEncoder(beatmap, beatmapSkin).Encode(writer);
|
||||||
|
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
|
@ -15,8 +15,10 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
using osu.Game.Users;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using SharpCompress.Archives.Zip;
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
@ -32,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportWhenClosed()
|
public async Task TestImportWhenClosed()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenClosed)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -49,7 +51,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDelete()
|
public async Task TestImportThenDelete()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDelete)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -70,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenImport()
|
public async Task TestImportThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -96,7 +98,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithReZip()
|
public async Task TestImportThenImportWithReZip()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithReZip)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -154,7 +156,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithChangedFile()
|
public async Task TestImportThenImportWithChangedFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithChangedFile)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -205,7 +207,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithDifferentFilename()
|
public async Task TestImportThenImportWithDifferentFilename()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithDifferentFilename)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -257,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportCorruptThenImport()
|
public async Task TestImportCorruptThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportCorruptThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -299,7 +301,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestRollbackOnFailure()
|
public async Task TestRollbackOnFailure()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestRollbackOnFailure)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -376,7 +378,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDeleteThenImport()
|
public async Task TestImportThenDeleteThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDeleteThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -404,7 +406,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"{nameof(TestImportThenDeleteThenImportWithOnlineIDMismatch)}-{set}"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(set.ToString()))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -438,7 +440,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportWithDuplicateBeatmapIDs()
|
public async Task TestImportWithDuplicateBeatmapIDs()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateBeatmapIDs)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -524,7 +526,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWhenFileOpen()
|
public async Task TestImportWhenFileOpen()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenFileOpen)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -546,7 +548,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDuplicateHashes()
|
public async Task TestImportWithDuplicateHashes()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateHashes)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -588,7 +590,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportNestedStructure()
|
public async Task TestImportNestedStructure()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -633,7 +635,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithIgnoredDirectoryInArchive()
|
public async Task TestImportWithIgnoredDirectoryInArchive()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithIgnoredDirectoryInArchive)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -687,7 +689,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapInfo()
|
public async Task TestUpdateBeatmapInfo()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapInfo)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -717,7 +719,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapFile()
|
public async Task TestUpdateBeatmapFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapFile)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -756,6 +758,63 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCreateNewEmptyBeatmap()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
manager.Save(working.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
|
||||||
|
|
||||||
|
// Check that the new file is referenced correctly by attempting a retrieval
|
||||||
|
Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
|
||||||
|
Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCreateNewBeatmapWithObject()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
((Beatmap)working.Beatmap).HitObjects.Add(new HitCircle { StartTime = 5000 });
|
||||||
|
|
||||||
|
manager.Save(working.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
|
||||||
|
|
||||||
|
// Check that the new file is referenced correctly by attempting a retrieval
|
||||||
|
Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
|
||||||
|
Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(updatedBeatmap.HitObjects[0].StartTime, Is.EqualTo(5000));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
||||||
{
|
{
|
||||||
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||||
|
@ -351,7 +351,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
using (var encoded = new MemoryStream())
|
using (var encoded = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var sw = new StreamWriter(encoded))
|
using (var sw = new StreamWriter(encoded))
|
||||||
new LegacyBeatmapEncoder(beatmap).Encode(sw);
|
new LegacyBeatmapEncoder(beatmap, null).Encode(sw);
|
||||||
|
|
||||||
return encoded.ToArray();
|
return encoded.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestBasicImport()
|
public async Task TestBasicImport()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestBasicImport"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -66,7 +66,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportMods()
|
public async Task TestImportMods()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportMods"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportStatistics()
|
public async Task TestImportStatistics()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportStatistics"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDeletedBeatmapSet()
|
public async Task TestImportWithDeletedBeatmapSet()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWithDeletedBeatmapSet"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -159,7 +159,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestOnlineScoreIsAvailableLocally()
|
public async Task TestOnlineScoreIsAvailableLocally()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestOnlineScoreIsAvailableLocally"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
protected new TestEditor Editor => (TestEditor)base.Editor;
|
||||||
|
|
||||||
public override void SetUpSteps()
|
public override void SetUpSteps()
|
||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
@ -35,6 +37,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
addUndoSteps();
|
addUndoSteps();
|
||||||
|
|
||||||
AddAssert("no change occurred", () => hitObjectCount == editorBeatmap.HitObjects.Count);
|
AddAssert("no change occurred", () => hitObjectCount == editorBeatmap.HitObjects.Count);
|
||||||
|
AddAssert("no unsaved changes", () => !Editor.HasUnsavedChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -47,6 +50,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
addRedoSteps();
|
addRedoSteps();
|
||||||
|
|
||||||
AddAssert("no change occurred", () => hitObjectCount == editorBeatmap.HitObjects.Count);
|
AddAssert("no change occurred", () => hitObjectCount == editorBeatmap.HitObjects.Count);
|
||||||
|
AddAssert("no unsaved changes", () => !Editor.HasUnsavedChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -64,9 +68,11 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("add hitobject", () => editorBeatmap.Add(expectedObject = new HitCircle { StartTime = 1000 }));
|
AddStep("add hitobject", () => editorBeatmap.Add(expectedObject = new HitCircle { StartTime = 1000 }));
|
||||||
AddAssert("hitobject added", () => addedObject == expectedObject);
|
AddAssert("hitobject added", () => addedObject == expectedObject);
|
||||||
|
AddAssert("unsaved changes", () => Editor.HasUnsavedChanges);
|
||||||
|
|
||||||
addUndoSteps();
|
addUndoSteps();
|
||||||
AddAssert("hitobject removed", () => removedObject == expectedObject);
|
AddAssert("hitobject removed", () => removedObject == expectedObject);
|
||||||
|
AddAssert("no unsaved changes", () => !Editor.HasUnsavedChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -94,6 +100,17 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
addRedoSteps();
|
addRedoSteps();
|
||||||
AddAssert("hitobject added", () => addedObject.StartTime == expectedObject.StartTime); // Can't compare via equality (new hitobject instance)
|
AddAssert("hitobject added", () => addedObject.StartTime == expectedObject.StartTime); // Can't compare via equality (new hitobject instance)
|
||||||
AddAssert("no hitobject removed", () => removedObject == null);
|
AddAssert("no hitobject removed", () => removedObject == null);
|
||||||
|
AddAssert("unsaved changes", () => Editor.HasUnsavedChanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddObjectThenSaveHasNoUnsavedChanges()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => editorBeatmap.Add(new HitCircle { StartTime = 1000 }));
|
||||||
|
|
||||||
|
AddAssert("unsaved changes", () => Editor.HasUnsavedChanges);
|
||||||
|
AddStep("save changes", () => Editor.Save());
|
||||||
|
AddAssert("no unsaved changes", () => !Editor.HasUnsavedChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -120,6 +137,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
addUndoSteps();
|
addUndoSteps();
|
||||||
AddAssert("hitobject added", () => addedObject.StartTime == expectedObject.StartTime); // Can't compare via equality (new hitobject instance)
|
AddAssert("hitobject added", () => addedObject.StartTime == expectedObject.StartTime); // Can't compare via equality (new hitobject instance)
|
||||||
AddAssert("no hitobject removed", () => removedObject == null);
|
AddAssert("no hitobject removed", () => removedObject == null);
|
||||||
|
AddAssert("unsaved changes", () => Editor.HasUnsavedChanges); // 2 steps performed, 1 undone
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -148,19 +166,24 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
addRedoSteps();
|
addRedoSteps();
|
||||||
AddAssert("hitobject removed", () => removedObject.StartTime == expectedObject.StartTime); // Can't compare via equality (new hitobject instance after undo)
|
AddAssert("hitobject removed", () => removedObject.StartTime == expectedObject.StartTime); // Can't compare via equality (new hitobject instance after undo)
|
||||||
AddAssert("no hitobject added", () => addedObject == null);
|
AddAssert("no hitobject added", () => addedObject == null);
|
||||||
|
AddAssert("no changes", () => !Editor.HasUnsavedChanges); // end result is empty beatmap, matching original state
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addUndoSteps() => AddStep("undo", () => ((TestEditor)Editor).Undo());
|
private void addUndoSteps() => AddStep("undo", () => Editor.Undo());
|
||||||
|
|
||||||
private void addRedoSteps() => AddStep("redo", () => ((TestEditor)Editor).Redo());
|
private void addRedoSteps() => AddStep("redo", () => Editor.Redo());
|
||||||
|
|
||||||
protected override Editor CreateEditor() => new TestEditor();
|
protected override Editor CreateEditor() => new TestEditor();
|
||||||
|
|
||||||
private class TestEditor : Editor
|
protected class TestEditor : Editor
|
||||||
{
|
{
|
||||||
public new void Undo() => base.Undo();
|
public new void Undo() => base.Undo();
|
||||||
|
|
||||||
public new void Redo() => base.Redo();
|
public new void Redo() => base.Redo();
|
||||||
|
|
||||||
|
public new void Save() => base.Save();
|
||||||
|
|
||||||
|
public new bool HasUnsavedChanges => base.HasUnsavedChanges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Screens.Edit.Components.RadioButtons;
|
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Editing
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
@ -22,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
new RadioButton("Item 1", () => { }),
|
new RadioButton("Item 1", () => { }),
|
||||||
new RadioButton("Item 2", () => { }),
|
new RadioButton("Item 2", () => { }),
|
||||||
new RadioButton("Item 3", () => { }),
|
new RadioButton("Item 3", () => { }, () => new SpriteIcon { Icon = FontAwesome.Regular.Angry }),
|
||||||
new RadioButton("Item 4", () => { }),
|
new RadioButton("Item 4", () => { }),
|
||||||
new RadioButton("Item 5", () => { })
|
new RadioButton("Item 5", () => { })
|
||||||
}
|
}
|
||||||
|
32
osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
Normal file
32
osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.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 NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneSetupScreen : EditorClockTestScene
|
||||||
|
{
|
||||||
|
[Cached(typeof(EditorBeatmap))]
|
||||||
|
[Cached(typeof(IBeatSnapProvider))]
|
||||||
|
private readonly EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
|
public TestSceneSetupScreen()
|
||||||
|
{
|
||||||
|
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
||||||
|
Child = new SetupScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs
Normal file
54
osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public class TestSceneOverlayActivation : OsuPlayerTestScene
|
||||||
|
{
|
||||||
|
protected new OverlayTestPlayer Player => base.Player as OverlayTestPlayer;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivation()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationPaused()
|
||||||
|
{
|
||||||
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("pause gameplay", () => Player.Pause());
|
||||||
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationReplayLoaded()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
||||||
|
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationBreaks()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
||||||
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
||||||
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
||||||
|
|
||||||
|
protected class OverlayTestPlayer : TestPlayer
|
||||||
|
{
|
||||||
|
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,7 +48,10 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private class ExampleContainer : PlayerSettingsGroup
|
private class ExampleContainer : PlayerSettingsGroup
|
||||||
{
|
{
|
||||||
protected override string Title => @"example";
|
public ExampleContainer()
|
||||||
|
: base("example")
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
83
osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
Normal file
83
osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
using osu.Game.Tests.Visual.Navigation;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
|
{
|
||||||
|
public class TestSceneMusicActionHandling : OsuGameTestScene
|
||||||
|
{
|
||||||
|
private GlobalActionContainer globalActionContainer => Game.ChildrenOfType<GlobalActionContainer>().First();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMusicPlayAction()
|
||||||
|
{
|
||||||
|
AddStep("ensure playing something", () => Game.MusicController.EnsurePlayingSomething());
|
||||||
|
AddStep("toggle playback", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPlay));
|
||||||
|
AddAssert("music paused", () => !Game.MusicController.IsPlaying && Game.MusicController.IsUserPaused);
|
||||||
|
AddStep("toggle playback", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPlay));
|
||||||
|
AddAssert("music resumed", () => Game.MusicController.IsPlaying && !Game.MusicController.IsUserPaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMusicNavigationActions()
|
||||||
|
{
|
||||||
|
int importId = 0;
|
||||||
|
Queue<(WorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
|
||||||
|
|
||||||
|
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
|
||||||
|
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
Beatmaps = new List<BeatmapInfo>
|
||||||
|
{
|
||||||
|
new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = $"a test map {importId++}",
|
||||||
|
Title = "title",
|
||||||
|
}
|
||||||
|
}).Wait(), 5);
|
||||||
|
|
||||||
|
AddStep("import beatmap with track", () =>
|
||||||
|
{
|
||||||
|
var setWithTrack = Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result;
|
||||||
|
Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(setWithTrack.Beatmaps.First());
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("bind to track change", () =>
|
||||||
|
{
|
||||||
|
trackChangeQueue = new Queue<(WorkingBeatmap, TrackChangeDirection)>();
|
||||||
|
Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection));
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("seek track to 6 second", () => Game.MusicController.SeekTo(6000));
|
||||||
|
AddUntilStep("wait for current time to update", () => Game.MusicController.CurrentTrack.CurrentTime > 5000);
|
||||||
|
|
||||||
|
AddStep("press previous", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPrev));
|
||||||
|
AddAssert("no track change", () => trackChangeQueue.Count == 0);
|
||||||
|
AddUntilStep("track restarted", () => Game.MusicController.CurrentTrack.CurrentTime < 5000);
|
||||||
|
|
||||||
|
AddStep("press previous", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPrev));
|
||||||
|
AddAssert("track changed to previous", () =>
|
||||||
|
trackChangeQueue.Count == 1 &&
|
||||||
|
trackChangeQueue.Dequeue().changeDirection == TrackChangeDirection.Prev);
|
||||||
|
|
||||||
|
AddStep("press next", () => globalActionContainer.TriggerPressed(GlobalAction.MusicNext));
|
||||||
|
AddAssert("track changed to next", () =>
|
||||||
|
trackChangeQueue.Count == 1 &&
|
||||||
|
trackChangeQueue.Dequeue().changeDirection == TrackChangeDirection.Next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -162,6 +162,28 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddAssert("item 2 has rate 2", () => Precision.AlmostEquals(2, ((OsuModDoubleTime)Room.Playlist.Last().RequiredMods[0]).SpeedChange.Value));
|
AddAssert("item 2 has rate 2", () => Precision.AlmostEquals(2, ((OsuModDoubleTime)Room.Playlist.Last().RequiredMods[0]).SpeedChange.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests that the global mod instances are not retained by the rooms, as global mod instances are retained and re-used by the mod select overlay.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestGlobalModInstancesNotRetained()
|
||||||
|
{
|
||||||
|
OsuModDoubleTime mod = null;
|
||||||
|
|
||||||
|
AddStep("set dt mod and store", () =>
|
||||||
|
{
|
||||||
|
SelectedMods.Value = new[] { new OsuModDoubleTime() };
|
||||||
|
|
||||||
|
// Mod select overlay replaces our mod.
|
||||||
|
mod = (OsuModDoubleTime)SelectedMods.Value[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||||
|
|
||||||
|
AddStep("change stored mod rate", () => mod.SpeedChange.Value = 2);
|
||||||
|
AddAssert("item has rate 1.5", () => Precision.AlmostEquals(1.5, ((OsuModDoubleTime)Room.Playlist.First().RequiredMods[0]).SpeedChange.Value));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestMatchSongSelect : MatchSongSelect
|
private class TestMatchSongSelect : MatchSongSelect
|
||||||
{
|
{
|
||||||
public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails;
|
public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails;
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneFullscreenOverlay : OsuTestScene
|
public class TestSceneFullscreenOverlay : OsuTestScene
|
||||||
{
|
{
|
||||||
private FullscreenOverlay overlay;
|
private FullscreenOverlay<OverlayHeader> overlay;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
@ -38,10 +38,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert("fire count 3", () => fireCount == 3);
|
AddAssert("fire count 3", () => fireCount == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestFullscreenOverlay : FullscreenOverlay
|
private class TestFullscreenOverlay : FullscreenOverlay<OverlayHeader>
|
||||||
{
|
{
|
||||||
public TestFullscreenOverlay()
|
public TestFullscreenOverlay()
|
||||||
: base(OverlayColourScheme.Pink)
|
: base(OverlayColourScheme.Pink, null)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -5,9 +5,9 @@ using System;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
using osu.Game.Online.Leaderboards;
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Select.Leaderboards;
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
@ -53,53 +53,46 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
private void showPersonalBestWithNullPosition()
|
private void showPersonalBestWithNullPosition()
|
||||||
{
|
{
|
||||||
leaderboard.TopScore = new APILegacyUserTopScoreInfo
|
leaderboard.TopScore = new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = null,
|
Rank = ScoreRank.XH,
|
||||||
Score = new APILegacyScoreInfo
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Id = 6602580,
|
||||||
Accuracy = 1,
|
Username = @"waaiiru",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
FullName = @"Spain",
|
||||||
Username = @"waaiiru",
|
FlagName = @"ES",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Spain",
|
|
||||||
FlagName = @"ES",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPersonalBest()
|
private void showPersonalBest()
|
||||||
{
|
{
|
||||||
leaderboard.TopScore = new APILegacyUserTopScoreInfo
|
leaderboard.TopScore = new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 999,
|
Position = 999,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.XH,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Id = 6602580,
|
||||||
Accuracy = 1,
|
Username = @"waaiiru",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
FullName = @"Spain",
|
||||||
Username = @"waaiiru",
|
FlagName = @"ES",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Spain",
|
|
||||||
FlagName = @"ES",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Screens.Select.Leaderboards;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.SongSelect
|
namespace osu.Game.Tests.Visual.SongSelect
|
||||||
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
public TestSceneUserTopScoreContainer()
|
public TestSceneUserTopScoreContainer()
|
||||||
{
|
{
|
||||||
UserTopScoreContainer topScoreContainer;
|
UserTopScoreContainer<ScoreInfo> topScoreContainer;
|
||||||
|
|
||||||
Add(dialogOverlay = new DialogOverlay
|
Add(dialogOverlay = new DialogOverlay
|
||||||
{
|
{
|
||||||
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.DarkGreen,
|
Colour = Color4.DarkGreen,
|
||||||
},
|
},
|
||||||
topScoreContainer = new UserTopScoreContainer
|
topScoreContainer = new UserTopScoreContainer<ScoreInfo>(s => new LeaderboardScore(s, s.Position, false))
|
||||||
{
|
{
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
@ -52,69 +52,60 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
var scores = new[]
|
var scores = new[]
|
||||||
{
|
{
|
||||||
new APILegacyUserTopScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 999,
|
Position = 999,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.XH,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Id = 6602580,
|
||||||
Accuracy = 1,
|
Username = @"waaiiru",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
FullName = @"Spain",
|
||||||
Username = @"waaiiru",
|
FlagName = @"ES",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Spain",
|
|
||||||
FlagName = @"ES",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
new APILegacyUserTopScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 110000,
|
Position = 110000,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.X,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.X,
|
Id = 4608074,
|
||||||
Accuracy = 1,
|
Username = @"Skycries",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 4608074,
|
FullName = @"Brazil",
|
||||||
Username = @"Skycries",
|
FlagName = @"BR",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Brazil",
|
|
||||||
FlagName = @"BR",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
new APILegacyUserTopScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 22333,
|
Position = 22333,
|
||||||
Score = new APILegacyScoreInfo
|
Rank = ScoreRank.S,
|
||||||
|
Accuracy = 1,
|
||||||
|
MaxCombo = 244,
|
||||||
|
TotalScore = 1707827,
|
||||||
|
User = new User
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.S,
|
Id = 1541390,
|
||||||
Accuracy = 1,
|
Username = @"Toukai",
|
||||||
MaxCombo = 244,
|
Country = new Country
|
||||||
TotalScore = 1707827,
|
|
||||||
User = new User
|
|
||||||
{
|
{
|
||||||
Id = 1541390,
|
FullName = @"Canada",
|
||||||
Username = @"Toukai",
|
FlagName = @"CA",
|
||||||
Country = new Country
|
|
||||||
{
|
|
||||||
FullName = @"Canada",
|
|
||||||
FlagName = @"CA",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Tests.Resources;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
@ -24,14 +17,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private NowPlayingOverlay nowPlayingOverlay;
|
private NowPlayingOverlay nowPlayingOverlay;
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio, GameHost host)
|
private void load()
|
||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
|
||||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
|
|
||||||
|
|
||||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
nowPlayingOverlay = new NowPlayingOverlay
|
nowPlayingOverlay = new NowPlayingOverlay
|
||||||
@ -51,49 +39,5 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
|
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
|
||||||
AddStep(@"hide", () => nowPlayingOverlay.Hide());
|
AddStep(@"hide", () => nowPlayingOverlay.Hide());
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapManager manager { get; set; }
|
|
||||||
|
|
||||||
private int importId;
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestPrevTrackBehavior()
|
|
||||||
{
|
|
||||||
// ensure we have at least two beatmaps available.
|
|
||||||
AddRepeatStep("import beatmap", () => manager.Import(new BeatmapSetInfo
|
|
||||||
{
|
|
||||||
Beatmaps = new List<BeatmapInfo>
|
|
||||||
{
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
|
||||||
Artist = $"a test map {importId++}",
|
|
||||||
Title = "title",
|
|
||||||
}
|
|
||||||
}).Wait(), 5);
|
|
||||||
|
|
||||||
WorkingBeatmap currentBeatmap = null;
|
|
||||||
|
|
||||||
AddStep("import beatmap with track", () =>
|
|
||||||
{
|
|
||||||
var setWithTrack = manager.Import(TestResources.GetTestBeatmapForImport()).Result;
|
|
||||||
Beatmap.Value = currentBeatmap = manager.GetWorkingBeatmap(setWithTrack.Beatmaps.First());
|
|
||||||
});
|
|
||||||
|
|
||||||
AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000));
|
|
||||||
AddUntilStep(@"Wait for current time to update", () => musicController.CurrentTrack.CurrentTime > 5000);
|
|
||||||
|
|
||||||
AddStep(@"Set previous", () => musicController.PreviousTrack());
|
|
||||||
|
|
||||||
AddAssert(@"Check beatmap didn't change", () => currentBeatmap == Beatmap.Value);
|
|
||||||
AddUntilStep("Wait for current time to update", () => musicController.CurrentTrack.CurrentTime < 5000);
|
|
||||||
|
|
||||||
AddStep(@"Set previous", () => musicController.PreviousTrack());
|
|
||||||
AddAssert(@"Check beatmap did change", () => currentBeatmap != Beatmap.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
{
|
{
|
||||||
private const int padding = 10;
|
private const int padding = 10;
|
||||||
|
|
||||||
protected override string Title => @"ladder";
|
|
||||||
|
|
||||||
private SettingsDropdown<TournamentRound> roundDropdown;
|
private SettingsDropdown<TournamentRound> roundDropdown;
|
||||||
private PlayerCheckbox losersCheckbox;
|
private PlayerCheckbox losersCheckbox;
|
||||||
private DateTextBox dateTimeBox;
|
private DateTextBox dateTimeBox;
|
||||||
@ -34,6 +32,11 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private LadderInfo ladderInfo { get; set; }
|
private LadderInfo ladderInfo { get; set; }
|
||||||
|
|
||||||
|
public LadderEditorSettings()
|
||||||
|
: base("ladder")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -14,6 +15,7 @@ using osu.Game.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,8 @@ using osu.Game.Online.API;
|
|||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
|
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -64,12 +66,14 @@ namespace osu.Game.Beatmaps
|
|||||||
private readonly RulesetStore rulesets;
|
private readonly RulesetStore rulesets;
|
||||||
private readonly BeatmapStore beatmaps;
|
private readonly BeatmapStore beatmaps;
|
||||||
private readonly AudioManager audioManager;
|
private readonly AudioManager audioManager;
|
||||||
private readonly BeatmapOnlineLookupQueue onlineLookupQueue;
|
|
||||||
private readonly TextureStore textureStore;
|
private readonly TextureStore textureStore;
|
||||||
private readonly ITrackStore trackStore;
|
private readonly ITrackStore trackStore;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
private readonly BeatmapOnlineLookupQueue onlineLookupQueue;
|
||||||
|
|
||||||
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host = null,
|
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host = null,
|
||||||
WorkingBeatmap defaultBeatmap = null)
|
WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false)
|
||||||
: base(storage, contextFactory, api, new BeatmapStore(contextFactory), host)
|
: base(storage, contextFactory, api, new BeatmapStore(contextFactory), host)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
@ -83,7 +87,8 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmaps.ItemRemoved += removeWorkingCache;
|
beatmaps.ItemRemoved += removeWorkingCache;
|
||||||
beatmaps.ItemUpdated += removeWorkingCache;
|
beatmaps.ItemUpdated += removeWorkingCache;
|
||||||
|
|
||||||
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
|
if (performOnlineLookups)
|
||||||
|
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
|
||||||
|
|
||||||
textureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store));
|
textureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store));
|
||||||
trackStore = audioManager.GetTrackStore(Files.Store);
|
trackStore = audioManager.GetTrackStore(Files.Store);
|
||||||
@ -94,6 +99,34 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz";
|
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz";
|
||||||
|
|
||||||
|
public WorkingBeatmap CreateNew(RulesetInfo ruleset, User user)
|
||||||
|
{
|
||||||
|
var metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = "artist",
|
||||||
|
Title = "title",
|
||||||
|
Author = user,
|
||||||
|
};
|
||||||
|
|
||||||
|
var set = new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
Metadata = metadata,
|
||||||
|
Beatmaps = new List<BeatmapInfo>
|
||||||
|
{
|
||||||
|
new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty(),
|
||||||
|
Ruleset = ruleset,
|
||||||
|
Metadata = metadata,
|
||||||
|
Version = "difficulty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var working = Import(set).Result;
|
||||||
|
return GetWorkingBeatmap(working.Beatmaps.First());
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default)
|
protected override async Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (archive != null)
|
if (archive != null)
|
||||||
@ -112,7 +145,8 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
bool hadOnlineBeatmapIDs = beatmapSet.Beatmaps.Any(b => b.OnlineBeatmapID > 0);
|
bool hadOnlineBeatmapIDs = beatmapSet.Beatmaps.Any(b => b.OnlineBeatmapID > 0);
|
||||||
|
|
||||||
await onlineLookupQueue.UpdateAsync(beatmapSet, cancellationToken);
|
if (onlineLookupQueue != null)
|
||||||
|
await onlineLookupQueue.UpdateAsync(beatmapSet, cancellationToken);
|
||||||
|
|
||||||
// ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID.
|
// ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID.
|
||||||
if (hadOnlineBeatmapIDs && !beatmapSet.Beatmaps.Any(b => b.OnlineBeatmapID > 0))
|
if (hadOnlineBeatmapIDs && !beatmapSet.Beatmaps.Any(b => b.OnlineBeatmapID > 0))
|
||||||
@ -198,24 +232,35 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
||||||
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
||||||
public void Save(BeatmapInfo info, IBeatmap beatmapContent)
|
/// <param name="beatmapSkin">The beatmap <see cref="ISkin"/> content to write, null if to be omitted.</param>
|
||||||
|
public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null)
|
||||||
{
|
{
|
||||||
var setInfo = QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == info.ID));
|
var setInfo = info.BeatmapSet;
|
||||||
|
|
||||||
using (var stream = new MemoryStream())
|
using (var stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
new LegacyBeatmapEncoder(beatmapContent).Encode(sw);
|
new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw);
|
||||||
|
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
using (ContextFactory.GetForWrite())
|
using (ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
var beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == info.ID);
|
var beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == info.ID);
|
||||||
|
var metadata = beatmapInfo.Metadata ?? setInfo.Metadata;
|
||||||
|
|
||||||
|
// grab the original file (or create a new one if not found).
|
||||||
|
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
|
||||||
|
|
||||||
|
// metadata may have changed; update the path with the standard format.
|
||||||
|
beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu";
|
||||||
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
||||||
|
|
||||||
|
// update existing or populate new file's filename.
|
||||||
|
fileInfo.Filename = beatmapInfo.Path;
|
||||||
|
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
UpdateFile(setInfo, setInfo.Files.Single(f => string.Equals(f.Filename, info.Path, StringComparison.OrdinalIgnoreCase)), stream);
|
UpdateFile(setInfo, fileInfo, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override IBeatmap GetBeatmap()
|
protected override IBeatmap GetBeatmap()
|
||||||
{
|
{
|
||||||
|
if (BeatmapInfo.Path == null)
|
||||||
|
return new Beatmap { BeatmapInfo = BeatmapInfo };
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
||||||
@ -67,6 +70,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Track GetBeatmapTrack()
|
protected override Track GetBeatmapTrack()
|
||||||
{
|
{
|
||||||
|
if (Metadata?.AudioFile == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return trackStore.Get(getPathForFile(Metadata.AudioFile));
|
return trackStore.Get(getPathForFile(Metadata.AudioFile));
|
||||||
@ -80,6 +86,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Waveform GetWaveform()
|
protected override Waveform GetWaveform()
|
||||||
{
|
{
|
||||||
|
if (Metadata?.AudioFile == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
||||||
|
@ -6,11 +6,13 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class BeatmapMetadata : IEquatable<BeatmapMetadata>, IHasPrimaryKey
|
public class BeatmapMetadata : IEquatable<BeatmapMetadata>, IHasPrimaryKey
|
||||||
{
|
{
|
||||||
|
@ -5,10 +5,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete, IEquatable<BeatmapSetInfo>
|
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete, IEquatable<BeatmapSetInfo>
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
@ -1,14 +1,31 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public class BeatmapStatistic
|
public class BeatmapStatistic
|
||||||
{
|
{
|
||||||
public IconUsage Icon;
|
[Obsolete("Use CreateIcon instead")] // can be removed 20210203
|
||||||
|
public IconUsage Icon = FontAwesome.Regular.QuestionCircle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A function to create the icon for display purposes. Use default icons available via <see cref="BeatmapStatisticIcon"/> whenever possible for conformity.
|
||||||
|
/// </summary>
|
||||||
|
public Func<Drawable> CreateIcon;
|
||||||
|
|
||||||
public string Content;
|
public string Content;
|
||||||
public string Name;
|
public string Name;
|
||||||
|
|
||||||
|
public BeatmapStatistic()
|
||||||
|
{
|
||||||
|
#pragma warning disable 618
|
||||||
|
CreateIcon = () => new SpriteIcon { Icon = Icon, Scale = new Vector2(0.7f) };
|
||||||
|
#pragma warning restore 618
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
osu.Game/Beatmaps/BeatmapStatisticIcon.cs
Normal file
43
osu.Game/Beatmaps/BeatmapStatisticIcon.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A default implementation of an icon used to represent beatmap statistics.
|
||||||
|
/// </summary>
|
||||||
|
public class BeatmapStatisticIcon : Sprite
|
||||||
|
{
|
||||||
|
private readonly BeatmapStatisticsIconType iconType;
|
||||||
|
|
||||||
|
public BeatmapStatisticIcon(BeatmapStatisticsIconType iconType)
|
||||||
|
{
|
||||||
|
this.iconType = iconType;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures)
|
||||||
|
{
|
||||||
|
Texture = textures.Get($"Icons/BeatmapDetails/{iconType.ToString().Kebaberize()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BeatmapStatisticsIconType
|
||||||
|
{
|
||||||
|
Accuracy,
|
||||||
|
ApproachRate,
|
||||||
|
Bpm,
|
||||||
|
Circles,
|
||||||
|
HpDrain,
|
||||||
|
Length,
|
||||||
|
OverallDifficulty,
|
||||||
|
Size,
|
||||||
|
Sliders,
|
||||||
|
Spinners,
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
public interface IHasCustomColours
|
public interface IHasCustomColours
|
||||||
{
|
{
|
||||||
Dictionary<string, Color4> CustomColours { get; set; }
|
Dictionary<string, Color4> CustomColours { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,16 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
{
|
{
|
||||||
@ -23,9 +26,18 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private readonly IBeatmap beatmap;
|
private readonly IBeatmap beatmap;
|
||||||
|
|
||||||
public LegacyBeatmapEncoder(IBeatmap beatmap)
|
[CanBeNull]
|
||||||
|
private readonly ISkin skin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="LegacyBeatmapEncoder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to encode.</param>
|
||||||
|
/// <param name="skin">The beatmap's skin, used for encoding combo colours.</param>
|
||||||
|
public LegacyBeatmapEncoder(IBeatmap beatmap, [CanBeNull] ISkin skin)
|
||||||
{
|
{
|
||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
|
this.skin = skin;
|
||||||
|
|
||||||
if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3)
|
if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3)
|
||||||
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
|
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
|
||||||
@ -53,6 +65,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
handleControlPoints(writer);
|
handleControlPoints(writer);
|
||||||
|
|
||||||
|
writer.WriteLine();
|
||||||
|
handleColours(writer);
|
||||||
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
handleHitObjects(writer);
|
handleHitObjects(writer);
|
||||||
}
|
}
|
||||||
@ -196,6 +211,28 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleColours(TextWriter writer)
|
||||||
|
{
|
||||||
|
var colours = skin?.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
|
||||||
|
|
||||||
|
if (colours == null || colours.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
writer.WriteLine("[Colours]");
|
||||||
|
|
||||||
|
for (var i = 0; i < colours.Count; i++)
|
||||||
|
{
|
||||||
|
var comboColour = colours[i];
|
||||||
|
|
||||||
|
writer.Write(FormattableString.Invariant($"Combo{i}: "));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.R * byte.MaxValue)},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.G * byte.MaxValue)},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.B * byte.MaxValue)},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.A * byte.MaxValue)}"));
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleHitObjects(TextWriter writer)
|
private void handleHitObjects(TextWriter writer)
|
||||||
{
|
{
|
||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -22,6 +23,7 @@ using osu.Game.Storyboards;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public abstract class WorkingBeatmap : IWorkingBeatmap
|
public abstract class WorkingBeatmap : IWorkingBeatmap
|
||||||
{
|
{
|
||||||
public readonly BeatmapInfo BeatmapInfo;
|
public readonly BeatmapInfo BeatmapInfo;
|
||||||
@ -53,7 +55,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
const double excess_length = 1000;
|
const double excess_length = 1000;
|
||||||
|
|
||||||
var lastObject = Beatmap.HitObjects.LastOrDefault();
|
var lastObject = Beatmap?.HitObjects.LastOrDefault();
|
||||||
|
|
||||||
double length;
|
double length;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Configuration;
|
|||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -13,6 +14,7 @@ using osu.Game.Screens.Select.Filter;
|
|||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public class OsuConfigManager : IniConfigManager<OsuSetting>
|
public class OsuConfigManager : IniConfigManager<OsuSetting>
|
||||||
{
|
{
|
||||||
protected override void InitialiseDefaults()
|
protected override void InitialiseDefaults()
|
||||||
@ -231,6 +233,6 @@ namespace osu.Game.Configuration
|
|||||||
UIHoldActivationDelay,
|
UIHoldActivationDelay,
|
||||||
HitLighting,
|
HitLighting,
|
||||||
MenuBackgroundSource,
|
MenuBackgroundSource,
|
||||||
GameplayDisableWinKey
|
GameplayDisableWinKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,15 +397,24 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update an existing file, or create a new entry if not already part of the <paramref name="model"/>'s files.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The item to operate on.</param>
|
||||||
|
/// <param name="file">The file model to be updated or added.</param>
|
||||||
|
/// <param name="contents">The new file contents.</param>
|
||||||
public void UpdateFile(TModel model, TFileModel file, Stream contents)
|
public void UpdateFile(TModel model, TFileModel file, Stream contents)
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
// Dereference the existing file info, since the file model will be removed.
|
// Dereference the existing file info, since the file model will be removed.
|
||||||
Files.Dereference(file.FileInfo);
|
if (file.FileInfo != null)
|
||||||
|
{
|
||||||
|
Files.Dereference(file.FileInfo);
|
||||||
|
|
||||||
// Remove the file model.
|
// Remove the file model.
|
||||||
usage.Context.Set<TFileModel>().Remove(file);
|
usage.Context.Set<TFileModel>().Remove(file);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the new file info and containing file model.
|
// Add the new file info and containing file model.
|
||||||
model.Files.Remove(file);
|
model.Files.Remove(file);
|
||||||
|
@ -103,6 +103,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool playedPopInSound;
|
||||||
|
|
||||||
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
||||||
{
|
{
|
||||||
switch (state.NewValue)
|
switch (state.NewValue)
|
||||||
@ -110,16 +112,24 @@ namespace osu.Game.Graphics.Containers
|
|||||||
case Visibility.Visible:
|
case Visibility.Visible:
|
||||||
if (OverlayActivationMode.Value == OverlayActivation.Disabled)
|
if (OverlayActivationMode.Value == OverlayActivation.Disabled)
|
||||||
{
|
{
|
||||||
|
// todo: visual/audible feedback that this operation could not complete.
|
||||||
State.Value = Visibility.Hidden;
|
State.Value = Visibility.Hidden;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
samplePopIn?.Play();
|
samplePopIn?.Play();
|
||||||
|
playedPopInSound = true;
|
||||||
|
|
||||||
if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this);
|
if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Visibility.Hidden:
|
case Visibility.Hidden:
|
||||||
samplePopOut?.Play();
|
if (playedPopInSound)
|
||||||
|
{
|
||||||
|
samplePopOut?.Play();
|
||||||
|
playedPopInSound = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this);
|
if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,11 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
if (value == expandableHeader) return;
|
if (value == expandableHeader) return;
|
||||||
|
|
||||||
expandableHeader?.Expire();
|
if (expandableHeader != null)
|
||||||
|
RemoveInternal(expandableHeader);
|
||||||
|
|
||||||
expandableHeader = value;
|
expandableHeader = value;
|
||||||
|
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
|
|
||||||
AddInternal(expandableHeader);
|
AddInternal(expandableHeader);
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.StateChanges;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
@ -47,7 +48,10 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (!CanShowCursor)
|
var lastMouseSource = inputManager.CurrentState.Mouse.LastSource;
|
||||||
|
bool hasValidInput = lastMouseSource != null && !(lastMouseSource is ISourcedFromTouch);
|
||||||
|
|
||||||
|
if (!hasValidInput || !CanShowCursor)
|
||||||
{
|
{
|
||||||
currentTarget?.Cursor?.Hide();
|
currentTarget?.Cursor?.Hide();
|
||||||
currentTarget = null;
|
currentTarget = null;
|
||||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
public class OsuDropdown<T> : Dropdown<T>, IHasAccentColour
|
public class OsuDropdown<T> : Dropdown<T>, IHasAccentColour
|
||||||
{
|
{
|
||||||
|
private const float corner_radius = 4;
|
||||||
|
|
||||||
private Color4 accentColour;
|
private Color4 accentColour;
|
||||||
|
|
||||||
public Color4 AccentColour
|
public Color4 AccentColour
|
||||||
@ -57,9 +59,11 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
public OsuDropdownMenu()
|
public OsuDropdownMenu()
|
||||||
{
|
{
|
||||||
CornerRadius = 4;
|
CornerRadius = corner_radius;
|
||||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||||
|
|
||||||
|
MaskingContainer.CornerRadius = corner_radius;
|
||||||
|
|
||||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
ItemsContainer.Padding = new MarginPadding(5);
|
ItemsContainer.Padding = new MarginPadding(5);
|
||||||
}
|
}
|
||||||
@ -138,7 +142,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Foreground.Padding = new MarginPadding(2);
|
Foreground.Padding = new MarginPadding(2);
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
CornerRadius = 6;
|
CornerRadius = corner_radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -237,7 +241,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
AutoSizeAxes = Axes.None;
|
AutoSizeAxes = Axes.None;
|
||||||
Margin = new MarginPadding { Bottom = 4 };
|
Margin = new MarginPadding { Bottom = 4 };
|
||||||
CornerRadius = 4;
|
CornerRadius = corner_radius;
|
||||||
Height = 40;
|
Height = 40;
|
||||||
|
|
||||||
Foreground.Children = new Drawable[]
|
Foreground.Children = new Drawable[]
|
||||||
|
@ -9,16 +9,20 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public abstract class RollingCounter<T> : Container
|
public abstract class RollingCounter<T> : Container, IHasCurrentValue<T>
|
||||||
where T : struct, IEquatable<T>
|
where T : struct, IEquatable<T>
|
||||||
{
|
{
|
||||||
/// <summary>
|
private readonly BindableWithCurrent<T> current = new BindableWithCurrent<T>();
|
||||||
/// The current value.
|
|
||||||
/// </summary>
|
public Bindable<T> Current
|
||||||
public Bindable<T> Current = new Bindable<T>();
|
{
|
||||||
|
get => current.Current;
|
||||||
|
set => current.Current = value;
|
||||||
|
}
|
||||||
|
|
||||||
private SpriteText displayedCountSpriteText;
|
private SpriteText displayedCountSpriteText;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
@ -32,6 +33,11 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
|||||||
set => Component.Text = value;
|
set => Component.Text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Container TabbableContentContainer
|
||||||
|
{
|
||||||
|
set => Component.TabbableContentContainer = value;
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,13 @@ namespace osu.Game.IO
|
|||||||
this.subPath = subPath;
|
this.subPath = subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string MutatePath(string path) => !string.IsNullOrEmpty(subPath) ? Path.Combine(subPath, path) : path;
|
protected virtual string MutatePath(string path)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return !string.IsNullOrEmpty(subPath) ? Path.Combine(subPath, path) : path;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void ChangeTargetStorage(Storage newStorage)
|
protected virtual void ChangeTargetStorage(Storage newStorage)
|
||||||
{
|
{
|
||||||
|
25
osu.Game/Input/GameIdleTracker.cs
Normal file
25
osu.Game/Input/GameIdleTracker.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Input
|
||||||
|
{
|
||||||
|
public class GameIdleTracker : IdleTracker
|
||||||
|
{
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
|
public GameIdleTracker(int time)
|
||||||
|
: base(time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
inputManager = GetContainingInputManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool AllowIdle => inputManager.FocusedDrawable == null;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Online.API.Requests.Responses
|
namespace osu.Game.Online.API.Requests.Responses
|
||||||
{
|
{
|
||||||
@ -22,5 +24,12 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
|
|
||||||
[JsonProperty(@"score")]
|
[JsonProperty(@"score")]
|
||||||
public APILegacyScoreInfo Score;
|
public APILegacyScoreInfo Score;
|
||||||
|
|
||||||
|
public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
|
||||||
|
{
|
||||||
|
var score = Score.CreateScoreInfo(rulesets);
|
||||||
|
score.Position = Position;
|
||||||
|
return score;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty("user")]
|
[JsonProperty("user")]
|
||||||
public User User { get; set; }
|
public User User { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("position")]
|
||||||
|
public int? Position { get; set; }
|
||||||
|
|
||||||
public ScoreInfo CreateScoreInfo() =>
|
public ScoreInfo CreateScoreInfo() =>
|
||||||
new ScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
@ -40,6 +43,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
PP = PP,
|
PP = PP,
|
||||||
TotalScore = TotalScore,
|
TotalScore = TotalScore,
|
||||||
User = User,
|
User = User,
|
||||||
|
Position = Position
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
|
|
||||||
private readonly OsuScrollContainer scrollContainer;
|
private readonly OsuScrollContainer scrollContainer;
|
||||||
private readonly Container placeholderContainer;
|
private readonly Container placeholderContainer;
|
||||||
|
private readonly UserTopScoreContainer<TScoreInfo> topScoreContainer;
|
||||||
|
|
||||||
private FillFlowContainer<LeaderboardScore> scrollFlow;
|
private FillFlowContainer<LeaderboardScore> scrollFlow;
|
||||||
|
|
||||||
@ -55,13 +56,14 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire();
|
scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire();
|
||||||
scrollFlow = null;
|
scrollFlow = null;
|
||||||
|
|
||||||
loading.Hide();
|
|
||||||
|
|
||||||
showScoresDelegate?.Cancel();
|
showScoresDelegate?.Cancel();
|
||||||
showScoresCancellationSource?.Cancel();
|
showScoresCancellationSource?.Cancel();
|
||||||
|
|
||||||
if (scores == null || !scores.Any())
|
if (scores == null || !scores.Any())
|
||||||
|
{
|
||||||
|
loading.Hide();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ensure placeholder is hidden when displaying scores
|
// ensure placeholder is hidden when displaying scores
|
||||||
PlaceholderState = PlaceholderState.Successful;
|
PlaceholderState = PlaceholderState.Successful;
|
||||||
@ -83,10 +85,25 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollContainer.ScrollTo(0f, false);
|
scrollContainer.ScrollTo(0f, false);
|
||||||
|
loading.Hide();
|
||||||
}, (showScoresCancellationSource = new CancellationTokenSource()).Token));
|
}, (showScoresCancellationSource = new CancellationTokenSource()).Token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TScoreInfo TopScore
|
||||||
|
{
|
||||||
|
get => topScoreContainer.Score.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
topScoreContainer.Score.Value = value;
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
topScoreContainer.Hide();
|
||||||
|
else
|
||||||
|
topScoreContainer.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual FillFlowContainer<LeaderboardScore> CreateScoreFlow()
|
protected virtual FillFlowContainer<LeaderboardScore> CreateScoreFlow()
|
||||||
=> new FillFlowContainer<LeaderboardScore>
|
=> new FillFlowContainer<LeaderboardScore>
|
||||||
{
|
{
|
||||||
@ -198,8 +215,9 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Child = topScoreContainer = new UserTopScoreContainer<TScoreInfo>(CreateDrawableTopScore)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -367,5 +385,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index);
|
protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index);
|
||||||
|
|
||||||
|
protected abstract LeaderboardScore CreateDrawableTopScore(TScoreInfo model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,31 +9,29 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
using osu.Game.Online.Leaderboards;
|
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Select.Leaderboards
|
namespace osu.Game.Online.Leaderboards
|
||||||
{
|
{
|
||||||
public class UserTopScoreContainer : VisibilityContainer
|
public class UserTopScoreContainer<TScoreInfo> : VisibilityContainer
|
||||||
{
|
{
|
||||||
private const int duration = 500;
|
private const int duration = 500;
|
||||||
|
|
||||||
|
public Bindable<TScoreInfo> Score = new Bindable<TScoreInfo>();
|
||||||
|
|
||||||
private readonly Container scoreContainer;
|
private readonly Container scoreContainer;
|
||||||
|
private readonly Func<TScoreInfo, LeaderboardScore> createScoreDelegate;
|
||||||
public Bindable<APILegacyUserTopScoreInfo> Score = new Bindable<APILegacyUserTopScoreInfo>();
|
|
||||||
|
|
||||||
public Action<ScoreInfo> ScoreSelected;
|
|
||||||
|
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private RulesetStore rulesets { get; set; }
|
private RulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
public UserTopScoreContainer()
|
public UserTopScoreContainer(Func<TScoreInfo, LeaderboardScore> createScoreDelegate)
|
||||||
{
|
{
|
||||||
|
this.createScoreDelegate = createScoreDelegate;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
@ -72,7 +70,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
|
|
||||||
private CancellationTokenSource loadScoreCancellation;
|
private CancellationTokenSource loadScoreCancellation;
|
||||||
|
|
||||||
private void onScoreChanged(ValueChangedEvent<APILegacyUserTopScoreInfo> score)
|
private void onScoreChanged(ValueChangedEvent<TScoreInfo> score)
|
||||||
{
|
{
|
||||||
var newScore = score.NewValue;
|
var newScore = score.NewValue;
|
||||||
|
|
||||||
@ -82,12 +80,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
if (newScore == null)
|
if (newScore == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var scoreInfo = newScore.Score.CreateScoreInfo(rulesets);
|
LoadComponentAsync(createScoreDelegate(newScore), drawableScore =>
|
||||||
|
|
||||||
LoadComponentAsync(new LeaderboardScore(scoreInfo, newScore.Position, false)
|
|
||||||
{
|
|
||||||
Action = () => ScoreSelected?.Invoke(scoreInfo)
|
|
||||||
}, drawableScore =>
|
|
||||||
{
|
{
|
||||||
scoreContainer.Child = drawableScore;
|
scoreContainer.Child = drawableScore;
|
||||||
drawableScore.FadeInFromZero(duration, Easing.OutQuint);
|
drawableScore.FadeInFromZero(duration, Easing.OutQuint);
|
18
osu.Game/Online/Multiplayer/APILeaderboard.cs
Normal file
18
osu.Game/Online/Multiplayer/APILeaderboard.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 System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.Multiplayer
|
||||||
|
{
|
||||||
|
public class APILeaderboard
|
||||||
|
{
|
||||||
|
[JsonProperty("leaderboard")]
|
||||||
|
public List<APIUserScoreAggregate> Leaderboard;
|
||||||
|
|
||||||
|
[JsonProperty("user_score")]
|
||||||
|
public APIUserScoreAggregate UserScore;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,15 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
|
|
||||||
namespace osu.Game.Online.Multiplayer
|
namespace osu.Game.Online.Multiplayer
|
||||||
{
|
{
|
||||||
public class GetRoomScoresRequest : APIRequest<List<APIUserScoreAggregate>>
|
public class GetRoomLeaderboardRequest : APIRequest<APILeaderboard>
|
||||||
{
|
{
|
||||||
private readonly int roomId;
|
private readonly int roomId;
|
||||||
|
|
||||||
public GetRoomScoresRequest(int roomId)
|
public GetRoomLeaderboardRequest(int roomId)
|
||||||
{
|
{
|
||||||
this.roomId = roomId;
|
this.roomId = roomId;
|
||||||
}
|
}
|
@ -38,6 +38,7 @@ using osu.Game.Input;
|
|||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Overlays.Music;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Game.Overlays.Volume;
|
using osu.Game.Overlays.Volume;
|
||||||
@ -647,6 +648,7 @@ namespace osu.Game
|
|||||||
chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible;
|
chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible;
|
||||||
|
|
||||||
Add(externalLinkOpener = new ExternalLinkOpener());
|
Add(externalLinkOpener = new ExternalLinkOpener());
|
||||||
|
Add(new MusicKeyBindingHandler());
|
||||||
|
|
||||||
// side overlays which cancel each other.
|
// side overlays which cancel each other.
|
||||||
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
|
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
|
||||||
@ -698,9 +700,9 @@ namespace osu.Game
|
|||||||
float offset = 0;
|
float offset = 0;
|
||||||
|
|
||||||
if (Settings.State.Value == Visibility.Visible)
|
if (Settings.State.Value == Visibility.Visible)
|
||||||
offset += ToolbarButton.WIDTH / 2;
|
offset += Toolbar.HEIGHT / 2;
|
||||||
if (notifications.State.Value == Visibility.Visible)
|
if (notifications.State.Value == Visibility.Visible)
|
||||||
offset -= ToolbarButton.WIDTH / 2;
|
offset -= Toolbar.HEIGHT / 2;
|
||||||
|
|
||||||
screenContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint);
|
screenContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
@ -718,24 +720,6 @@ namespace osu.Game
|
|||||||
overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime);
|
overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameIdleTracker : IdleTracker
|
|
||||||
{
|
|
||||||
private InputManager inputManager;
|
|
||||||
|
|
||||||
public GameIdleTracker(int time)
|
|
||||||
: base(time)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
inputManager = GetContainingInputManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool AllowIdle => inputManager.FocusedDrawable == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void forwardLoggedErrorsToNotifications()
|
private void forwardLoggedErrorsToNotifications()
|
||||||
{
|
{
|
||||||
int recentLogCount = 0;
|
int recentLogCount = 0;
|
||||||
@ -991,10 +975,4 @@ namespace osu.Game
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScorePresentType
|
|
||||||
{
|
|
||||||
Results,
|
|
||||||
Gameplay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
|
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
|
||||||
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host));
|
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host));
|
||||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap));
|
dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap, true));
|
||||||
|
|
||||||
// this should likely be moved to ArchiveModelManager when another case appers where it is necessary
|
// this should likely be moved to ArchiveModelManager when another case appers where it is necessary
|
||||||
// to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
|
// to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
|
||||||
@ -250,10 +250,11 @@ namespace osu.Game
|
|||||||
AddInternal(apiAccess);
|
AddInternal(apiAccess);
|
||||||
AddInternal(RulesetConfigCache);
|
AddInternal(RulesetConfigCache);
|
||||||
|
|
||||||
GlobalActionContainer globalBinding;
|
|
||||||
|
|
||||||
MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both };
|
MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both };
|
||||||
MenuCursorContainer.Child = globalBinding = new GlobalActionContainer(this)
|
|
||||||
|
GlobalActionContainer globalBindings;
|
||||||
|
|
||||||
|
MenuCursorContainer.Child = globalBindings = new GlobalActionContainer(this)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
|
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
|
||||||
@ -261,8 +262,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
base.Content.Add(CreateScalingContainer().WithChild(MenuCursorContainer));
|
base.Content.Add(CreateScalingContainer().WithChild(MenuCursorContainer));
|
||||||
|
|
||||||
KeyBindingStore.Register(globalBinding);
|
KeyBindingStore.Register(globalBindings);
|
||||||
dependencies.Cache(globalBinding);
|
dependencies.Cache(globalBindings);
|
||||||
|
|
||||||
PreviewTrackManager previewTrackManager;
|
PreviewTrackManager previewTrackManager;
|
||||||
dependencies.Cache(previewTrackManager = new PreviewTrackManager());
|
dependencies.Cache(previewTrackManager = new PreviewTrackManager());
|
||||||
|
@ -12,7 +12,8 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
public BeatmapListingTitle()
|
public BeatmapListingTitle()
|
||||||
{
|
{
|
||||||
Title = "beatmap listing";
|
Title = "beatmap listing";
|
||||||
IconTexture = "Icons/changelog";
|
Description = "browse for new beatmaps";
|
||||||
|
IconTexture = "Icons/Hexacons/beatmap";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class BeatmapListingOverlay : FullscreenOverlay
|
public class BeatmapListingOverlay : FullscreenOverlay<BeatmapListingHeader>
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private PreviewTrackManager previewTrackManager { get; set; }
|
private PreviewTrackManager previewTrackManager { get; set; }
|
||||||
@ -38,7 +38,7 @@ namespace osu.Game.Overlays
|
|||||||
private OverlayScrollContainer resultScrollContainer;
|
private OverlayScrollContainer resultScrollContainer;
|
||||||
|
|
||||||
public BeatmapListingOverlay()
|
public BeatmapListingOverlay()
|
||||||
: base(OverlayColourScheme.Blue)
|
: base(OverlayColourScheme.Blue, new BeatmapListingHeader())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ namespace osu.Game.Overlays
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new BeatmapListingHeader(),
|
Header,
|
||||||
filterControl = new BeatmapListingFilterControl
|
filterControl = new BeatmapListingFilterControl
|
||||||
{
|
{
|
||||||
SearchStarted = onSearchStarted,
|
SearchStarted = onSearchStarted,
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
public BeatmapHeaderTitle()
|
public BeatmapHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "beatmap info";
|
Title = "beatmap info";
|
||||||
IconTexture = "Icons/changelog";
|
IconTexture = "Icons/Hexacons/beatmap";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,14 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class BeatmapSetOverlay : FullscreenOverlay
|
public class BeatmapSetOverlay : FullscreenOverlay<OverlayHeader> // we don't provide a standard header for now.
|
||||||
{
|
{
|
||||||
public const float X_PADDING = 40;
|
public const float X_PADDING = 40;
|
||||||
public const float Y_PADDING = 25;
|
public const float Y_PADDING = 25;
|
||||||
public const float RIGHT_WIDTH = 275;
|
public const float RIGHT_WIDTH = 275;
|
||||||
protected readonly Header Header;
|
|
||||||
|
//todo: should be an OverlayHeader? or maybe not?
|
||||||
|
protected new readonly Header Header;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private RulesetStore rulesets { get; set; }
|
private RulesetStore rulesets { get; set; }
|
||||||
@ -37,7 +39,7 @@ namespace osu.Game.Overlays
|
|||||||
private readonly Box background;
|
private readonly Box background;
|
||||||
|
|
||||||
public BeatmapSetOverlay()
|
public BeatmapSetOverlay()
|
||||||
: base(OverlayColourScheme.Blue)
|
: base(OverlayColourScheme.Blue, null)
|
||||||
{
|
{
|
||||||
OverlayScrollContainer scroll;
|
OverlayScrollContainer scroll;
|
||||||
Info info;
|
Info info;
|
||||||
|
@ -115,7 +115,8 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
public ChangelogHeaderTitle()
|
public ChangelogHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "changelog";
|
Title = "changelog";
|
||||||
IconTexture = "Icons/changelog";
|
Description = "track recent dev updates in the osu! ecosystem";
|
||||||
|
IconTexture = "Icons/Hexacons/devtools";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,10 @@ using osu.Game.Overlays.Changelog;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class ChangelogOverlay : FullscreenOverlay
|
public class ChangelogOverlay : FullscreenOverlay<ChangelogHeader>
|
||||||
{
|
{
|
||||||
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
||||||
|
|
||||||
protected ChangelogHeader Header;
|
|
||||||
|
|
||||||
private Container<ChangelogContent> content;
|
private Container<ChangelogContent> content;
|
||||||
|
|
||||||
private SampleChannel sampleBack;
|
private SampleChannel sampleBack;
|
||||||
@ -36,7 +34,7 @@ namespace osu.Game.Overlays
|
|||||||
protected List<APIUpdateStream> Streams;
|
protected List<APIUpdateStream> Streams;
|
||||||
|
|
||||||
public ChangelogOverlay()
|
public ChangelogOverlay()
|
||||||
: base(OverlayColourScheme.Purple)
|
: base(OverlayColourScheme.Purple, new ChangelogHeader())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,10 +59,11 @@ namespace osu.Game.Overlays
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Header = new ChangelogHeader
|
Header.With(h =>
|
||||||
{
|
{
|
||||||
ListingSelected = ShowListing,
|
h.ListingSelected = ShowListing;
|
||||||
},
|
h.Build.BindTarget = Current;
|
||||||
|
}),
|
||||||
content = new Container<ChangelogContent>
|
content = new Container<ChangelogContent>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -77,8 +76,6 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
|
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
|
||||||
|
|
||||||
Header.Build.BindTo(Current);
|
|
||||||
|
|
||||||
Current.BindValueChanged(e =>
|
Current.BindValueChanged(e =>
|
||||||
{
|
{
|
||||||
if (e.NewValue != null)
|
if (e.NewValue != null)
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
|||||||
{
|
{
|
||||||
public class ChannelSelectionOverlay : WaveOverlayContainer
|
public class ChannelSelectionOverlay : WaveOverlayContainer
|
||||||
{
|
{
|
||||||
public const float WIDTH_PADDING = 170;
|
public new const float WIDTH_PADDING = 170;
|
||||||
|
|
||||||
private const float transition_duration = 500;
|
private const float transition_duration = 500;
|
||||||
|
|
||||||
|
@ -26,8 +26,12 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class ChatOverlay : OsuFocusedOverlayContainer
|
public class ChatOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
|
||||||
{
|
{
|
||||||
|
public string IconTexture => "Icons/Hexacons/messaging";
|
||||||
|
public string Title => "chat";
|
||||||
|
public string Description => "join the real-time discussion";
|
||||||
|
|
||||||
private const float textbox_height = 60;
|
private const float textbox_height = 60;
|
||||||
private const float channel_selection_min_height = 0.3f;
|
private const float channel_selection_min_height = 0.3f;
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
public DashboardTitle()
|
public DashboardTitle()
|
||||||
{
|
{
|
||||||
Title = "dashboard";
|
Title = "dashboard";
|
||||||
IconTexture = "Icons/changelog";
|
Description = "view your friends and other information";
|
||||||
|
IconTexture = "Icons/Hexacons/social";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,21 @@ using osu.Game.Overlays.Dashboard.Friends;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class DashboardOverlay : FullscreenOverlay
|
public class DashboardOverlay : FullscreenOverlay<DashboardOverlayHeader>
|
||||||
{
|
{
|
||||||
private CancellationTokenSource cancellationToken;
|
private CancellationTokenSource cancellationToken;
|
||||||
|
|
||||||
private Container content;
|
private Container content;
|
||||||
private DashboardOverlayHeader header;
|
|
||||||
private LoadingLayer loading;
|
private LoadingLayer loading;
|
||||||
private OverlayScrollContainer scrollFlow;
|
private OverlayScrollContainer scrollFlow;
|
||||||
|
|
||||||
public DashboardOverlay()
|
public DashboardOverlay()
|
||||||
: base(OverlayColourScheme.Purple)
|
: base(OverlayColourScheme.Purple, new DashboardOverlayHeader
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Depth = -float.MaxValue
|
||||||
|
})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +54,7 @@ namespace osu.Game.Overlays
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
header = new DashboardOverlayHeader
|
Header,
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Depth = -float.MaxValue
|
|
||||||
},
|
|
||||||
content = new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -72,7 +71,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
header.Current.BindValueChanged(onTabChanged);
|
Header.Current.BindValueChanged(onTabChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool displayUpdateRequired = true;
|
private bool displayUpdateRequired = true;
|
||||||
@ -84,7 +83,7 @@ namespace osu.Game.Overlays
|
|||||||
// We don't want to create a new display on every call, only when exiting from fully closed state.
|
// We don't want to create a new display on every call, only when exiting from fully closed state.
|
||||||
if (displayUpdateRequired)
|
if (displayUpdateRequired)
|
||||||
{
|
{
|
||||||
header.Current.TriggerChange();
|
Header.Current.TriggerChange();
|
||||||
displayUpdateRequired = false;
|
displayUpdateRequired = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,7 +135,7 @@ namespace osu.Game.Overlays
|
|||||||
if (State.Value == Visibility.Hidden)
|
if (State.Value == Visibility.Hidden)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
header.Current.TriggerChange();
|
Header.Current.TriggerChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -12,16 +12,25 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public abstract class FullscreenOverlay : WaveOverlayContainer, IOnlineComponent
|
public abstract class FullscreenOverlay<T> : WaveOverlayContainer, IOnlineComponent, INamedOverlayComponent
|
||||||
|
where T : OverlayHeader
|
||||||
{
|
{
|
||||||
|
public virtual string IconTexture => Header?.Title.IconTexture ?? string.Empty;
|
||||||
|
public virtual string Title => Header?.Title.Title ?? string.Empty;
|
||||||
|
public virtual string Description => Header?.Title.Description ?? string.Empty;
|
||||||
|
|
||||||
|
public T Header { get; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected IAPIProvider API { get; private set; }
|
protected IAPIProvider API { get; private set; }
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
protected readonly OverlayColourProvider ColourProvider;
|
protected readonly OverlayColourProvider ColourProvider;
|
||||||
|
|
||||||
protected FullscreenOverlay(OverlayColourScheme colourScheme)
|
protected FullscreenOverlay(OverlayColourScheme colourScheme, T header)
|
||||||
{
|
{
|
||||||
|
Header = header;
|
||||||
|
|
||||||
ColourProvider = new OverlayColourProvider(colourScheme);
|
ColourProvider = new OverlayColourProvider(colourScheme);
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
14
osu.Game/Overlays/INamedOverlayComponent.cs
Normal file
14
osu.Game/Overlays/INamedOverlayComponent.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// 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.Overlays
|
||||||
|
{
|
||||||
|
public interface INamedOverlayComponent
|
||||||
|
{
|
||||||
|
string IconTexture { get; }
|
||||||
|
|
||||||
|
string Title { get; }
|
||||||
|
|
||||||
|
string Description { get; }
|
||||||
|
}
|
||||||
|
}
|
81
osu.Game/Overlays/Music/MusicKeyBindingHandler.cs
Normal file
81
osu.Game/Overlays/Music/MusicKeyBindingHandler.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Overlays.OSD;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Music
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles <see cref="GlobalAction"/>s related to music playback, and displays <see cref="Toast"/>s via the global <see cref="OnScreenDisplay"/> accordingly.
|
||||||
|
/// </summary>
|
||||||
|
public class MusicKeyBindingHandler : Component, IKeyBindingHandler<GlobalAction>
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private MusicController musicController { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private OnScreenDisplay onScreenDisplay { get; set; }
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (beatmap.Disabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.MusicPlay:
|
||||||
|
// use previous state as TogglePause may not update the track's state immediately (state update is run on the audio thread see https://github.com/ppy/osu/issues/9880#issuecomment-674668842)
|
||||||
|
bool wasPlaying = musicController.IsPlaying;
|
||||||
|
|
||||||
|
if (musicController.TogglePause())
|
||||||
|
onScreenDisplay?.Display(new MusicActionToast(wasPlaying ? "Pause track" : "Play track"));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.MusicNext:
|
||||||
|
musicController.NextTrack(() => onScreenDisplay?.Display(new MusicActionToast("Next track")));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.MusicPrev:
|
||||||
|
musicController.PreviousTrack(res =>
|
||||||
|
{
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case PreviousTrackResult.Restart:
|
||||||
|
onScreenDisplay?.Display(new MusicActionToast("Restart track"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PreviousTrackResult.Previous:
|
||||||
|
onScreenDisplay?.Display(new MusicActionToast("Previous track"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(GlobalAction action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MusicActionToast : Toast
|
||||||
|
{
|
||||||
|
public MusicActionToast(string action)
|
||||||
|
: base("Music Playback", action, string.Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,12 +12,9 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Audio;
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Input.Bindings;
|
|
||||||
using osu.Game.Overlays.OSD;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
@ -25,7 +22,7 @@ namespace osu.Game.Overlays
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles playback of the global music track.
|
/// Handles playback of the global music track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MusicController : CompositeDrawable, IKeyBindingHandler<GlobalAction>
|
public class MusicController : CompositeDrawable
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
@ -62,9 +59,6 @@ namespace osu.Game.Overlays
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
|
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private OnScreenDisplay onScreenDisplay { get; set; }
|
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
public DrawableTrack CurrentTrack { get; private set; } = new DrawableTrack(new TrackVirtual(1000));
|
public DrawableTrack CurrentTrack { get; private set; } = new DrawableTrack(new TrackVirtual(1000));
|
||||||
|
|
||||||
@ -207,7 +201,13 @@ namespace osu.Game.Overlays
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Play the previous track or restart the current track if it's current time below <see cref="restart_cutoff_point"/>.
|
/// Play the previous track or restart the current track if it's current time below <see cref="restart_cutoff_point"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void PreviousTrack() => Schedule(() => prev());
|
/// <param name="onSuccess">Invoked when the operation has been performed successfully.</param>
|
||||||
|
public void PreviousTrack(Action<PreviousTrackResult> onSuccess = null) => Schedule(() =>
|
||||||
|
{
|
||||||
|
PreviousTrackResult res = prev();
|
||||||
|
if (res != PreviousTrackResult.None)
|
||||||
|
onSuccess?.Invoke(res);
|
||||||
|
});
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Play the previous track or restart the current track if it's current time below <see cref="restart_cutoff_point"/>.
|
/// Play the previous track or restart the current track if it's current time below <see cref="restart_cutoff_point"/>.
|
||||||
@ -243,7 +243,14 @@ namespace osu.Game.Overlays
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Play the next random or playlist track.
|
/// Play the next random or playlist track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void NextTrack() => Schedule(() => next());
|
/// <param name="onSuccess">Invoked when the operation has been performed successfully.</param>
|
||||||
|
/// <returns>A <see cref="ScheduledDelegate"/> of the operation.</returns>
|
||||||
|
public void NextTrack(Action onSuccess = null) => Schedule(() =>
|
||||||
|
{
|
||||||
|
bool res = next();
|
||||||
|
if (res)
|
||||||
|
onSuccess?.Invoke();
|
||||||
|
});
|
||||||
|
|
||||||
private bool next()
|
private bool next()
|
||||||
{
|
{
|
||||||
@ -279,6 +286,11 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private void changeBeatmap(WorkingBeatmap newWorking)
|
private void changeBeatmap(WorkingBeatmap newWorking)
|
||||||
{
|
{
|
||||||
|
// This method can potentially be triggered multiple times as it is eagerly fired in next() / prev() to ensure correct execution order
|
||||||
|
// (changeBeatmap must be called before consumers receive the bindable changed event, which is not the case when the local beatmap bindable is updated directly).
|
||||||
|
if (newWorking == current)
|
||||||
|
return;
|
||||||
|
|
||||||
var lastWorking = current;
|
var lastWorking = current;
|
||||||
|
|
||||||
TrackChangeDirection direction = TrackChangeDirection.None;
|
TrackChangeDirection direction = TrackChangeDirection.None;
|
||||||
@ -402,54 +414,6 @@ namespace osu.Game.Overlays
|
|||||||
mod.ApplyToTrack(CurrentTrack);
|
mod.ApplyToTrack(CurrentTrack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
|
||||||
{
|
|
||||||
if (beatmap.Disabled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case GlobalAction.MusicPlay:
|
|
||||||
if (TogglePause())
|
|
||||||
onScreenDisplay?.Display(new MusicControllerToast(IsPlaying ? "Play track" : "Pause track"));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GlobalAction.MusicNext:
|
|
||||||
if (next())
|
|
||||||
onScreenDisplay?.Display(new MusicControllerToast("Next track"));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GlobalAction.MusicPrev:
|
|
||||||
switch (prev())
|
|
||||||
{
|
|
||||||
case PreviousTrackResult.Restart:
|
|
||||||
onScreenDisplay?.Display(new MusicControllerToast("Restart track"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PreviousTrackResult.Previous:
|
|
||||||
onScreenDisplay?.Display(new MusicControllerToast("Previous track"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnReleased(GlobalAction action)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MusicControllerToast : Toast
|
|
||||||
{
|
|
||||||
public MusicControllerToast(string action)
|
|
||||||
: base("Music Playback", action, string.Empty)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TrackChangeDirection
|
public enum TrackChangeDirection
|
||||||
|
@ -57,7 +57,8 @@ namespace osu.Game.Overlays.News
|
|||||||
public NewsHeaderTitle()
|
public NewsHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "news";
|
Title = "news";
|
||||||
IconTexture = "Icons/news";
|
Description = "get up-to-date on community happenings";
|
||||||
|
IconTexture = "Icons/Hexacons/news";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,16 @@ using osu.Game.Overlays.News.Displays;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class NewsOverlay : FullscreenOverlay
|
public class NewsOverlay : FullscreenOverlay<NewsHeader>
|
||||||
{
|
{
|
||||||
private readonly Bindable<string> article = new Bindable<string>(null);
|
private readonly Bindable<string> article = new Bindable<string>(null);
|
||||||
|
|
||||||
private Container content;
|
private Container content;
|
||||||
private LoadingLayer loading;
|
private LoadingLayer loading;
|
||||||
private NewsHeader header;
|
|
||||||
private OverlayScrollContainer scrollFlow;
|
private OverlayScrollContainer scrollFlow;
|
||||||
|
|
||||||
public NewsOverlay()
|
public NewsOverlay()
|
||||||
: base(OverlayColourScheme.Purple)
|
: base(OverlayColourScheme.Purple, new NewsHeader())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +47,10 @@ namespace osu.Game.Overlays
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
header = new NewsHeader
|
Header.With(h =>
|
||||||
{
|
{
|
||||||
ShowFrontPage = ShowFrontPage
|
h.ShowFrontPage = ShowFrontPage;
|
||||||
},
|
}),
|
||||||
content = new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -112,12 +111,12 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
if (e.NewValue == null)
|
if (e.NewValue == null)
|
||||||
{
|
{
|
||||||
header.SetFrontPage();
|
Header.SetFrontPage();
|
||||||
LoadDisplay(new FrontPageDisplay());
|
LoadDisplay(new FrontPageDisplay());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
header.SetArticle(e.NewValue);
|
Header.SetArticle(e.NewValue);
|
||||||
LoadDisplay(Empty());
|
LoadDisplay(Empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,12 @@ using osu.Framework.Threading;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class NotificationOverlay : OsuFocusedOverlayContainer
|
public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
|
||||||
{
|
{
|
||||||
|
public string IconTexture => "Icons/Hexacons/notification";
|
||||||
|
public string Title => "notifications";
|
||||||
|
public string Description => "waiting for 'ya";
|
||||||
|
|
||||||
private const float width = 320;
|
private const float width = 320;
|
||||||
|
|
||||||
public const float TRANSITION_LENGTH = 600;
|
public const float TRANSITION_LENGTH = 600;
|
||||||
|
@ -25,8 +25,12 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class NowPlayingOverlay : OsuFocusedOverlayContainer
|
public class NowPlayingOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
|
||||||
{
|
{
|
||||||
|
public string IconTexture => "Icons/Hexacons/music";
|
||||||
|
public string Title => "now playing";
|
||||||
|
public string Description => "manage the currently playing track";
|
||||||
|
|
||||||
private const float player_height = 130;
|
private const float player_height = 130;
|
||||||
private const float transition_length = 800;
|
private const float transition_length = 800;
|
||||||
private const float progress_height = 10;
|
private const float progress_height = 10;
|
||||||
|
@ -12,6 +12,8 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public abstract class OverlayHeader : Container
|
public abstract class OverlayHeader : Container
|
||||||
{
|
{
|
||||||
|
public OverlayTitle Title { get; }
|
||||||
|
|
||||||
private float contentSidePadding;
|
private float contentSidePadding;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -73,7 +75,7 @@ namespace osu.Game.Overlays
|
|||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
CreateTitle().With(title =>
|
Title = CreateTitle().With(title =>
|
||||||
{
|
{
|
||||||
title.Anchor = Anchor.CentreLeft;
|
title.Anchor = Anchor.CentreLeft;
|
||||||
title.Origin = Anchor.CentreLeft;
|
title.Origin = Anchor.CentreLeft;
|
||||||
|
@ -17,7 +17,7 @@ using osuTK.Graphics;
|
|||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="OsuScrollContainer"/> which provides <see cref="ScrollToTopButton"/>. Mostly used in <see cref="FullscreenOverlay"/>.
|
/// <see cref="OsuScrollContainer"/> which provides <see cref="ScrollToTopButton"/>. Mostly used in <see cref="FullscreenOverlay{T}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OverlayScrollContainer : OsuScrollContainer
|
public class OverlayScrollContainer : OsuScrollContainer
|
||||||
{
|
{
|
||||||
|
@ -12,19 +12,27 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public abstract class OverlayTitle : CompositeDrawable
|
public abstract class OverlayTitle : CompositeDrawable, INamedOverlayComponent
|
||||||
{
|
{
|
||||||
private readonly OsuSpriteText title;
|
private readonly OsuSpriteText titleText;
|
||||||
private readonly Container icon;
|
private readonly Container icon;
|
||||||
|
|
||||||
protected string Title
|
private string title;
|
||||||
|
|
||||||
|
public string Title
|
||||||
{
|
{
|
||||||
set => title.Text = value;
|
get => title;
|
||||||
|
protected set => titleText.Text = title = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string IconTexture
|
public string Description { get; protected set; }
|
||||||
|
|
||||||
|
private string iconTexture;
|
||||||
|
|
||||||
|
public string IconTexture
|
||||||
{
|
{
|
||||||
set => icon.Child = new OverlayTitleIcon(value);
|
get => iconTexture;
|
||||||
|
protected set => icon.Child = new OverlayTitleIcon(iconTexture = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OverlayTitle()
|
protected OverlayTitle()
|
||||||
@ -45,7 +53,7 @@ namespace osu.Game.Overlays
|
|||||||
Margin = new MarginPadding { Horizontal = 5 }, // compensates for osu-web sprites having around 5px of whitespace on each side
|
Margin = new MarginPadding { Horizontal = 5 }, // compensates for osu-web sprites having around 5px of whitespace on each side
|
||||||
Size = new Vector2(30)
|
Size = new Vector2(30)
|
||||||
},
|
},
|
||||||
title = new OsuSpriteText
|
titleText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -9,7 +9,7 @@ using osu.Game.Online.API;
|
|||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A subview containing online content, to be displayed inside a <see cref="FullscreenOverlay"/>.
|
/// A subview containing online content, to be displayed inside a <see cref="FullscreenOverlay{T}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Automatically performs a data fetch on load.
|
/// Automatically performs a data fetch on load.
|
||||||
|
@ -97,7 +97,7 @@ namespace osu.Game.Overlays.Profile
|
|||||||
public ProfileHeaderTitle()
|
public ProfileHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "player info";
|
Title = "player info";
|
||||||
IconTexture = "Icons/profile";
|
IconTexture = "Icons/Hexacons/profile";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ namespace osu.Game.Overlays.Rankings
|
|||||||
public RankingsTitle()
|
public RankingsTitle()
|
||||||
{
|
{
|
||||||
Title = "ranking";
|
Title = "ranking";
|
||||||
IconTexture = "Icons/rankings";
|
Description = "find out who's the best right now";
|
||||||
|
IconTexture = "Icons/Hexacons/rankings";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,16 @@ using osu.Game.Overlays.Rankings.Tables;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class RankingsOverlay : FullscreenOverlay
|
public class RankingsOverlay : FullscreenOverlay<RankingsOverlayHeader>
|
||||||
{
|
{
|
||||||
protected Bindable<Country> Country => header.Country;
|
protected Bindable<Country> Country => Header.Country;
|
||||||
|
|
||||||
protected Bindable<RankingsScope> Scope => header.Current;
|
protected Bindable<RankingsScope> Scope => Header.Current;
|
||||||
|
|
||||||
private readonly OverlayScrollContainer scrollFlow;
|
private readonly OverlayScrollContainer scrollFlow;
|
||||||
private readonly Container contentContainer;
|
private readonly Container contentContainer;
|
||||||
private readonly LoadingLayer loading;
|
private readonly LoadingLayer loading;
|
||||||
private readonly Box background;
|
private readonly Box background;
|
||||||
private readonly RankingsOverlayHeader header;
|
|
||||||
|
|
||||||
private APIRequest lastRequest;
|
private APIRequest lastRequest;
|
||||||
private CancellationTokenSource cancellationToken;
|
private CancellationTokenSource cancellationToken;
|
||||||
@ -36,7 +35,12 @@ namespace osu.Game.Overlays
|
|||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
public RankingsOverlay()
|
public RankingsOverlay()
|
||||||
: base(OverlayColourScheme.Green)
|
: base(OverlayColourScheme.Green, new RankingsOverlayHeader
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Depth = -float.MaxValue
|
||||||
|
})
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -55,12 +59,7 @@ namespace osu.Game.Overlays
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
header = new RankingsOverlayHeader
|
Header,
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Depth = -float.MaxValue
|
|
||||||
},
|
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -97,7 +96,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
header.Ruleset.BindTo(ruleset);
|
Header.Ruleset.BindTo(ruleset);
|
||||||
|
|
||||||
Country.BindValueChanged(_ =>
|
Country.BindValueChanged(_ =>
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.SearchableList
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of padding added to content (does not affect background or tab control strip).
|
/// The amount of padding added to content (does not affect background or tab control strip).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual float ContentHorizontalPadding => SearchableListOverlay.WIDTH_PADDING;
|
protected virtual float ContentHorizontalPadding => WaveOverlayContainer.WIDTH_PADDING;
|
||||||
|
|
||||||
protected SearchableListFilterControl()
|
protected SearchableListFilterControl()
|
||||||
{
|
{
|
||||||
|
@ -1,82 +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 osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.SearchableList
|
|
||||||
{
|
|
||||||
public abstract class SearchableListHeader<T> : Container
|
|
||||||
where T : struct, Enum
|
|
||||||
{
|
|
||||||
public readonly HeaderTabControl<T> Tabs;
|
|
||||||
|
|
||||||
protected abstract Color4 BackgroundColour { get; }
|
|
||||||
protected abstract T DefaultTab { get; }
|
|
||||||
protected abstract Drawable CreateHeaderText();
|
|
||||||
protected abstract IconUsage Icon { get; }
|
|
||||||
|
|
||||||
protected SearchableListHeader()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = 90;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = BackgroundColour,
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Left = SearchableListOverlay.WIDTH_PADDING, Right = SearchableListOverlay.WIDTH_PADDING },
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Position = new Vector2(-35f, 5f),
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(10f, 0f),
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
new SpriteIcon
|
|
||||||
{
|
|
||||||
Size = new Vector2(25),
|
|
||||||
Icon = Icon,
|
|
||||||
},
|
|
||||||
CreateHeaderText(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Tabs = new HeaderTabControl<T>
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Tabs.Current.Value = DefaultTab;
|
|
||||||
Tabs.Current.TriggerChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
Tabs.StripColour = colours.Green;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,128 +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 osuTK.Graphics;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Graphics.Backgrounds;
|
|
||||||
using osu.Game.Graphics.Cursor;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.SearchableList
|
|
||||||
{
|
|
||||||
public abstract class SearchableListOverlay : FullscreenOverlay
|
|
||||||
{
|
|
||||||
public const float WIDTH_PADDING = 80;
|
|
||||||
|
|
||||||
protected SearchableListOverlay(OverlayColourScheme colourScheme)
|
|
||||||
: base(colourScheme)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class SearchableListOverlay<THeader, TTab, TCategory> : SearchableListOverlay
|
|
||||||
where THeader : struct, Enum
|
|
||||||
where TTab : struct, Enum
|
|
||||||
where TCategory : struct, Enum
|
|
||||||
{
|
|
||||||
private readonly Container scrollContainer;
|
|
||||||
|
|
||||||
protected readonly SearchableListHeader<THeader> Header;
|
|
||||||
protected readonly SearchableListFilterControl<TTab, TCategory> Filter;
|
|
||||||
protected readonly FillFlowContainer ScrollFlow;
|
|
||||||
|
|
||||||
protected abstract Color4 BackgroundColour { get; }
|
|
||||||
protected abstract Color4 TrianglesColourLight { get; }
|
|
||||||
protected abstract Color4 TrianglesColourDark { get; }
|
|
||||||
protected abstract SearchableListHeader<THeader> CreateHeader();
|
|
||||||
protected abstract SearchableListFilterControl<TTab, TCategory> CreateFilterControl();
|
|
||||||
|
|
||||||
protected SearchableListOverlay(OverlayColourScheme colourScheme)
|
|
||||||
: base(colourScheme)
|
|
||||||
{
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = BackgroundColour,
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
new Triangles
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
TriangleScale = 5,
|
|
||||||
ColourLight = TrianglesColourLight,
|
|
||||||
ColourDark = TrianglesColourDark,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scrollContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Child = new OsuContextMenuContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Child = new OverlayScrollContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
ScrollbarVisible = false,
|
|
||||||
Child = ScrollFlow = new FillFlowContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Padding = new MarginPadding { Horizontal = 10, Bottom = 50 },
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
Header = CreateHeader(),
|
|
||||||
Filter = CreateFilterControl(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
scrollContainer.Padding = new MarginPadding { Top = Header.Height + Filter.Height };
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnFocus(FocusEvent e)
|
|
||||||
{
|
|
||||||
Filter.Search.TakeFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopIn()
|
|
||||||
{
|
|
||||||
base.PopIn();
|
|
||||||
|
|
||||||
Filter.Search.HoldFocus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopOut()
|
|
||||||
{
|
|
||||||
base.PopOut();
|
|
||||||
|
|
||||||
Filter.Search.HoldFocus = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user