1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 04:42:58 +08:00

Merge branch 'master' into add-confirmation-dialog

This commit is contained in:
Aergwyn 2017-12-15 18:11:13 +01:00
commit 2e196661bb
59 changed files with 1370 additions and 417 deletions

77
.vscode/tasks.json vendored
View File

@ -2,63 +2,70 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558 // See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format // for the documentation about the tasks.json format
"version": "2.0.0", "version": "2.0.0",
"command": "msbuild",
"type": "shell",
"suppressTaskName": true,
"args": [
"/property:GenerateFullPaths=true",
"/property:DebugType=portable",
"/verbosity:minimal",
"/m" //parallel compiling support.
],
"tasks": [{ "tasks": [{
"taskName": "Build (Debug)", "label": "Build (Debug)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:GenerateFullPaths=true",
"/p:DebugType=portable",
"/m",
"/v:m"
],
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
}, },
"problemMatcher": [ "problemMatcher": "$msCompile"
"$msCompile"
]
}, },
{ {
"taskName": "Build (Release)", "label": "Build (Release)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:Configuration=Release",
"/p:DebugType=portable",
"/p:GenerateFullPaths=true",
"/m",
"/v:m"
],
"group": "build", "group": "build",
"args": [ "problemMatcher": "$msCompile"
"/property:Configuration=Release"
],
"problemMatcher": [
"$msCompile"
]
}, },
{ {
"taskName": "Clean (Debug)", "label": "Clean (Debug)",
"type": "shell",
"command": "msbuild",
"args": [ "args": [
"/target:Clean" "/p:DebugType=portable",
"/p:GenerateFullPaths=true",
"/m",
"/t:Clean",
"/v:m"
], ],
"problemMatcher": [ "problemMatcher": "$msCompile"
"$msCompile"
]
}, },
{ {
"taskName": "Clean (Release)", "label": "Clean (Release)",
"type": "shell",
"command": "msbuild",
"args": [ "args": [
"/target:Clean", "/p:Configuration=Release",
"/property:Configuration=Release" "/p:GenerateFullPaths=true",
"/p:DebugType=portable",
"/m",
"/t:Clean",
"/v:m"
], ],
"problemMatcher": [ "problemMatcher": "$msCompile"
"$msCompile"
]
}, },
{ {
"taskName": "Clean All", "label": "Clean All",
"dependsOn": [ "dependsOn": [
"Clean (Debug)", "Clean (Debug)",
"Clean (Release)" "Clean (Release)"
], ],
"problemMatcher": [ "problemMatcher": "$msCompile"
"$msCompile"
]
} }
] ]
} }

View File

@ -93,6 +93,8 @@ namespace osu.Game.Rulesets.Catch
public override string Description => "osu!catch"; public override string Description => "osu!catch";
public override string ShortName => "fruits";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);

View File

@ -90,6 +90,9 @@
<Private>True</Private> <Private>True</Private>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -105,6 +105,8 @@ namespace osu.Game.Rulesets.Mania
public override string Description => "osu!mania"; public override string Description => "osu!mania";
public override string ShortName => "mania";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap);

View File

@ -114,6 +114,9 @@
<Private>True</Private> <Private>True</Private>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -5,7 +5,6 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.OsuDifficulty; using osu.Game.Rulesets.Osu.OsuDifficulty;
using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -18,6 +17,8 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Osu namespace osu.Game.Rulesets.Osu
{ {
@ -33,21 +34,35 @@ namespace osu.Game.Rulesets.Osu
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton), new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
}; };
public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap)
{
IEnumerable<HitObject> hitObjects = beatmap.Beatmap.HitObjects;
IEnumerable<HitObject> circles = hitObjects.Where(c => !(c is IHasEndTime));
IEnumerable<HitObject> sliders = hitObjects.Where(s => s is IHasCurve);
IEnumerable<HitObject> spinners = hitObjects.Where(s => s is IHasEndTime && !(s is IHasCurve));
return new[]
{ {
new BeatmapStatistic new BeatmapStatistic
{ {
Name = @"Circle count", Name = @"Circle Count",
Content = beatmap.Beatmap.HitObjects.Count(h => h is HitCircle).ToString(), Content = circles.Count().ToString(),
Icon = FontAwesome.fa_dot_circle_o Icon = FontAwesome.fa_circle_o
}, },
new BeatmapStatistic new BeatmapStatistic
{ {
Name = @"Slider count", Name = @"Slider Count",
Content = beatmap.Beatmap.HitObjects.Count(h => h is Slider).ToString(), Content = sliders.Count().ToString(),
Icon = FontAwesome.fa_circle_o Icon = FontAwesome.fa_circle
},
new BeatmapStatistic
{
Name = @"Spinner Count",
Content = spinners.Count().ToString(),
Icon = FontAwesome.fa_circle
} }
}; };
}
public override IEnumerable<Mod> GetModsFor(ModType type) public override IEnumerable<Mod> GetModsFor(ModType type)
{ {
@ -124,6 +139,8 @@ namespace osu.Game.Rulesets.Osu
public override string Description => "osu!"; public override string Description => "osu!";
public override string ShortName => "osu";
public override SettingsSubsection CreateSettings() => new OsuSettings(); public override SettingsSubsection CreateSettings() => new OsuSettings();
public override int LegacyID => 0; public override int LegacyID => 0;

View File

@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{ {
internal class CursorTrail : Drawable internal class CursorTrail : Drawable
{ {
public override bool HandleInput => true;
private int currentIndex; private int currentIndex;
private Shader shader; private Shader shader;

View File

@ -123,7 +123,9 @@
<Private>True</Private> <Private>True</Private>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -95,6 +95,8 @@ namespace osu.Game.Rulesets.Taiko
public override string Description => "osu!taiko"; public override string Description => "osu!taiko";
public override string ShortName => "taiko";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap);

View File

@ -111,6 +111,9 @@
<Private>True</Private> <Private>True</Private>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -0,0 +1,69 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual
{
internal class TestCaseBeatmapInfoWedge : OsuTestCase
{
private BeatmapManager beatmaps;
private readonly Random random;
private readonly BeatmapInfoWedge infoWedge;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
public TestCaseBeatmapInfoWedge()
{
random = new Random(0123);
Add(infoWedge = new BeatmapInfoWedge
{
Size = new Vector2(0.5f, 245),
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding
{
Top = 20,
},
});
AddStep("show", () =>
{
Content.FadeInFromZero(250);
infoWedge.State = Visibility.Visible;
infoWedge.UpdateBeatmap(beatmap);
});
AddStep("hide", () =>
{
infoWedge.State = Visibility.Hidden;
Content.FadeOut(100);
});
AddStep("random beatmap", randomBeatmap);
AddStep("null beatmap", () => infoWedge.UpdateBeatmap(beatmap.Default));
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game, BeatmapManager beatmaps)
{
this.beatmaps = beatmaps;
beatmap.BindTo(game.Beatmap);
}
private void randomBeatmap()
{
var sets = beatmaps.GetAllUsableBeatmapSets();
if (sets.Count == 0)
return;
var b = sets[random.Next(0, sets.Count)].Beatmaps[0];
beatmap.Value = beatmaps.GetWorkingBeatmap(b);
infoWedge.UpdateBeatmap(beatmap);
}
}
}

View File

@ -0,0 +1,47 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Historical;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
{
internal class TestCaseHistoricalSection : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes =>
new[]
{
typeof(HistoricalSection),
typeof(PaginatedMostPlayedBeatmapContainer),
typeof(DrawableMostPlayedRow),
typeof(DrawableProfileRow)
};
public TestCaseHistoricalSection()
{
HistoricalSection section;
Add(new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.2f)
});
Add(new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = section = new HistoricalSection(),
});
AddStep("Show peppy", () => section.User.Value = new User { Id = 2 });
AddStep("Show WubWoofWolf", () => section.User.Value = new User { Id = 39828 });
}
}
}

View File

@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual
{ {
internal class TestCaseUserRanks : OsuTestCase internal class TestCaseUserRanks : OsuTestCase
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableScore), typeof(RanksSection) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableProfileScore), typeof(RanksSection) };
public TestCaseUserRanks() public TestCaseUserRanks()
{ {

View File

@ -90,6 +90,7 @@
<Compile Include="Beatmaps\Formats\LegacyBeatmapDecoderTest.cs" /> <Compile Include="Beatmaps\Formats\LegacyBeatmapDecoderTest.cs" />
<Compile Include="Visual\TestCaseBeatmapDetailArea.cs" /> <Compile Include="Visual\TestCaseBeatmapDetailArea.cs" />
<Compile Include="Visual\TestCaseBeatmapDetails.cs" /> <Compile Include="Visual\TestCaseBeatmapDetails.cs" />
<Compile Include="Visual\TestCaseBeatmapInfoWedge.cs" />
<Compile Include="Visual\TestCaseBeatmapOptionsOverlay.cs" /> <Compile Include="Visual\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Visual\TestCaseBeatmapScoresContainer.cs" /> <Compile Include="Visual\TestCaseBeatmapScoresContainer.cs" />
<Compile Include="Visual\TestCaseBeatmapSetOverlay.cs" /> <Compile Include="Visual\TestCaseBeatmapSetOverlay.cs" />
@ -110,6 +111,7 @@
<Compile Include="Visual\TestCaseEditorSummaryTimeline.cs" /> <Compile Include="Visual\TestCaseEditorSummaryTimeline.cs" />
<Compile Include="Visual\TestCaseGamefield.cs" /> <Compile Include="Visual\TestCaseGamefield.cs" />
<Compile Include="Visual\TestCaseGraph.cs" /> <Compile Include="Visual\TestCaseGraph.cs" />
<Compile Include="Visual\TestCaseHistoricalSection.cs" />
<Compile Include="Visual\TestCaseIconButton.cs" /> <Compile Include="Visual\TestCaseIconButton.cs" />
<Compile Include="Visual\TestCaseIntroSequence.cs" /> <Compile Include="Visual\TestCaseIntroSequence.cs" />
<Compile Include="Visual\TestCaseKeyConfiguration.cs" /> <Compile Include="Visual\TestCaseKeyConfiguration.cs" />

View File

@ -115,6 +115,7 @@ namespace osu.Game.Beatmaps
// Metadata // Metadata
public string Version { get; set; } public string Version { get; set; }
[JsonProperty("difficulty_rating")]
public double StarDifficulty { get; set; } public double StarDifficulty { get; set; }
public bool Equals(BeatmapInfo other) public bool Equals(BeatmapInfo other)

View File

@ -497,8 +497,13 @@ namespace osu.Game.Beatmaps
using (var stream = new StreamReader(reader.GetStream(mapName))) using (var stream = new StreamReader(reader.GetStream(mapName)))
metadata = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; metadata = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata;
// check if a set already exists with the same online id. // check if a set already exists with the same online id.
beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) ?? new BeatmapSetInfo if (metadata.OnlineBeatmapSetID != null)
beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID);
if (beatmapSet == null)
beatmapSet = new BeatmapSetInfo
{ {
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
Beatmaps = new List<BeatmapInfo>(), Beatmaps = new List<BeatmapInfo>(),
@ -507,6 +512,7 @@ namespace osu.Game.Beatmaps
Metadata = metadata Metadata = metadata
}; };
var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu")); var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu"));
foreach (var name in mapNames) foreach (var name in mapNames)
@ -525,11 +531,12 @@ namespace osu.Game.Beatmaps
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID); var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || beatmap.BeatmapInfo.OnlineBeatmapID != null && b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID);
if (existing == null) if (existing == null)
{ {
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary // Exclude beatmap-metadata if it's equal to beatmapset-metadata
if (metadata.Equals(beatmap.Metadata))
beatmap.BeatmapInfo.Metadata = null; beatmap.BeatmapInfo.Metadata = null;
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
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;
@ -9,7 +10,7 @@ using osu.Game.Users;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public class BeatmapMetadata public class BeatmapMetadata : IEquatable<BeatmapMetadata>
{ {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; } public int ID { get; set; }
@ -66,5 +67,23 @@ namespace osu.Game.Beatmaps
Source, Source,
Tags Tags
}.Where(s => !string.IsNullOrEmpty(s)).ToArray(); }.Where(s => !string.IsNullOrEmpty(s)).ToArray();
public bool Equals(BeatmapMetadata other)
{
if (other == null)
return false;
return onlineBeatmapSetID == other.onlineBeatmapSetID
&& Title == other.Title
&& TitleUnicode == other.TitleUnicode
&& Artist == other.Artist
&& ArtistUnicode == other.ArtistUnicode
&& AuthorString == other.AuthorString
&& Source == other.Source
&& Tags == other.Tags
&& PreviewTime == other.PreviewTime
&& AudioFile == other.AudioFile
&& BackgroundFile == other.BackgroundFile;
}
} }
} }

View File

@ -32,6 +32,18 @@ namespace osu.Game.Beatmaps
{ {
var context = GetContext(); var context = GetContext();
foreach (var beatmap in beatmapSet.Beatmaps.Where(b => b.Metadata != null))
{
// If we detect a new metadata object it'll be attached to the current context so it can be reused
// to prevent duplicate entries when persisting. To accomplish this we look in the cache (.Local)
// of the corresponding table (.Set<BeatmapMetadata>()) for matching entries to our criteria.
var contextMetadata = context.Set<BeatmapMetadata>().Local.SingleOrDefault(e => e.Equals(beatmap.Metadata));
if (contextMetadata != null)
beatmap.Metadata = contextMetadata;
else
context.BeatmapMetadata.Attach(beatmap.Metadata);
}
context.BeatmapSetInfo.Attach(beatmapSet); context.BeatmapSetInfo.Attach(beatmapSet);
context.SaveChanges(); context.SaveChanges();

View File

@ -40,19 +40,31 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapSetInfo BeatmapSet; public BeatmapSetInfo BeatmapSet;
private BeatmapGroupState state; private BeatmapGroupState state;
public BeatmapGroupState State public BeatmapGroupState State
{ {
get { return state; } get { return state; }
set set
{ {
state = value; state = value;
UpdateState();
StateChanged?.Invoke(state);
}
}
switch (value) public void UpdateState()
{
switch (state)
{ {
case BeatmapGroupState.Expanded: case BeatmapGroupState.Expanded:
Header.State = PanelSelectedState.Selected; Header.State = PanelSelectedState.Selected;
foreach (BeatmapPanel panel in BeatmapPanels) foreach (BeatmapPanel panel in BeatmapPanels)
panel.State = panel == SelectedPanel ? PanelSelectedState.Selected : PanelSelectedState.NotSelected; if (panel == SelectedPanel)
panel.State = PanelSelectedState.Selected;
else if (panel.Filtered)
panel.State = PanelSelectedState.Hidden;
else
panel.State = PanelSelectedState.NotSelected;
break; break;
case BeatmapGroupState.Collapsed: case BeatmapGroupState.Collapsed:
Header.State = PanelSelectedState.NotSelected; Header.State = PanelSelectedState.NotSelected;
@ -65,9 +77,6 @@ namespace osu.Game.Beatmaps.Drawables
panel.State = PanelSelectedState.Hidden; panel.State = PanelSelectedState.Hidden;
break; break;
} }
StateChanged?.Invoke(state);
}
} }
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager) public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager)
@ -88,7 +97,7 @@ namespace osu.Game.Beatmaps.Drawables
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}; };
BeatmapPanels = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.StarDifficulty).Select(b => new BeatmapPanel(b) BeatmapPanels = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.RulesetID).ThenBy(b => b.StarDifficulty).Select(b => new BeatmapPanel(b)
{ {
Alpha = 0, Alpha = 0,
GainedSelection = panelGainedSelection, GainedSelection = panelGainedSelection,
@ -108,7 +117,7 @@ namespace osu.Game.Beatmaps.Drawables
//we want to make sure one of our children is selected in the case none have been selected yet. //we want to make sure one of our children is selected in the case none have been selected yet.
if (SelectedPanel == null) if (SelectedPanel == null)
BeatmapPanels.First().State = PanelSelectedState.Selected; BeatmapPanels.First(p => !p.Filtered).State = PanelSelectedState.Selected;
} }
private void panelGainedSelection(BeatmapPanel panel) private void panelGainedSelection(BeatmapPanel panel)

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -61,6 +62,8 @@ namespace osu.Game.Beatmaps.Drawables
return base.OnClick(state); return base.OnClick(state);
} }
public BindableBool Filtered = new BindableBool();
protected override void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden) protected override void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden)
{ {
if (!IsLoaded) return; if (!IsLoaded) return;

View File

@ -11,21 +11,44 @@ namespace osu.Game.Beatmaps.Drawables
public class BeatmapSetCover : Sprite public class BeatmapSetCover : Sprite
{ {
private readonly BeatmapSetInfo set; private readonly BeatmapSetInfo set;
public BeatmapSetCover(BeatmapSetInfo set) private readonly BeatmapSetCoverType type;
public BeatmapSetCover(BeatmapSetInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover)
{ {
if (set == null) if (set == null)
throw new ArgumentNullException(nameof(set)); throw new ArgumentNullException(nameof(set));
this.set = set; this.set = set;
this.type = type;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(TextureStore textures) private void load(TextureStore textures)
{ {
string resource = set.OnlineInfo.Covers.Cover; string resource = null;
switch (type)
{
case BeatmapSetCoverType.Cover:
resource = set.OnlineInfo.Covers.Cover;
break;
case BeatmapSetCoverType.Card:
resource = set.OnlineInfo.Covers.Card;
break;
case BeatmapSetCoverType.List:
resource = set.OnlineInfo.Covers.List;
break;
}
if (resource != null) if (resource != null)
Texture = textures.Get(resource); Texture = textures.Get(resource);
} }
} }
public enum BeatmapSetCoverType
{
Cover,
Card,
List,
}
} }

View File

@ -7,6 +7,7 @@ using System.Linq;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -157,8 +158,7 @@ namespace osu.Game.Beatmaps.Drawables
if (panels == null) if (panels == null)
throw new ArgumentNullException(nameof(panels)); throw new ArgumentNullException(nameof(panels));
foreach (var p in panels) difficultyIcons.AddRange(panels.Select(p => new FilterableDifficultyIcon(p)));
difficultyIcons.Add(new DifficultyIcon(p.Beatmap));
} }
public MenuItem[] ContextMenuItems public MenuItem[] ContextMenuItems
@ -178,5 +178,18 @@ namespace osu.Game.Beatmaps.Drawables
return items.ToArray(); return items.ToArray();
} }
} }
public class FilterableDifficultyIcon : DifficultyIcon
{
private readonly BindableBool filtered = new BindableBool();
public FilterableDifficultyIcon(BeatmapPanel panel)
: base(panel.Beatmap)
{
filtered.BindTo(panel.Filtered);
filtered.ValueChanged += v => this.FadeTo(v ? 0.1f : 1, 100);
filtered.TriggerChange();
}
}
} }
} }

View File

@ -63,6 +63,8 @@ namespace osu.Game.Beatmaps
public override string Description => "dummy"; public override string Description => "dummy";
public override string ShortName => "dummy";
public DummyRuleset(RulesetInfo rulesetInfo) public DummyRuleset(RulesetInfo rulesetInfo)
: base(rulesetInfo) : base(rulesetInfo)
{ {

View File

@ -93,6 +93,7 @@ namespace osu.Game.Database
modelBuilder.Entity<FileInfo>().HasIndex(b => b.ReferenceCount); modelBuilder.Entity<FileInfo>().HasIndex(b => b.ReferenceCount);
modelBuilder.Entity<RulesetInfo>().HasIndex(b => b.Available); modelBuilder.Entity<RulesetInfo>().HasIndex(b => b.Available);
modelBuilder.Entity<RulesetInfo>().HasIndex(b => b.ShortName).IsUnique();
modelBuilder.Entity<BeatmapInfo>().HasOne(b => b.BaseDifficulty); modelBuilder.Entity<BeatmapInfo>().HasOne(b => b.BaseDifficulty);
} }

View File

@ -0,0 +1,307 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using osu.Game.Database;
using System;
namespace osu.Game.Migrations
{
[DbContext(typeof(OsuDbContext))]
[Migration("20171209034410_AddRulesetInfoShortName")]
partial class AddRulesetInfoShortName
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<float>("ApproachRate");
b.Property<float>("CircleSize");
b.Property<float>("DrainRate");
b.Property<float>("OverallDifficulty");
b.Property<float>("SliderMultiplier");
b.Property<float>("SliderTickRate");
b.HasKey("ID");
b.ToTable("BeatmapDifficulty");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("AudioLeadIn");
b.Property<int>("BaseDifficultyID");
b.Property<int>("BeatDivisor");
b.Property<int>("BeatmapSetInfoID");
b.Property<bool>("Countdown");
b.Property<double>("DistanceSpacing");
b.Property<int>("GridSize");
b.Property<string>("Hash");
b.Property<bool>("Hidden");
b.Property<bool>("LetterboxInBreaks");
b.Property<string>("MD5Hash");
b.Property<int?>("MetadataID");
b.Property<int?>("OnlineBeatmapID");
b.Property<string>("Path");
b.Property<int>("RulesetID");
b.Property<bool>("SpecialStyle");
b.Property<float>("StackLeniency");
b.Property<double>("StarDifficulty");
b.Property<string>("StoredBookmarks");
b.Property<double>("TimelineZoom");
b.Property<string>("Version");
b.Property<bool>("WidescreenStoryboard");
b.HasKey("ID");
b.HasIndex("BaseDifficultyID");
b.HasIndex("BeatmapSetInfoID");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("MD5Hash")
.IsUnique();
b.HasIndex("MetadataID");
b.HasIndex("OnlineBeatmapID")
.IsUnique();
b.HasIndex("RulesetID");
b.ToTable("BeatmapInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Artist");
b.Property<string>("ArtistUnicode");
b.Property<string>("AudioFile");
b.Property<string>("AuthorString")
.HasColumnName("Author");
b.Property<string>("BackgroundFile");
b.Property<int>("PreviewTime");
b.Property<string>("Source");
b.Property<string>("Tags");
b.Property<string>("Title");
b.Property<string>("TitleUnicode");
b.HasKey("ID");
b.ToTable("BeatmapMetadata");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("BeatmapSetInfoID");
b.Property<int>("FileInfoID");
b.Property<string>("Filename")
.IsRequired();
b.HasKey("ID");
b.HasIndex("BeatmapSetInfoID");
b.HasIndex("FileInfoID");
b.ToTable("BeatmapSetFileInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<bool>("DeletePending");
b.Property<string>("Hash");
b.Property<int?>("MetadataID");
b.Property<int?>("OnlineBeatmapSetID");
b.Property<bool>("Protected");
b.HasKey("ID");
b.HasIndex("DeletePending");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("MetadataID");
b.HasIndex("OnlineBeatmapSetID")
.IsUnique();
b.ToTable("BeatmapSetInfo");
});
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("IntAction")
.HasColumnName("Action");
b.Property<string>("KeysString")
.HasColumnName("Keys");
b.Property<int?>("RulesetID");
b.Property<int?>("Variant");
b.HasKey("ID");
b.HasIndex("IntAction");
b.HasIndex("Variant");
b.ToTable("KeyBinding");
});
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Hash");
b.Property<int>("ReferenceCount");
b.HasKey("ID");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("ReferenceCount");
b.ToTable("FileInfo");
});
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
{
b.Property<int?>("ID")
.ValueGeneratedOnAdd();
b.Property<bool>("Available");
b.Property<string>("InstantiationInfo");
b.Property<string>("Name");
b.Property<string>("ShortName");
b.HasKey("ID");
b.HasIndex("Available");
b.HasIndex("ShortName")
.IsUnique();
b.ToTable("RulesetInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
.WithMany()
.HasForeignKey("BaseDifficultyID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
.WithMany("Beatmaps")
.HasForeignKey("BeatmapSetInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
.WithMany("Beatmaps")
.HasForeignKey("MetadataID");
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
.WithMany()
.HasForeignKey("RulesetID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
.WithMany("Files")
.HasForeignKey("BeatmapSetInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
.WithMany()
.HasForeignKey("FileInfoID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
.WithMany("BeatmapSets")
.HasForeignKey("MetadataID");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
namespace osu.Game.Migrations
{
public partial class AddRulesetInfoShortName : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ShortName",
table: "RulesetInfo",
type: "TEXT",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_RulesetInfo_ShortName",
table: "RulesetInfo",
column: "ShortName",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_RulesetInfo_ShortName",
table: "RulesetInfo");
migrationBuilder.DropColumn(
name: "ShortName",
table: "RulesetInfo");
}
}
}

View File

@ -247,10 +247,15 @@ namespace osu.Game.Migrations
b.Property<string>("Name"); b.Property<string>("Name");
b.Property<string>("ShortName");
b.HasKey("ID"); b.HasKey("ID");
b.HasIndex("Available"); b.HasIndex("Available");
b.HasIndex("ShortName")
.IsUnique();
b.ToTable("RulesetInfo"); b.ToTable("RulesetInfo");
}); });

View File

@ -10,7 +10,7 @@ using System;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
public class GetBeatmapSetsResponse : BeatmapMetadata // todo: this is a bit wrong... public class APIResponseBeatmapSet : BeatmapMetadata // todo: this is a bit wrong...
{ {
[JsonProperty(@"covers")] [JsonProperty(@"covers")]
private BeatmapSetOnlineCovers covers { get; set; } private BeatmapSetOnlineCovers covers { get; set; }
@ -45,7 +45,7 @@ namespace osu.Game.Online.API.Requests
} }
[JsonProperty(@"beatmaps")] [JsonProperty(@"beatmaps")]
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; } private IEnumerable<APIResponseBeatmap> beatmaps { get; set; }
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets) public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
{ {
@ -65,11 +65,11 @@ namespace osu.Game.Online.API.Requests
Ranked = ranked, Ranked = ranked,
LastUpdated = lastUpdated, LastUpdated = lastUpdated,
}, },
Beatmaps = beatmaps.Select(b => b.ToBeatmap(rulesets)).ToList(), Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
}; };
} }
private class GetBeatmapSetsBeatmapResponse : BeatmapMetadata private class APIResponseBeatmap : BeatmapMetadata
{ {
[JsonProperty(@"id")] [JsonProperty(@"id")]
private int onlineBeatmapID { get; set; } private int onlineBeatmapID { get; set; }

View File

@ -3,7 +3,7 @@
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
public class GetBeatmapSetRequest : APIRequest<GetBeatmapSetsResponse> public class GetBeatmapSetRequest : APIRequest<APIResponseBeatmapSet>
{ {
private readonly int beatmapSetId; private readonly int beatmapSetId;

View File

@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
public class GetUserBeatmapsRequest : APIRequest<List<GetBeatmapSetsResponse>> public class GetUserBeatmapsRequest : APIRequest<List<APIResponseBeatmapSet>>
{ {
private readonly long userId; private readonly long userId;
private readonly int offset; private readonly int offset;
@ -24,7 +24,6 @@ namespace osu.Game.Online.API.Requests
public enum BeatmapSetType public enum BeatmapSetType
{ {
MostPlayed,
Favourite, Favourite,
RankedAndApproved, RankedAndApproved,
Unranked, Unranked,

View File

@ -0,0 +1,48 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using System.Collections.Generic;
namespace osu.Game.Online.API.Requests
{
public class GetUserMostPlayedBeatmapsRequest : APIRequest<List<MostPlayedBeatmap>>
{
private readonly long userId;
private readonly int offset;
public GetUserMostPlayedBeatmapsRequest(long userId, int offset = 0)
{
this.userId = userId;
this.offset = offset;
}
protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}";
}
public class MostPlayedBeatmap
{
[JsonProperty("beatmap_id")]
public int BeatmapID;
[JsonProperty("count")]
public int PlayCount;
[JsonProperty]
private BeatmapInfo beatmap;
[JsonProperty]
private APIResponseBeatmapSet beatmapSet;
public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets)
{
BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets);
beatmap.BeatmapSet = setInfo;
beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID;
beatmap.Metadata = setInfo.Metadata;
return beatmap;
}
}
}

View File

@ -9,7 +9,7 @@ using osu.Game.Rulesets;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
public class SearchBeatmapSetsRequest : APIRequest<IEnumerable<GetBeatmapSetsResponse>> public class SearchBeatmapSetsRequest : APIRequest<IEnumerable<APIResponseBeatmapSet>>
{ {
private readonly string query; private readonly string query;
private readonly RulesetInfo ruleset; private readonly RulesetInfo ruleset;

View File

@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Direct
{ {
base.Update(); base.Update();
if (PreviewPlaying && Preview != null) if (PreviewPlaying && Preview != null && Preview.IsLoaded)
{ {
PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length); PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length);
} }

View File

@ -105,6 +105,7 @@ namespace osu.Game.Overlays.Direct
public enum DirectSortCriteria public enum DirectSortCriteria
{ {
Relevance,
Title, Title,
Artist, Artist,
Creator, Creator,

View File

@ -43,6 +43,7 @@ namespace osu.Game.Overlays
protected override SearchableListFilterControl<DirectSortCriteria, RankStatus> CreateFilterControl() => new FilterControl(); protected override SearchableListFilterControl<DirectSortCriteria, RankStatus> CreateFilterControl() => new FilterControl();
private IEnumerable<BeatmapSetInfo> beatmapSets; private IEnumerable<BeatmapSetInfo> beatmapSets;
public IEnumerable<BeatmapSetInfo> BeatmapSets public IEnumerable<BeatmapSetInfo> BeatmapSets
{ {
get { return beatmapSets; } get { return beatmapSets; }
@ -69,6 +70,7 @@ namespace osu.Game.Overlays
} }
private ResultCounts resultAmounts; private ResultCounts resultAmounts;
public ResultCounts ResultAmounts public ResultCounts ResultAmounts
{ {
get { return resultAmounts; } get { return resultAmounts; }
@ -115,7 +117,23 @@ namespace osu.Game.Overlays
}, },
}; };
Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; }; Filter.Search.Current.ValueChanged += text =>
{
if (text != string.Empty)
{
Header.Tabs.Current.Value = DirectTab.Search;
if (Filter.Tabs.Current.Value == DirectSortCriteria.Ranked)
Filter.Tabs.Current.Value = DirectSortCriteria.Relevance;
}
else
{
Header.Tabs.Current.Value = DirectTab.NewestMaps;
if (Filter.Tabs.Current.Value == DirectSortCriteria.Relevance)
Filter.Tabs.Current.Value = DirectSortCriteria.Ranked;
}
};
((FilterControl)Filter).Ruleset.ValueChanged += ruleset => Scheduler.AddOnce(updateSearch); ((FilterControl)Filter).Ruleset.ValueChanged += ruleset => Scheduler.AddOnce(updateSearch);
Filter.DisplayStyleControl.DisplayStyle.ValueChanged += recreatePanels; Filter.DisplayStyleControl.DisplayStyle.ValueChanged += recreatePanels;
Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += rankStatus => Scheduler.AddOnce(updateSearch); Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += rankStatus => Scheduler.AddOnce(updateSearch);

View File

@ -251,7 +251,7 @@ namespace osu.Game.Overlays
playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o;
if (track.HasCompleted && !beatmapBacking.Disabled && playlist.BeatmapSets.Any()) if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled && playlist.BeatmapSets.Any())
next(); next();
} }
else else

View File

@ -81,12 +81,12 @@ namespace osu.Game.Overlays.Profile
{ {
rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank";
performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty; performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty;
relativeText.Text = $"{user.Country?.FullName} #{user.CountryRank:#,0}"; relativeText.Text = user.CountryRank > 0 ? $"{user.Country?.FullName} #{user.CountryRank:#,0}" : $"{user.Country?.FullName}";
} }
private void showHistoryRankTexts(int dayIndex) private void showHistoryRankTexts(int dayIndex)
{ {
rankText.Text = $"#{ranks[dayIndex]:#,0}"; rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank";
dayIndex++; dayIndex++;
relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago"; relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago";
//plural should be handled in a general way //plural should be handled in a general way
@ -99,7 +99,7 @@ namespace osu.Game.Overlays.Profile
{ {
graph.Colour = colours.Yellow; graph.Colour = colours.Yellow;
// use logarithmic coordinates // use logarithmic coordinates
graph.Values = ranks.Select(x => -(float)Math.Log(x)); graph.Values = ranks.Select(x => x == 0 ? float.MinValue : -(float)Math.Log(x));
graph.SetStaticBallPosition(); graph.SetStaticBallPosition();
} }

View File

@ -0,0 +1,63 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Sections
{
/// <summary>
/// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row (see <see cref="DrawableProfileRow"/>).
/// </summary>
public class BeatmapMetadataContainer : OsuHoverContainer, IHasTooltip
{
private readonly BeatmapInfo beatmap;
public BeatmapMetadataContainer(BeatmapInfo beatmap)
{
this.beatmap = beatmap;
AutoSizeAxes = Axes.Both;
TooltipText = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title}";
}
public string TooltipText { get; }
[BackgroundDependencyLoader(true)]
private void load(LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay)
{
Action = () =>
{
if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value);
};
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new OsuSpriteText
{
Current = locale.GetUnicodePreference(
$"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
$"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] "
),
TextSize = 15,
Font = "Exo2.0-SemiBoldItalic",
},
new OsuSpriteText
{
Current = locale.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist),
TextSize = 12,
Padding = new MarginPadding { Top = 3 },
Font = "Exo2.0-RegularItalic",
},
},
};
}
}
}

View File

@ -0,0 +1,124 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Overlays.Profile.Sections
{
public abstract class DrawableProfileRow : Container
{
private const int fade_duration = 200;
private Box underscoreLine;
private readonly Box coloredBackground;
private readonly Container background;
/// <summary>
/// A visual element displayed to the left of <see cref="LeftFlowContainer"/> content.
/// </summary>
protected abstract Drawable CreateLeftVisual();
protected FillFlowContainer LeftFlowContainer { get; private set; }
protected FillFlowContainer RightFlowContainer { get; private set; }
protected override Container<Drawable> Content { get; }
protected DrawableProfileRow()
{
RelativeSizeAxes = Axes.X;
Height = 60;
InternalChildren = new Drawable[]
{
background = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 3,
Alpha = 0,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
Radius = 1f,
Colour = Color4.Black.Opacity(0.2f),
},
Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
},
Content = new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 0.97f,
},
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
{
AddRange(new Drawable[]
{
underscoreLine = new Box
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
Height = 1,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
CreateLeftVisual(),
LeftFlowContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 10 },
Direction = FillDirection.Vertical,
},
}
},
RightFlowContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Vertical,
},
});
coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
}
protected override bool OnClick(InputState state) => true;
protected override bool OnHover(InputState state)
{
background.FadeIn(fade_duration, Easing.OutQuint);
underscoreLine.FadeOut(fade_duration, Easing.OutQuint);
return true;
}
protected override void OnHoverLost(InputState state)
{
background.FadeOut(fade_duration, Easing.OutQuint);
underscoreLine.FadeIn(fade_duration, Easing.OutQuint);
base.OnHoverLost(state);
}
}
}

View File

@ -0,0 +1,105 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Overlays.Profile.Sections.Historical
{
public class DrawableMostPlayedRow : DrawableProfileRow
{
private readonly BeatmapInfo beatmap;
private readonly int playCount;
private OsuHoverContainer mapperContainer;
public DrawableMostPlayedRow(BeatmapInfo beatmap, int playCount)
{
this.beatmap = beatmap;
this.playCount = playCount;
}
protected override Drawable CreateLeftVisual() => new DelayedLoadWrapper(new BeatmapSetCover(beatmap.BeatmapSet, BeatmapSetCoverType.List)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fit,
RelativeSizeAxes = Axes.Both,
OnLoadComplete = d => d.FadeInFromZero(500, Easing.OutQuint)
})
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
RelativeSizeAxes = Axes.None,
Size = new Vector2(80, 50),
};
[BackgroundDependencyLoader(true)]
private void load(UserProfileOverlay profileOverlay)
{
LeftFlowContainer.Add(new BeatmapMetadataContainer(beatmap));
LeftFlowContainer.Add(new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
new OsuSpriteText
{
Text = @"mapped by ",
TextSize = 12,
},
mapperContainer = new OsuHoverContainer
{
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new OsuSpriteText
{
Text = beatmap.Metadata.AuthorString,
TextSize = 12,
Font = @"Exo2.0-MediumItalic"
}
}
},
}
});
RightFlowContainer.Add(new FillFlowContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Text = playCount.ToString(),
TextSize = 18,
Font = @"Exo2.0-SemiBoldItalic"
},
new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Text = @"times played ",
TextSize = 12,
Font = @"Exo2.0-RegularItalic"
},
}
});
if (profileOverlay != null)
mapperContainer.Action = () => profileOverlay.ShowUser(beatmap.BeatmapSet.Metadata.Author);
}
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Sections.Historical
{
public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer
{
public PaginatedMostPlayedBeatmapContainer(Bindable<User> user)
:base(user, "Most Played Beatmaps", "No records. :(")
{
ItemsPerPage = 5;
ItemsContainer.Direction = FillDirection.Vertical;
}
protected override void ShowMore()
{
base.ShowMore();
var req = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++ * ItemsPerPage);
req.Success += beatmaps =>
{
ShowMoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0);
ShowMoreLoading.Hide();
if (!beatmaps.Any() && VisiblePages == 1)
{
MissingText.Show();
return;
}
MissingText.Hide();
foreach (var beatmap in beatmaps)
{
ItemsContainer.Add(new DrawableMostPlayedRow(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount));
}
};
Api.Queue(req);
}
}
}

View File

@ -1,7 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile.Sections.Historical;
using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Overlays.Profile.Sections.Ranks;
namespace osu.Game.Overlays.Profile.Sections namespace osu.Game.Overlays.Profile.Sections
@ -14,7 +16,11 @@ namespace osu.Game.Overlays.Profile.Sections
public HistoricalSection() public HistoricalSection()
{ {
Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", "No performance records. :("); Children = new Drawable[]
{
new PaginatedMostPlayedBeatmapContainer(User),
new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", "No performance records. :("),
};
} }
} }
} }

View File

@ -9,7 +9,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Overlays.Profile.Sections.Ranks namespace osu.Game.Overlays.Profile.Sections.Ranks
{ {
public class DrawablePerformanceScore : DrawableScore public class DrawablePerformanceScore : DrawableProfileScore
{ {
private readonly double? weight; private readonly double? weight;
@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
private void load(OsuColour colour) private void load(OsuColour colour)
{ {
double pp = Score.PP ?? 0; double pp = Score.PP ?? 0;
Stats.Add(new OsuSpriteText RightFlowContainer.Add(new OsuSpriteText
{ {
Text = $"{pp:0}pp", Text = $"{pp:0}pp",
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
if (weight.HasValue) if (weight.HasValue)
{ {
Stats.Add(new OsuSpriteText RightFlowContainer.Add(new OsuSpriteText
{ {
Text = $"weighted: {pp * weight:0}pp ({weight:P0})", Text = $"weighted: {pp * weight:0}pp ({weight:P0})",
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,

View File

@ -0,0 +1,75 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public abstract class DrawableProfileScore : DrawableProfileRow
{
private readonly FillFlowContainer metadata;
private readonly ScoreModsContainer modsContainer;
protected readonly Score Score;
protected DrawableProfileScore(Score score)
{
Score = score;
RelativeSizeAxes = Axes.X;
Height = 60;
Children = new Drawable[]
{
modsContainer = new ScoreModsContainer
{
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Width = 60,
Margin = new MarginPadding { Right = 160 }
}
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
{
RightFlowContainer.Add(new OsuSpriteText
{
Text = $"accuracy: {Score.Accuracy:P2}",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Colour = colour.GrayA,
TextSize = 11,
Font = "Exo2.0-RegularItalic",
Depth = -1,
});
LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap));
LeftFlowContainer.Add(new OsuSpriteText
{
Text = Score.Date.LocalDateTime.ToShortDateString(),
TextSize = 11,
Colour = OsuColour.Gray(0xAA),
});
foreach (Mod mod in Score.Mods)
modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) });
}
protected override Drawable CreateLeftVisual() => new DrawableRank(Score.Rank)
{
RelativeSizeAxes = Axes.Y,
Width = 60,
FillMode = FillMode.Fit,
};
}
}

View File

@ -1,195 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select.Leaderboards;
using osu.Framework.Localisation;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public abstract class DrawableScore : Container
{
private const int fade_duration = 200;
protected readonly FillFlowContainer<OsuSpriteText> Stats;
private readonly FillFlowContainer metadata;
private readonly ScoreModsContainer modsContainer;
protected readonly Score Score;
private readonly Box underscoreLine;
private readonly Box coloredBackground;
private readonly Container background;
protected DrawableScore(Score score)
{
Score = score;
RelativeSizeAxes = Axes.X;
Height = 60;
Children = new Drawable[]
{
background = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 3,
Alpha = 0,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
Radius = 1f,
Colour = Color4.Black.Opacity(0.2f),
},
Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
},
new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 0.97f,
Children = new Drawable[]
{
underscoreLine = new Box
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
Height = 1,
},
new DrawableRank(score.Rank)
{
RelativeSizeAxes = Axes.Y,
Width = 60,
FillMode = FillMode.Fit,
},
Stats = new FillFlowContainer<OsuSpriteText>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Vertical,
},
metadata = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 70 },
Direction = FillDirection.Vertical,
Child = new OsuSpriteText
{
Text = score.Date.LocalDateTime.ToShortDateString(),
TextSize = 11,
Colour = OsuColour.Gray(0xAA),
Depth = -1,
},
},
modsContainer = new ScoreModsContainer
{
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Width = 60,
Margin = new MarginPadding { Right = 160 }
}
}
},
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay)
{
coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
Stats.Add(new OsuSpriteText
{
Text = $"accuracy: {Score.Accuracy:P2}",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Colour = colour.GrayA,
TextSize = 11,
Font = "Exo2.0-RegularItalic",
Depth = -1,
});
metadata.Add(new MetadataContainer(Score.Beatmap.Metadata.Title, Score.Beatmap.Metadata.Artist)
{
AutoSizeAxes = Axes.Both,
Action = () =>
{
if (Score.Beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(Score.Beatmap.OnlineBeatmapSetID.Value);
},
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new OsuSpriteText
{
Current = locale.GetUnicodePreference(
$"{Score.Beatmap.Metadata.TitleUnicode ?? Score.Beatmap.Metadata.Title} [{Score.Beatmap.Version}] ",
$"{Score.Beatmap.Metadata.Title ?? Score.Beatmap.Metadata.TitleUnicode} [{Score.Beatmap.Version}] "
),
TextSize = 15,
Font = "Exo2.0-SemiBoldItalic",
},
new OsuSpriteText
{
Current = locale.GetUnicodePreference(Score.Beatmap.Metadata.ArtistUnicode, Score.Beatmap.Metadata.Artist),
TextSize = 12,
Padding = new MarginPadding { Top = 3 },
Font = "Exo2.0-RegularItalic",
},
},
},
});
foreach (Mod mod in Score.Mods)
modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) });
}
protected override bool OnClick(InputState state) => true;
protected override bool OnHover(InputState state)
{
background.FadeIn(fade_duration, Easing.OutQuint);
underscoreLine.FadeOut(fade_duration, Easing.OutQuint);
return true;
}
protected override void OnHoverLost(InputState state)
{
background.FadeOut(fade_duration, Easing.OutQuint);
underscoreLine.FadeIn(fade_duration, Easing.OutQuint);
base.OnHoverLost(state);
}
private class MetadataContainer : OsuHoverContainer, IHasTooltip
{
public string TooltipText { get; set; }
public MetadataContainer(string title, string artist)
{
TooltipText = $"{artist} - {title}";
}
}
}
}

View File

@ -8,7 +8,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Overlays.Profile.Sections.Ranks namespace osu.Game.Overlays.Profile.Sections.Ranks
{ {
public class DrawableTotalScore : DrawableScore public class DrawableTotalScore : DrawableProfileScore
{ {
public DrawableTotalScore(Score score) public DrawableTotalScore(Score score)
: base(score) : base(score)
@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Stats.Add(new OsuSpriteText RightFlowContainer.Add(new OsuSpriteText
{ {
Text = Score.TotalScore.ToString("#,###"), Text = Score.TotalScore.ToString("#,###"),
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,

View File

@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
foreach (OnlineScore score in scores) foreach (OnlineScore score in scores)
{ {
DrawableScore drawableScore; DrawableProfileScore drawableScore;
switch (type) switch (type)
{ {

View File

@ -159,8 +159,6 @@ namespace osu.Game.Overlays.Settings
public string TooltipText => "Revert to default"; public string TooltipText => "Revert to default";
public override bool HandleInput => true;
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => true; protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => true;

View File

@ -23,13 +23,12 @@ namespace osu.Game.Rulesets
public virtual IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { }; public virtual IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { };
public IEnumerable<Mod> GetAllMods() => Enum.GetValues(typeof(ModType)).Cast<ModType>() public IEnumerable<Mod> GetAllMods() => Enum.GetValues(typeof(ModType)).Cast<ModType>()
// Get all mod types as an IEnumerable<ModType>
.SelectMany(GetModsFor)
// Confine all mods of each mod type into a single IEnumerable<Mod> // Confine all mods of each mod type into a single IEnumerable<Mod>
.Where(mod => mod != null) .SelectMany(GetModsFor)
// Filter out all null mods // Filter out all null mods
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); .Where(mod => mod != null)
// Resolve MultiMods as their .Mods property // Resolve MultiMods as their .Mods property
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
public abstract IEnumerable<Mod> GetModsFor(ModType type); public abstract IEnumerable<Mod> GetModsFor(ModType type);
@ -66,6 +65,11 @@ namespace osu.Game.Rulesets
/// </summary> /// </summary>
public virtual int LegacyID => -1; public virtual int LegacyID => -1;
/// <summary>
/// A unique short name to reference this ruleset in online requests.
/// </summary>
public abstract string ShortName { get; }
/// <summary> /// <summary>
/// A list of available variant ids. /// A list of available variant ids.
/// </summary> /// </summary>

View File

@ -13,6 +13,8 @@ namespace osu.Game.Rulesets
public string Name { get; set; } public string Name { get; set; }
public string ShortName { get; set; }
public string InstantiationInfo { get; set; } public string InstantiationInfo { get; set; }
public bool Available { get; set; } public bool Available { get; set; }

View File

@ -83,7 +83,11 @@ namespace osu.Game.Rulesets
{ {
try try
{ {
r.CreateInstance(); var instance = r.CreateInstance();
r.Name = instance.Description;
r.ShortName = instance.ShortName;
r.Available = true; r.Available = true;
} }
catch catch
@ -117,6 +121,7 @@ namespace osu.Game.Rulesets
private RulesetInfo createRulesetInfo(Ruleset ruleset) => new RulesetInfo private RulesetInfo createRulesetInfo(Ruleset ruleset) => new RulesetInfo
{ {
Name = ruleset.Description, Name = ruleset.Description,
ShortName = ruleset.ShortName,
InstantiationInfo = ruleset.GetType().AssemblyQualifiedName, InstantiationInfo = ruleset.GetType().AssemblyQualifiedName,
ID = ruleset.LegacyID ID = ruleset.LegacyID
}; };

View File

@ -16,8 +16,6 @@ namespace osu.Game.Screens.Play.HUD
public bool ReplayLoaded; public bool ReplayLoaded;
public override bool HandleInput => true;
public readonly PlaybackSettings PlaybackSettings; public readonly PlaybackSettings PlaybackSettings;
//public readonly CollectionSettings CollectionSettings; //public readonly CollectionSettings CollectionSettings;
//public readonly DiscussionSettings DiscussionSettings; //public readonly DiscussionSettings DiscussionSettings;

View File

@ -141,8 +141,6 @@ namespace osu.Game.Screens.Play
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
public override bool HandleInput => true;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyDown(state, args)); protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyDown(state, args));
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyUp(state, args)); protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyUp(state, args));

View File

@ -34,7 +34,6 @@ namespace osu.Game.Screens.Select
public IEnumerable<BeatmapSetInfo> Beatmaps public IEnumerable<BeatmapSetInfo> Beatmaps
{ {
get { return groups.Select(g => g.BeatmapSet); } get { return groups.Select(g => g.BeatmapSet); }
set set
{ {
scrollableContent.Clear(false); scrollableContent.Clear(false);
@ -52,7 +51,7 @@ namespace osu.Game.Screens.Select
Schedule(() => Schedule(() =>
{ {
foreach (var g in newGroups) foreach (var g in newGroups)
if (g != null) addGroup(g); addGroup(g);
computeYPositions(); computeYPositions();
BeatmapsChanged?.Invoke(); BeatmapsChanged?.Invoke();
@ -95,50 +94,31 @@ namespace osu.Game.Screens.Select
}); });
} }
public void AddBeatmap(BeatmapSetInfo beatmapSet)
{
Schedule(() =>
{
var group = createGroup(beatmapSet);
if (group == null)
return;
addGroup(group);
computeYPositions();
if (selectedGroup == null)
selectGroup(group);
});
}
public void RemoveBeatmap(BeatmapSetInfo beatmapSet) public void RemoveBeatmap(BeatmapSetInfo beatmapSet)
{ {
Schedule(() => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID))); Schedule(() => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID)));
} }
public void UpdateBeatmap(BeatmapInfo beatmap) public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet)
{ {
// todo: this method should not run more than once for the same BeatmapSetInfo.
var set = manager.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID);
// todo: this method should be smarter as to not recreate panels that haven't changed, etc. // todo: this method should be smarter as to not recreate panels that haven't changed, etc.
var group = groups.Find(b => b.BeatmapSet.ID == set.ID); var oldGroup = groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID);
int i = groups.IndexOf(group); var newGroup = createGroup(beatmapSet);
if (i >= 0)
groups.RemoveAt(i);
var newGroup = createGroup(set); int index = groups.IndexOf(oldGroup);
if (index >= 0)
groups.RemoveAt(index);
if (newGroup != null) if (newGroup != null)
{ {
if (i >= 0) if (index >= 0)
groups.Insert(i, newGroup); groups.Insert(index, newGroup);
else else
groups.Add(newGroup); addGroup(newGroup);
} }
bool hadSelection = selectedGroup == group; bool hadSelection = selectedGroup == oldGroup;
if (hadSelection && newGroup == null) if (hadSelection && newGroup == null)
selectedGroup = null; selectedGroup = null;
@ -149,8 +129,10 @@ namespace osu.Game.Screens.Select
if (hadSelection && newGroup != null) if (hadSelection && newGroup != null)
{ {
var newSelection = var newSelection =
newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID) ?? newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID);
newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, group.BeatmapPanels.IndexOf(selectedPanel))];
if (newSelection == null && oldGroup != null && selectedPanel != null)
newSelection = newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, oldGroup.BeatmapPanels.IndexOf(selectedPanel))];
selectGroup(newGroup, newSelection); selectGroup(newGroup, newSelection);
} }
@ -196,42 +178,62 @@ namespace osu.Game.Screens.Select
SelectionChanged?.Invoke(null); SelectionChanged?.Invoke(null);
} }
/// <summary>
/// Increment selection in the carousel in a chosen direction.
/// </summary>
/// <param name="direction">The direction to increment. Negative is backwards.</param>
/// <param name="skipDifficulties">Whether to skip individual difficulties and only increment over full groups.</param>
public void SelectNext(int direction = 1, bool skipDifficulties = true) public void SelectNext(int direction = 1, bool skipDifficulties = true)
{ {
// todo: we may want to refactor and remove this as an optimisation in the future.
if (groups.All(g => g.State == BeatmapGroupState.Hidden)) if (groups.All(g => g.State == BeatmapGroupState.Hidden))
{ {
selectNullBeatmap(); selectNullBeatmap();
return; return;
} }
if (!skipDifficulties && selectedGroup != null) int originalIndex = Math.Max(0, groups.IndexOf(selectedGroup));
{ int currentIndex = originalIndex;
int i = selectedGroup.BeatmapPanels.IndexOf(selectedPanel) + direction;
if (i >= 0 && i < selectedGroup.BeatmapPanels.Count) // local function to increment the index in the required direction, wrapping over extremities.
{ int incrementIndex() => currentIndex = (currentIndex + direction + groups.Count) % groups.Count;
//changing difficulty panel, not set.
selectGroup(selectedGroup, selectedGroup.BeatmapPanels[i]);
return;
}
}
int startIndex = Math.Max(0, groups.IndexOf(selectedGroup)); // in the case we are skipping difficulties, we want to increment the index once before starting to find out new target
int index = startIndex; // (we don't care about the currently selected group).
if (skipDifficulties)
incrementIndex();
do do
{ {
index = (index + direction + groups.Count) % groups.Count; var group = groups[currentIndex];
if (groups[index].State != BeatmapGroupState.Hidden)
{
if (skipDifficulties)
SelectBeatmap(groups[index].SelectedPanel != null ? groups[index].SelectedPanel.Beatmap : groups[index].BeatmapPanels.First().Beatmap);
else
SelectBeatmap(direction == 1 ? groups[index].BeatmapPanels.First().Beatmap : groups[index].BeatmapPanels.Last().Beatmap);
if (group.State == BeatmapGroupState.Hidden) continue;
// we are only interested in non-filtered panels.
IEnumerable<BeatmapPanel> validPanels = group.BeatmapPanels.Where(p => !p.Filtered);
// if we are considering difficulties, we need to do a few extrea steps.
if (!skipDifficulties)
{
// we want to reverse the panel order if we are searching backwards.
if (direction < 0)
validPanels = validPanels.Reverse();
// if we are currently on the selected panel, let's try to find a valid difficulty before leaving to the next group.
// the first valid difficulty is found by skipping to the selected panel and then one further.
if (currentIndex == originalIndex)
validPanels = validPanels.SkipWhile(p => p != selectedPanel).Skip(1);
}
var next = validPanels.FirstOrDefault();
// at this point, we can perform the selection change if we have a valid new target, else continue to increment in the specified direction.
if (next != null)
{
selectGroup(group, next);
return; return;
} }
} while (index != startIndex); } while (incrementIndex() != originalIndex);
} }
private IEnumerable<BeatmapGroup> getVisibleGroups() => groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden); private IEnumerable<BeatmapGroup> getVisibleGroups() => groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden);
@ -308,8 +310,6 @@ namespace osu.Game.Screens.Select
if (newCriteria != null) if (newCriteria != null)
criteria = newCriteria; criteria = newCriteria;
if (!IsLoaded) return;
Action perform = delegate Action perform = delegate
{ {
filterTask = null; filterTask = null;
@ -327,6 +327,8 @@ namespace osu.Game.Screens.Select
computeYPositions(); computeYPositions();
selectedGroup?.UpdateState();
if (selectedGroup == null || selectedGroup.State == BeatmapGroupState.Hidden) if (selectedGroup == null || selectedGroup.State == BeatmapGroupState.Hidden)
SelectNext(); SelectNext();
else else
@ -381,6 +383,10 @@ namespace osu.Game.Screens.Select
private void addGroup(BeatmapGroup group) private void addGroup(BeatmapGroup group)
{ {
// prevent duplicates by concurrent independent actions trying to add a group
if (groups.Any(g => g.BeatmapSet.ID == group.BeatmapSet.ID))
return;
groups.Add(group); groups.Add(group);
panels.Add(group.Header); panels.Add(group.Header);
panels.AddRange(group.BeatmapPanels); panels.AddRange(group.BeatmapPanels);
@ -437,11 +443,13 @@ namespace osu.Game.Screens.Select
panel.MoveToX(-50, 500, Easing.OutExpo); panel.MoveToX(-50, 500, Easing.OutExpo);
bool isHidden = panel.State == PanelSelectedState.Hidden;
//on first display we want to begin hidden under our group's header. //on first display we want to begin hidden under our group's header.
if (panel.Alpha == 0) if (isHidden || panel.Alpha == 0)
panel.MoveToY(headerY); panel.MoveToY(headerY);
movePanel(panel, true, animated, ref currentY); movePanel(panel, !isHidden, animated, ref currentY);
} }
} }
else else
@ -475,8 +483,8 @@ namespace osu.Game.Screens.Select
{ {
try try
{ {
if (panel == null) if (panel == null || panel.Filtered == true)
panel = group.BeatmapPanels.First(); panel = group.BeatmapPanels.First(p => !p.Filtered);
if (selectedPanel == panel) return; if (selectedPanel == panel) return;

View File

@ -19,6 +19,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Cursor;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -217,8 +218,8 @@ namespace osu.Game.Screens.Select
}, },
new FillFlowContainer new FillFlowContainer
{ {
Margin = new MarginPadding { Top = 20, Left = 10 }, Margin = new MarginPadding { Top = 20 },
Spacing = new Vector2(40, 0), Spacing = new Vector2(20, 0),
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = labels Children = labels
}, },
@ -232,43 +233,59 @@ namespace osu.Game.Screens.Select
double bpmMax = beatmap.ControlPointInfo.BPMMaximum; double bpmMax = beatmap.ControlPointInfo.BPMMaximum;
double bpmMin = beatmap.ControlPointInfo.BPMMinimum; double bpmMin = beatmap.ControlPointInfo.BPMMinimum;
if (Precision.AlmostEquals(bpmMin, bpmMax)) return $"{bpmMin:0}bpm"; if (Precision.AlmostEquals(bpmMin, bpmMax)) return $"{bpmMin:0}";
return $"{bpmMin:0}-{bpmMax:0}bpm (mostly {beatmap.ControlPointInfo.BPMMode:0}bpm)"; return $"{bpmMin:0}-{bpmMax:0} (mostly {beatmap.ControlPointInfo.BPMMode:0})";
} }
public class InfoLabel : Container public class InfoLabel : Container, IHasTooltip
{ {
public string TooltipText { get; private set; }
public InfoLabel(BeatmapStatistic statistic) public InfoLabel(BeatmapStatistic statistic)
{ {
TooltipText = statistic.Name;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Children = new Drawable[] Children = new Drawable[]
{
new Container
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(20),
Children = new[]
{ {
new SpriteIcon new SpriteIcon
{ {
Icon = FontAwesome.fa_square, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Colour = new Color4(68, 17, 136, 255), RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"441288"),
Icon = FontAwesome.fa_square,
Rotation = 45, Rotation = 45,
Size = new Vector2(20),
}, },
new SpriteIcon new SpriteIcon
{ {
Icon = statistic.Icon, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Colour = new Color4(255, 221, 85, 255), RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.8f), Scale = new Vector2(0.8f),
Size = new Vector2(20), Colour = OsuColour.FromHex(@"f7dd55"),
Icon = statistic.Icon,
},
}
}, },
new OsuSpriteText new OsuSpriteText
{ {
Margin = new MarginPadding { Left = 13 }, Anchor = Anchor.CentreLeft,
Font = @"Exo2.0-Bold", Origin = Anchor.CentreLeft,
Colour = new Color4(255, 221, 85, 255), Colour = new Color4(255, 221, 85, 255),
Font = @"Exo2.0-Bold",
Margin = new MarginPadding { Left = 30 },
Text = statistic.Content, Text = statistic.Content,
TextSize = 17, TextSize = 17,
Origin = Anchor.CentreLeft }
},
}; };
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Select.Filter; using osu.Game.Screens.Select.Filter;
@ -18,19 +19,26 @@ namespace osu.Game.Screens.Select
public RulesetInfo Ruleset; public RulesetInfo Ruleset;
public bool AllowConvertedBeatmaps; public bool AllowConvertedBeatmaps;
private bool canConvert(BeatmapInfo beatmapInfo) => beatmapInfo.RulesetID == Ruleset.ID || beatmapInfo.RulesetID == 0 && Ruleset.ID > 0 && AllowConvertedBeatmaps;
public void Filter(List<BeatmapGroup> groups) public void Filter(List<BeatmapGroup> groups)
{ {
foreach (var g in groups) foreach (var g in groups)
{ {
var set = g.BeatmapSet; var set = g.BeatmapSet;
bool hasCurrentMode = AllowConvertedBeatmaps || set.Beatmaps.Any(bm => bm.RulesetID == (Ruleset?.ID ?? 0)); // we only support converts from osu! mode to other modes for now.
// in the future this will have to change, at which point this condition will become a touch more complicated.
bool hasCurrentMode = set.Beatmaps.Any(canConvert);
bool match = hasCurrentMode; bool match = hasCurrentMode;
if (!string.IsNullOrEmpty(SearchText)) if (!string.IsNullOrEmpty(SearchText))
match &= set.Metadata.SearchableTerms.Any(term => term.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0); match &= set.Metadata.SearchableTerms.Any(term => term.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0);
foreach (var panel in g.BeatmapPanels)
panel.Filtered.Value = !canConvert(panel.Beatmap);
switch (g.State) switch (g.State)
{ {
case BeatmapGroupState.Hidden: case BeatmapGroupState.Hidden:

View File

@ -203,8 +203,23 @@ namespace osu.Game.Screens.Select
Push(new Editor()); Push(new Editor());
} }
private void onBeatmapRestored(BeatmapInfo b) => Schedule(() => carousel.UpdateBeatmap(b)); private void onBeatmapRestored(BeatmapInfo beatmap)
private void onBeatmapHidden(BeatmapInfo b) => Schedule(() => carousel.UpdateBeatmap(b)); {
Schedule(() =>
{
var beatmapSet = beatmaps.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID);
carousel.UpdateBeatmapSet(beatmapSet);
});
}
private void onBeatmapHidden(BeatmapInfo beatmap)
{
Schedule(() =>
{
var beatmapSet = beatmaps.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID);
carousel.UpdateBeatmapSet(beatmapSet);
});
}
private void carouselBeatmapsLoaded() private void carouselBeatmapsLoaded()
{ {
@ -255,11 +270,11 @@ namespace osu.Game.Screens.Select
UpdateBeatmap(Beatmap.Value); UpdateBeatmap(Beatmap.Value);
}; };
selectionChangedDebounce?.Cancel();
if (beatmap?.Equals(beatmapNoDebounce) == true) if (beatmap?.Equals(beatmapNoDebounce) == true)
return; return;
selectionChangedDebounce?.Cancel();
beatmapNoDebounce = beatmap; beatmapNoDebounce = beatmap;
if (beatmap == null) if (beatmap == null)
@ -293,7 +308,7 @@ namespace osu.Game.Screens.Select
carousel.Filter(criteria, debounce); carousel.Filter(criteria, debounce);
} }
private void onBeatmapSetAdded(BeatmapSetInfo s) => Schedule(() => addBeatmapSet(s)); private void onBeatmapSetAdded(BeatmapSetInfo s) => Schedule(() => carousel.UpdateBeatmapSet(s));
private void onBeatmapSetRemoved(BeatmapSetInfo s) => Schedule(() => removeBeatmapSet(s)); private void onBeatmapSetRemoved(BeatmapSetInfo s) => Schedule(() => removeBeatmapSet(s));
@ -436,8 +451,6 @@ namespace osu.Game.Screens.Select
} }
} }
private void addBeatmapSet(BeatmapSetInfo beatmapSet) => carousel.AddBeatmap(beatmapSet);
private void removeBeatmapSet(BeatmapSetInfo beatmapSet) private void removeBeatmapSet(BeatmapSetInfo beatmapSet)
{ {
carousel.RemoveBeatmap(beatmapSet); carousel.RemoveBeatmap(beatmapSet);

View File

@ -285,15 +285,24 @@
<Compile Include="Migrations\20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs"> <Compile Include="Migrations\20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs">
<DependentUpon>20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs</DependentUpon> <DependentUpon>20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Migrations\20171209034410_AddRulesetInfoShortName.cs" />
<Compile Include="Migrations\20171209034410_AddRulesetInfoShortName.Designer.cs">
<DependentUpon>20171209034410_AddRulesetInfoShortName.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\OsuDbContextModelSnapshot.cs" /> <Compile Include="Migrations\OsuDbContextModelSnapshot.cs" />
<Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" /> <Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" />
<Compile Include="Online\API\Requests\GetBeatmapSetsResponse.cs" /> <Compile Include="Online\API\Requests\APIResponseBeatmapSet.cs" />
<Compile Include="Online\API\Requests\GetUserMostPlayedBeatmapsRequest.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\ClickableUsername.cs" /> <Compile Include="Overlays\BeatmapSet\Scores\ClickableUsername.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\DrawableScore.cs" /> <Compile Include="Overlays\BeatmapSet\Scores\DrawableScore.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\DrawableTopScore.cs" /> <Compile Include="Overlays\BeatmapSet\Scores\DrawableTopScore.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\ScoresContainer.cs" /> <Compile Include="Overlays\BeatmapSet\Scores\ScoresContainer.cs" />
<Compile Include="Online\API\Requests\GetUserBeatmapsRequest.cs" /> <Compile Include="Online\API\Requests\GetUserBeatmapsRequest.cs" />
<Compile Include="Overlays\Profile\Sections\BeatmapMetadataContainer.cs" />
<Compile Include="Overlays\Profile\Sections\Beatmaps\PaginatedBeatmapContainer.cs" /> <Compile Include="Overlays\Profile\Sections\Beatmaps\PaginatedBeatmapContainer.cs" />
<Compile Include="Overlays\Profile\Sections\DrawableProfileRow.cs" />
<Compile Include="Overlays\Profile\Sections\Historical\DrawableMostPlayedRow.cs" />
<Compile Include="Overlays\Profile\Sections\Historical\PaginatedMostPlayedBeatmapContainer.cs" />
<Compile Include="Overlays\Profile\Sections\Kudosu\KudosuInfo.cs" /> <Compile Include="Overlays\Profile\Sections\Kudosu\KudosuInfo.cs" />
<Compile Include="Overlays\Profile\Sections\PaginatedContainer.cs" /> <Compile Include="Overlays\Profile\Sections\PaginatedContainer.cs" />
<Compile Include="Overlays\Profile\Sections\Ranks\DrawablePerformanceScore.cs" /> <Compile Include="Overlays\Profile\Sections\Ranks\DrawablePerformanceScore.cs" />
@ -484,7 +493,7 @@
<Compile Include="Overlays\Notifications\ProgressNotification.cs" /> <Compile Include="Overlays\Notifications\ProgressNotification.cs" />
<Compile Include="Overlays\Notifications\SimpleNotification.cs" /> <Compile Include="Overlays\Notifications\SimpleNotification.cs" />
<Compile Include="Overlays\OnScreenDisplay.cs" /> <Compile Include="Overlays\OnScreenDisplay.cs" />
<Compile Include="Overlays\Profile\Sections\Ranks\DrawableScore.cs" /> <Compile Include="Overlays\Profile\Sections\Ranks\DrawableProfileScore.cs" />
<Compile Include="Overlays\Profile\ProfileHeader.cs" /> <Compile Include="Overlays\Profile\ProfileHeader.cs" />
<Compile Include="Overlays\Profile\ProfileSection.cs" /> <Compile Include="Overlays\Profile\ProfileSection.cs" />
<Compile Include="Overlays\Profile\RankChart.cs" /> <Compile Include="Overlays\Profile\RankChart.cs" />
@ -821,6 +830,9 @@
<Compile Include="Overlays\BeatmapSet\SuccessRate.cs" /> <Compile Include="Overlays\BeatmapSet\SuccessRate.cs" />
<Compile Include="Overlays\BeatmapSet\PreviewButton.cs" /> <Compile Include="Overlays\BeatmapSet\PreviewButton.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -602,6 +602,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-frame
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalFunctions/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>