mirror of
https://github.com/ppy/osu.git
synced 2024-09-23 18:47:28 +08:00
commit
c2d7874c11
58
CodeAnalysis/osu.ruleset
Normal file
58
CodeAnalysis/osu.ruleset
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RuleSet Name="osu! Rule Set" Description=" " ToolsVersion="16.0">
|
||||||
|
<Rules AnalyzerId="Microsoft.CodeQuality.Analyzers" RuleNamespace="Microsoft.CodeQuality.Analyzers">
|
||||||
|
<Rule Id="CA1016" Action="None" />
|
||||||
|
<Rule Id="CA1028" Action="None" />
|
||||||
|
<Rule Id="CA1031" Action="None" />
|
||||||
|
<Rule Id="CA1034" Action="None" />
|
||||||
|
<Rule Id="CA1036" Action="None" />
|
||||||
|
<Rule Id="CA1040" Action="None" />
|
||||||
|
<Rule Id="CA1044" Action="None" />
|
||||||
|
<Rule Id="CA1051" Action="None" />
|
||||||
|
<Rule Id="CA1054" Action="None" />
|
||||||
|
<Rule Id="CA1056" Action="None" />
|
||||||
|
<Rule Id="CA1062" Action="None" />
|
||||||
|
<Rule Id="CA1063" Action="None" />
|
||||||
|
<Rule Id="CA1067" Action="None" />
|
||||||
|
<Rule Id="CA1707" Action="None" />
|
||||||
|
<Rule Id="CA1710" Action="None" />
|
||||||
|
<Rule Id="CA1714" Action="None" />
|
||||||
|
<Rule Id="CA1716" Action="None" />
|
||||||
|
<Rule Id="CA1717" Action="None" />
|
||||||
|
<Rule Id="CA1720" Action="None" />
|
||||||
|
<Rule Id="CA1721" Action="None" />
|
||||||
|
<Rule Id="CA1724" Action="None" />
|
||||||
|
<Rule Id="CA1801" Action="None" />
|
||||||
|
<Rule Id="CA1806" Action="None" />
|
||||||
|
<Rule Id="CA1812" Action="None" />
|
||||||
|
<Rule Id="CA1814" Action="None" />
|
||||||
|
<Rule Id="CA1815" Action="None" />
|
||||||
|
<Rule Id="CA1819" Action="None" />
|
||||||
|
<Rule Id="CA1822" Action="None" />
|
||||||
|
<Rule Id="CA1823" Action="None" />
|
||||||
|
<Rule Id="CA2007" Action="None" />
|
||||||
|
<Rule Id="CA2214" Action="None" />
|
||||||
|
<Rule Id="CA2227" Action="None" />
|
||||||
|
</Rules>
|
||||||
|
<Rules AnalyzerId="Microsoft.CodeQuality.CSharp.Analyzers" RuleNamespace="Microsoft.CodeQuality.CSharp.Analyzers">
|
||||||
|
<Rule Id="CA1001" Action="None" />
|
||||||
|
<Rule Id="CA1032" Action="None" />
|
||||||
|
</Rules>
|
||||||
|
<Rules AnalyzerId="Microsoft.NetCore.Analyzers" RuleNamespace="Microsoft.NetCore.Analyzers">
|
||||||
|
<Rule Id="CA1303" Action="None" />
|
||||||
|
<Rule Id="CA1304" Action="None" />
|
||||||
|
<Rule Id="CA1305" Action="None" />
|
||||||
|
<Rule Id="CA1307" Action="None" />
|
||||||
|
<Rule Id="CA1308" Action="None" />
|
||||||
|
<Rule Id="CA1816" Action="None" />
|
||||||
|
<Rule Id="CA1826" Action="None" />
|
||||||
|
<Rule Id="CA2000" Action="None" />
|
||||||
|
<Rule Id="CA2008" Action="None" />
|
||||||
|
<Rule Id="CA2213" Action="None" />
|
||||||
|
<Rule Id="CA2235" Action="None" />
|
||||||
|
</Rules>
|
||||||
|
<Rules AnalyzerId="Microsoft.NetCore.CSharp.Analyzers" RuleNamespace="Microsoft.NetCore.CSharp.Analyzers">
|
||||||
|
<Rule Id="CA1309" Action="Warning" />
|
||||||
|
<Rule Id="CA2201" Action="Warning" />
|
||||||
|
</Rules>
|
||||||
|
</RuleSet>
|
@ -18,7 +18,11 @@
|
|||||||
<ItemGroup Label="Code Analysis">
|
<ItemGroup Label="Code Analysis">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Code Analysis">
|
||||||
|
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodeAnalysis\osu.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Label="Documentation">
|
<PropertyGroup Label="Documentation">
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
|
@ -16,14 +16,20 @@ using osu.Game.Rulesets.Replays.Types;
|
|||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Difficulty;
|
using osu.Game.Rulesets.Catch.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Catch.Scoring;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
public class CatchRuleset : Ruleset
|
public class CatchRuleset : Ruleset
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
||||||
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new CatchScoreProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
|
||||||
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
|
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
|
||||||
|
|
||||||
@ -114,7 +120,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new Mod[] { };
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,8 @@ using osu.Game.Replays;
|
|||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Catch.Scoring;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
|
||||||
@ -32,8 +30,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(Beatmap);
|
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
||||||
|
@ -25,6 +25,8 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Difficulty;
|
using osu.Game.Rulesets.Mania.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Edit;
|
using osu.Game.Rulesets.Mania.Edit;
|
||||||
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
@ -32,7 +34,11 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
public class ManiaRuleset : Ruleset
|
public class ManiaRuleset : Ruleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableManiaRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableManiaRuleset(this, beatmap, mods);
|
||||||
|
|
||||||
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ManiaScoreProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
public const string SHORT_NAME = "mania";
|
public const string SHORT_NAME = "mania";
|
||||||
@ -160,7 +166,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new Mod[] { };
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +276,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
return stage1Bindings.Concat(stage2Bindings);
|
return stage1Bindings.Concat(stage2Bindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new KeyBinding[0];
|
return Array.Empty<KeyBinding>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetVariantName(int variant)
|
public override string GetVariantName(int variant)
|
||||||
|
@ -14,11 +14,9 @@ using osu.Game.Rulesets.Mania.Configuration;
|
|||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -67,8 +65,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(Beatmap);
|
|
||||||
|
|
||||||
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
||||||
|
|
||||||
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
||||||
{
|
{
|
||||||
public OsuDistanceSnapGrid(OsuHitObject hitObject, [CanBeNull] OsuHitObject nextHitObject = null)
|
public OsuDistanceSnapGrid(OsuHitObject hitObject, [CanBeNull] OsuHitObject nextHitObject = null)
|
||||||
: base(hitObject.StackedPosition, hitObject.StartTime, nextHitObject?.StartTime)
|
: base(hitObject.StackedEndPosition, hitObject.GetEndTime(), nextHitObject?.StartTime)
|
||||||
{
|
{
|
||||||
Masking = true;
|
Masking = true;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,24 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
OsuHitObject sourceObject = EditorBeatmap.HitObjects[sourceIndex];
|
OsuHitObject sourceObject = EditorBeatmap.HitObjects[sourceIndex];
|
||||||
OsuHitObject targetObject = sourceIndex + targetOffset < EditorBeatmap.HitObjects.Count ? EditorBeatmap.HitObjects[sourceIndex + targetOffset] : null;
|
|
||||||
|
int targetIndex = sourceIndex + targetOffset;
|
||||||
|
OsuHitObject targetObject = null;
|
||||||
|
|
||||||
|
// Keep advancing the target object while its start time falls before the end time of the source object
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (targetIndex >= EditorBeatmap.HitObjects.Count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (EditorBeatmap.HitObjects[targetIndex].StartTime >= sourceObject.GetEndTime())
|
||||||
|
{
|
||||||
|
targetObject = EditorBeatmap.HitObjects[targetIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
return new OsuDistanceSnapGrid(sourceObject, targetObject);
|
return new OsuDistanceSnapGrid(sourceObject, targetObject);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
@ -54,13 +55,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSlider slider:
|
case DrawableSlider slider:
|
||||||
slider.AccentColour.BindValueChanged(_ =>
|
slider.Body.OnSkinChanged += () => applySliderState(slider);
|
||||||
{
|
applySliderState(slider);
|
||||||
//will trigger on skin change.
|
|
||||||
slider.Body.AccentColour = slider.AccentColour.Value.Opacity(0);
|
|
||||||
slider.Body.BorderColour = slider.AccentColour.Value;
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSpinner spinner:
|
case DrawableSpinner spinner:
|
||||||
@ -69,5 +65,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applySliderState(DrawableSlider slider)
|
||||||
|
{
|
||||||
|
((PlaySliderBody)slider.Body.Drawable).AccentColour = slider.AccentColour.Value.Opacity(0);
|
||||||
|
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -98,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||||
{
|
{
|
||||||
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
|
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
|
||||||
List<Vector2> curve = drawableSlider.Body.CurrentCurve;
|
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
|
||||||
|
|
||||||
Position = isRepeatAtEnd ? end : start;
|
Position = isRepeatAtEnd ? end : start;
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Configuration;
|
|
||||||
using osu.Game.Rulesets.Osu.Skinning;
|
using osu.Game.Rulesets.Osu.Skinning;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -24,8 +23,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public DrawableSliderHead HeadCircle => headContainer.Child;
|
public DrawableSliderHead HeadCircle => headContainer.Child;
|
||||||
public DrawableSliderTail TailCircle => tailContainer.Child;
|
public DrawableSliderTail TailCircle => tailContainer.Child;
|
||||||
|
|
||||||
public readonly SnakingSliderBody Body;
|
|
||||||
public readonly SliderBall Ball;
|
public readonly SliderBall Ball;
|
||||||
|
public readonly SkinnableDrawable Body;
|
||||||
|
|
||||||
|
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
|
||||||
|
|
||||||
private readonly Container<DrawableSliderHead> headContainer;
|
private readonly Container<DrawableSliderHead> headContainer;
|
||||||
private readonly Container<DrawableSliderTail> tailContainer;
|
private readonly Container<DrawableSliderTail> tailContainer;
|
||||||
@ -37,10 +38,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
||||||
private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
|
private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
|
||||||
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
||||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
|
||||||
private OsuRulesetConfigManager config { get; set; }
|
|
||||||
|
|
||||||
public DrawableSlider(Slider s)
|
public DrawableSlider(Slider s)
|
||||||
: base(s)
|
: base(s)
|
||||||
@ -51,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
Body = new SnakingSliderBody(s),
|
Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling),
|
||||||
tickContainer = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
|
tickContainer = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
|
||||||
repeatContainer = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
|
repeatContainer = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
|
||||||
Ball = new SliderBall(s, this)
|
Ball = new SliderBall(s, this)
|
||||||
@ -70,28 +67,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
config?.BindWith(OsuRulesetSetting.SnakingInSliders, Body.SnakingIn);
|
|
||||||
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, Body.SnakingOut);
|
|
||||||
|
|
||||||
positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
stackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
stackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
scaleBindable.BindValueChanged(scale =>
|
scaleBindable.BindValueChanged(scale => Ball.Scale = new Vector2(scale.NewValue));
|
||||||
{
|
|
||||||
updatePathRadius();
|
|
||||||
Ball.Scale = new Vector2(scale.NewValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
positionBindable.BindTo(HitObject.PositionBindable);
|
positionBindable.BindTo(HitObject.PositionBindable);
|
||||||
stackHeightBindable.BindTo(HitObject.StackHeightBindable);
|
stackHeightBindable.BindTo(HitObject.StackHeightBindable);
|
||||||
scaleBindable.BindTo(HitObject.ScaleBindable);
|
scaleBindable.BindTo(HitObject.ScaleBindable);
|
||||||
pathVersion.BindTo(slider.Path.Version);
|
|
||||||
|
|
||||||
pathVersion.BindValueChanged(_ => Body.Refresh());
|
|
||||||
|
|
||||||
AccentColour.BindValueChanged(colour =>
|
AccentColour.BindValueChanged(colour =>
|
||||||
{
|
{
|
||||||
Body.AccentColour = colour.NewValue;
|
|
||||||
|
|
||||||
foreach (var drawableHitObject in NestedHitObjects)
|
foreach (var drawableHitObject in NestedHitObjects)
|
||||||
drawableHitObject.AccentColour.Value = colour.NewValue;
|
drawableHitObject.AccentColour.Value = colour.NewValue;
|
||||||
}, true);
|
}, true);
|
||||||
@ -169,16 +154,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
||||||
|
|
||||||
Ball.UpdateProgress(completionProgress);
|
Ball.UpdateProgress(completionProgress);
|
||||||
Body.UpdateProgress(completionProgress);
|
sliderBody?.UpdateProgress(completionProgress);
|
||||||
|
|
||||||
foreach (DrawableHitObject hitObject in NestedHitObjects)
|
foreach (DrawableHitObject hitObject in NestedHitObjects)
|
||||||
{
|
{
|
||||||
if (hitObject is ITrackSnaking s) s.UpdateSnakingPosition(slider.Path.PositionAt(Body.SnakedStart ?? 0), slider.Path.PositionAt(Body.SnakedEnd ?? 0));
|
if (hitObject is ITrackSnaking s) s.UpdateSnakingPosition(slider.Path.PositionAt(sliderBody?.SnakedStart ?? 0), slider.Path.PositionAt(sliderBody?.SnakedEnd ?? 0));
|
||||||
if (hitObject is IRequireTracking t) t.Tracking = Ball.Tracking;
|
if (hitObject is IRequireTracking t) t.Tracking = Ball.Tracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size = Body.Size;
|
Size = sliderBody?.Size ?? Vector2.Zero;
|
||||||
OriginPosition = Body.PathOffset;
|
OriginPosition = sliderBody?.PathOffset ?? Vector2.Zero;
|
||||||
|
|
||||||
if (DrawSize != Vector2.Zero)
|
if (DrawSize != Vector2.Zero)
|
||||||
{
|
{
|
||||||
@ -192,28 +177,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public override void OnKilled()
|
public override void OnKilled()
|
||||||
{
|
{
|
||||||
base.OnKilled();
|
base.OnKilled();
|
||||||
Body.RecyclePath();
|
sliderBody?.RecyclePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float sliderPathRadius;
|
|
||||||
|
|
||||||
protected override void ApplySkin(ISkinSource skin, bool allowFallback)
|
protected override void ApplySkin(ISkinSource skin, bool allowFallback)
|
||||||
{
|
{
|
||||||
base.ApplySkin(skin, allowFallback);
|
base.ApplySkin(skin, allowFallback);
|
||||||
|
|
||||||
Body.BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE;
|
|
||||||
sliderPathRadius = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS;
|
|
||||||
updatePathRadius();
|
|
||||||
|
|
||||||
Body.AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? AccentColour.Value;
|
|
||||||
Body.BorderColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBorder)?.Value ?? Color4.White;
|
|
||||||
|
|
||||||
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
||||||
Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White;
|
Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePathRadius() => Body.PathRadius = slider.Scale * sliderPathRadius;
|
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (userTriggered || Time.Current < slider.EndTime)
|
if (userTriggered || Time.Current < slider.EndTime)
|
||||||
@ -264,6 +238,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public Drawable ProxiedLayer => HeadCircle.ProxiedLayer;
|
public Drawable ProxiedLayer => HeadCircle.ProxiedLayer;
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Body.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => sliderBody?.ReceivePositionalInputAt(screenSpacePos) ?? base.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
|
private class DefaultSliderBody : PlaySliderBody
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Lines;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
|
{
|
||||||
|
public abstract class DrawableSliderPath : SmoothPath
|
||||||
|
{
|
||||||
|
protected const float BORDER_PORTION = 0.128f;
|
||||||
|
protected const float GRADIENT_PORTION = 1 - BORDER_PORTION;
|
||||||
|
|
||||||
|
private const float border_max_size = 8f;
|
||||||
|
private const float border_min_size = 0f;
|
||||||
|
|
||||||
|
private Color4 borderColour = Color4.White;
|
||||||
|
|
||||||
|
public Color4 BorderColour
|
||||||
|
{
|
||||||
|
get => borderColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (borderColour == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
borderColour = value;
|
||||||
|
|
||||||
|
InvalidateTexture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color4 accentColour = Color4.White;
|
||||||
|
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get => accentColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (accentColour == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
accentColour = value;
|
||||||
|
|
||||||
|
InvalidateTexture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float borderSize = 1;
|
||||||
|
|
||||||
|
public float BorderSize
|
||||||
|
{
|
||||||
|
get => borderSize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (borderSize == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (value < border_min_size || value > border_max_size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
borderSize = value;
|
||||||
|
|
||||||
|
InvalidateTexture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float CalculatedBorderPortion => BorderSize * BORDER_PORTION;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Configuration;
|
||||||
|
using osu.Game.Rulesets.Osu.Skinning;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
|
{
|
||||||
|
public abstract class PlaySliderBody : SnakingSliderBody
|
||||||
|
{
|
||||||
|
private IBindable<float> scaleBindable;
|
||||||
|
private IBindable<int> pathVersion;
|
||||||
|
private IBindable<Color4> accentColour;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private DrawableHitObject drawableObject { get; set; }
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private OsuRulesetConfigManager config { get; set; }
|
||||||
|
|
||||||
|
private Slider slider;
|
||||||
|
private float defaultPathRadius;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin)
|
||||||
|
{
|
||||||
|
slider = (Slider)drawableObject.HitObject;
|
||||||
|
defaultPathRadius = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS;
|
||||||
|
|
||||||
|
scaleBindable = slider.ScaleBindable.GetBoundCopy();
|
||||||
|
scaleBindable.BindValueChanged(_ => updatePathRadius(), true);
|
||||||
|
|
||||||
|
pathVersion = slider.Path.Version.GetBoundCopy();
|
||||||
|
pathVersion.BindValueChanged(_ => Refresh());
|
||||||
|
|
||||||
|
accentColour = drawableObject.AccentColour.GetBoundCopy();
|
||||||
|
accentColour.BindValueChanged(accent => updateAccentColour(skin, accent.NewValue), true);
|
||||||
|
|
||||||
|
config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn);
|
||||||
|
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, SnakingOut);
|
||||||
|
|
||||||
|
BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? 1;
|
||||||
|
BorderColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBorder)?.Value ?? Color4.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePathRadius()
|
||||||
|
=> PathRadius = defaultPathRadius * scaleBindable.Value;
|
||||||
|
|
||||||
|
private void updateAccentColour(ISkinSource skin, Color4 defaultAccentColour)
|
||||||
|
=> AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? defaultAccentColour;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Lines;
|
using osu.Framework.Graphics.Lines;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -12,9 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
{
|
{
|
||||||
public abstract class SliderBody : CompositeDrawable
|
public abstract class SliderBody : CompositeDrawable
|
||||||
{
|
{
|
||||||
public const float DEFAULT_BORDER_SIZE = 1;
|
private DrawableSliderPath path;
|
||||||
|
|
||||||
private SliderPath path;
|
|
||||||
|
|
||||||
protected Path Path => path;
|
protected Path Path => path;
|
||||||
|
|
||||||
@ -80,19 +79,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new <see cref="SliderPath"/>, releasing all resources retained by the old one.
|
/// Initialises a new <see cref="DrawableSliderPath"/>, releasing all resources retained by the old one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void RecyclePath()
|
public virtual void RecyclePath()
|
||||||
{
|
{
|
||||||
InternalChild = path = new SliderPath
|
InternalChild = path = CreateSliderPath().With(p =>
|
||||||
{
|
{
|
||||||
Position = path?.Position ?? Vector2.Zero,
|
p.Position = path?.Position ?? Vector2.Zero;
|
||||||
PathRadius = path?.PathRadius ?? 10,
|
p.PathRadius = path?.PathRadius ?? 10;
|
||||||
AccentColour = path?.AccentColour ?? Color4.White,
|
p.AccentColour = path?.AccentColour ?? Color4.White;
|
||||||
BorderColour = path?.BorderColour ?? Color4.White,
|
p.BorderColour = path?.BorderColour ?? Color4.White;
|
||||||
BorderSize = path?.BorderSize ?? DEFAULT_BORDER_SIZE,
|
p.BorderSize = path?.BorderSize ?? 1;
|
||||||
Vertices = path?.Vertices ?? Array.Empty<Vector2>()
|
p.Vertices = path?.Vertices ?? Array.Empty<Vector2>();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
|
||||||
@ -103,77 +102,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
/// <param name="vertices">The vertices</param>
|
/// <param name="vertices">The vertices</param>
|
||||||
protected void SetVertices(IReadOnlyList<Vector2> vertices) => path.Vertices = vertices;
|
protected void SetVertices(IReadOnlyList<Vector2> vertices) => path.Vertices = vertices;
|
||||||
|
|
||||||
private class SliderPath : SmoothPath
|
protected virtual DrawableSliderPath CreateSliderPath() => new DefaultDrawableSliderPath();
|
||||||
|
|
||||||
|
private class DefaultDrawableSliderPath : DrawableSliderPath
|
||||||
{
|
{
|
||||||
private const float border_max_size = 8f;
|
|
||||||
private const float border_min_size = 0f;
|
|
||||||
|
|
||||||
private const float border_portion = 0.128f;
|
|
||||||
private const float gradient_portion = 1 - border_portion;
|
|
||||||
|
|
||||||
private const float opacity_at_centre = 0.3f;
|
private const float opacity_at_centre = 0.3f;
|
||||||
private const float opacity_at_edge = 0.8f;
|
private const float opacity_at_edge = 0.8f;
|
||||||
|
|
||||||
private Color4 borderColour = Color4.White;
|
|
||||||
|
|
||||||
public Color4 BorderColour
|
|
||||||
{
|
|
||||||
get => borderColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (borderColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
borderColour = value;
|
|
||||||
|
|
||||||
InvalidateTexture();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour = Color4.White;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
|
|
||||||
InvalidateTexture();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float borderSize = DEFAULT_BORDER_SIZE;
|
|
||||||
|
|
||||||
public float BorderSize
|
|
||||||
{
|
|
||||||
get => borderSize;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (borderSize == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (value < border_min_size || value > border_max_size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
borderSize = value;
|
|
||||||
|
|
||||||
InvalidateTexture();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float calculatedBorderPortion => BorderSize * border_portion;
|
|
||||||
|
|
||||||
protected override Color4 ColourAt(float position)
|
protected override Color4 ColourAt(float position)
|
||||||
{
|
{
|
||||||
if (calculatedBorderPortion != 0f && position <= calculatedBorderPortion)
|
if (CalculatedBorderPortion != 0f && position <= CalculatedBorderPortion)
|
||||||
return BorderColour;
|
return BorderColour;
|
||||||
|
|
||||||
position -= calculatedBorderPortion;
|
position -= CalculatedBorderPortion;
|
||||||
return new Color4(AccentColour.R, AccentColour.G, AccentColour.B, (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * position / gradient_portion) * AccentColour.A);
|
return new Color4(AccentColour.R, AccentColour.G, AccentColour.B, (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * position / GRADIENT_PORTION) * AccentColour.A);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -50,16 +51,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Vector2 snakedPathOffset;
|
private Vector2 snakedPathOffset;
|
||||||
|
|
||||||
private readonly Slider slider;
|
private Slider slider;
|
||||||
|
|
||||||
public SnakingSliderBody(Slider slider)
|
|
||||||
{
|
|
||||||
this.slider = slider;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(DrawableHitObject drawableObject)
|
||||||
{
|
{
|
||||||
|
slider = (Slider)drawableObject.HitObject;
|
||||||
|
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,16 +23,23 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Configuration;
|
using osu.Game.Rulesets.Osu.Configuration;
|
||||||
using osu.Game.Rulesets.Osu.Difficulty;
|
using osu.Game.Rulesets.Osu.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Rulesets.Osu.Skinning;
|
using osu.Game.Rulesets.Osu.Skinning;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
public class OsuRuleset : Ruleset
|
public class OsuRuleset : Ruleset
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
||||||
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new OsuScoreProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap);
|
||||||
|
|
||||||
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap);
|
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap);
|
||||||
|
|
||||||
public const string SHORT_NAME = "osu";
|
public const string SHORT_NAME = "osu";
|
||||||
@ -151,7 +158,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new Mod[] { };
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
ReverseArrow,
|
ReverseArrow,
|
||||||
HitCircleText,
|
HitCircleText,
|
||||||
SliderFollowCircle,
|
SliderFollowCircle,
|
||||||
SliderBall
|
SliderBall,
|
||||||
|
SliderBody,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
47
osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs
Normal file
47
osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Skinning
|
||||||
|
{
|
||||||
|
public class LegacySliderBody : PlaySliderBody
|
||||||
|
{
|
||||||
|
protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath();
|
||||||
|
|
||||||
|
private class LegacyDrawableSliderPath : DrawableSliderPath
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (CalculatedBorderPortion != 0f && position <= CalculatedBorderPortion)
|
||||||
|
return BorderColour;
|
||||||
|
|
||||||
|
position -= BORDER_PORTION;
|
||||||
|
|
||||||
|
Color4 outerColour = AccentColour.Darken(0.1f);
|
||||||
|
Color4 innerColour = lighten(AccentColour, 0.5f);
|
||||||
|
|
||||||
|
return Interpolation.ValueAt(position / GRADIENT_PORTION, outerColour, innerColour, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lightens a colour in a way more friendly to dark or strong colours.
|
||||||
|
/// </summary>
|
||||||
|
private static Color4 lighten(Color4 color, float amount)
|
||||||
|
{
|
||||||
|
amount *= 0.5f;
|
||||||
|
return new Color4(
|
||||||
|
Math.Min(1, color.R * (1 + 0.5f * amount) + 1 * amount),
|
||||||
|
Math.Min(1, color.G * (1 + 0.5f * amount) + 1 * amount),
|
||||||
|
Math.Min(1, color.B * (1 + 0.5f * amount) + 1 * amount),
|
||||||
|
color.A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -73,6 +73,12 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
case OsuSkinComponents.SliderBody:
|
||||||
|
if (hasHitCircle.Value)
|
||||||
|
return new LegacySliderBody();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case OsuSkinComponents.HitCircle:
|
case OsuSkinComponents.HitCircle:
|
||||||
if (hasHitCircle.Value)
|
if (hasHitCircle.Value)
|
||||||
return new LegacyMainCirclePiece();
|
return new LegacyMainCirclePiece();
|
||||||
|
@ -14,8 +14,6 @@ using osu.Game.Rulesets.Osu.Configuration;
|
|||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -33,8 +31,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(Beatmap);
|
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
||||||
|
|
||||||
protected override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
|
protected override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
|
||||||
|
@ -105,19 +105,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableTaikoHitObject
|
public abstract class DrawableTaikoHitObject<TTaikoHit> : DrawableTaikoHitObject
|
||||||
where TaikoHitType : TaikoHitObject
|
where TTaikoHit : TaikoHitObject
|
||||||
{
|
{
|
||||||
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
|
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
|
||||||
|
|
||||||
public new TaikoHitType HitObject;
|
public new TTaikoHit HitObject;
|
||||||
|
|
||||||
protected readonly Vector2 BaseSize;
|
protected readonly Vector2 BaseSize;
|
||||||
protected readonly TaikoPiece MainPiece;
|
protected readonly TaikoPiece MainPiece;
|
||||||
|
|
||||||
private readonly Container<DrawableStrongNestedHit> strongHitContainer;
|
private readonly Container<DrawableStrongNestedHit> strongHitContainer;
|
||||||
|
|
||||||
protected DrawableTaikoHitObject(TaikoHitType hitObject)
|
protected DrawableTaikoHitObject(TTaikoHit hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
HitObject = hitObject;
|
||||||
|
@ -15,15 +15,21 @@ using osu.Game.Rulesets.Replays.Types;
|
|||||||
using osu.Game.Rulesets.Taiko.Replays;
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
using osu.Game.Rulesets.Taiko.Difficulty;
|
using osu.Game.Rulesets.Taiko.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Taiko.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko
|
||||||
{
|
{
|
||||||
public class TaikoRuleset : Ruleset
|
public class TaikoRuleset : Ruleset
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
||||||
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new TaikoScoreProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap);
|
||||||
|
|
||||||
public const string SHORT_NAME = "taiko";
|
public const string SHORT_NAME = "taiko";
|
||||||
@ -113,7 +119,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new Mod[] { };
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,8 @@ using System.Collections.Generic;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Scoring;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.Taiko.Replays;
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
@ -40,8 +38,6 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(Beatmap);
|
|
||||||
|
|
||||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
||||||
|
|
||||||
protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
cpi.Add(1000, new DifficultyControlPoint()); // is redundant
|
cpi.Add(1000, new DifficultyControlPoint()); // is redundant
|
||||||
|
|
||||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||||
|
|
||||||
cpi.Add(1000, new DifficultyControlPoint { SpeedMultiplier = 2 }); // is not redundant
|
cpi.Add(1000, new DifficultyControlPoint { SpeedMultiplier = 2 }); // is not redundant
|
||||||
@ -60,18 +60,18 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new ControlPointInfo();
|
||||||
|
|
||||||
cpi.Add(0, new SampleControlPoint()); // is redundant
|
cpi.Add(0, new SampleControlPoint()); // is *not* redundant, special exception for first sample point
|
||||||
cpi.Add(1000, new SampleControlPoint()); // is redundant
|
cpi.Add(1000, new SampleControlPoint()); // is redundant
|
||||||
|
|
||||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
|
||||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
|
||||||
|
|
||||||
cpi.Add(1000, new SampleControlPoint { SampleVolume = 50 }); // is not redundant
|
|
||||||
|
|
||||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||||
Assert.That(cpi.SamplePoints.Count, Is.EqualTo(1));
|
Assert.That(cpi.SamplePoints.Count, Is.EqualTo(1));
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||||
|
|
||||||
|
cpi.Add(1000, new SampleControlPoint { SampleVolume = 50 }); // is not redundant
|
||||||
|
|
||||||
|
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(cpi.SamplePoints.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -83,7 +83,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
cpi.Add(1000, new EffectControlPoint()); // is redundant
|
cpi.Add(1000, new EffectControlPoint()); // is redundant
|
||||||
|
|
||||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(0));
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||||
|
|
||||||
cpi.Add(1000, new EffectControlPoint { KiaiMode = true }); // is not redundant
|
cpi.Add(1000, new EffectControlPoint { KiaiMode = true }); // is not redundant
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
Assert.AreEqual(0, stack.Count);
|
Assert.AreEqual(0, stack.Count);
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||||
{
|
{
|
||||||
int unused = stack[0];
|
int unused = stack[0];
|
||||||
});
|
});
|
||||||
@ -55,7 +55,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
// e.g. indices 3, 4, 5, 6 (out of range)
|
// e.g. indices 3, 4, 5, 6 (out of range)
|
||||||
for (int i = stack.Count; i < stack.Count + capacity; i++)
|
for (int i = stack.Count; i < stack.Count + capacity; i++)
|
||||||
{
|
{
|
||||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||||
{
|
{
|
||||||
int unused = stack[i];
|
int unused = stack[i];
|
||||||
});
|
});
|
||||||
@ -80,7 +80,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
// e.g. indices 3, 4, 5, 6 (out of range)
|
// e.g. indices 3, 4, 5, 6 (out of range)
|
||||||
for (int i = stack.Count; i < stack.Count + capacity; i++)
|
for (int i = stack.Count; i < stack.Count + capacity; i++)
|
||||||
{
|
{
|
||||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||||
{
|
{
|
||||||
int unused = stack[i];
|
int unused = stack[i];
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -10,6 +11,7 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.IO.Archives;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
@ -154,7 +156,30 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ScoreInfo> loadIntoOsu(OsuGameBase osu, ScoreInfo score)
|
[Test]
|
||||||
|
public async Task TestOnlineScoreIsAvailableLocally()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestOnlineScoreIsAvailableLocally"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = await loadOsu(host);
|
||||||
|
|
||||||
|
await loadIntoOsu(osu, new ScoreInfo { OnlineScoreID = 2 }, new TestArchiveReader());
|
||||||
|
|
||||||
|
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||||
|
|
||||||
|
// Note: A new score reference is used here since the import process mutates the original object to set an ID
|
||||||
|
Assert.That(scoreManager.IsAvailableLocally(new ScoreInfo { OnlineScoreID = 2 }));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ScoreInfo> loadIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
|
||||||
{
|
{
|
||||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
@ -165,7 +190,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
score.Ruleset = new OsuRuleset().RulesetInfo;
|
score.Ruleset = new OsuRuleset().RulesetInfo;
|
||||||
|
|
||||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||||
await scoreManager.Import(score);
|
await scoreManager.Import(score, archive);
|
||||||
|
|
||||||
return scoreManager.GetAllUsableScores().FirstOrDefault();
|
return scoreManager.GetAllUsableScores().FirstOrDefault();
|
||||||
}
|
}
|
||||||
@ -196,5 +221,23 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
|
|
||||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestArchiveReader : ArchiveReader
|
||||||
|
{
|
||||||
|
public TestArchiveReader()
|
||||||
|
: base("test_archive")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream GetStream(string name) => new MemoryStream();
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> Filenames => new[] { "test_file.osr" };
|
||||||
|
|
||||||
|
public override Stream GetUnderlyingStream() => new MemoryStream();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -31,7 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
requestCount = 0;
|
requestCount = 0;
|
||||||
increment = skip_time;
|
increment = skip_time;
|
||||||
|
|
||||||
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new Mod[] { }, 0)
|
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), Array.Empty<Mod>(), 0)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
|
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
|
||||||
AddStep(@"clear users", () => Room.Participants.Value = new User[] { });
|
AddStep(@"clear users", () => Room.Participants.Value = System.Array.Empty<User>());
|
||||||
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
osu.Game.Tests/Visual/Online/TestSceneProfileCounterPill.cs
Normal file
42
osu.Game.Tests/Visual/Online/TestSceneProfileCounterPill.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Overlays.Profile.Sections;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public class TestSceneProfileCounterPill : OsuTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(CounterPill)
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly CounterPill pill;
|
||||||
|
private readonly BindableInt value = new BindableInt();
|
||||||
|
|
||||||
|
public TestSceneProfileCounterPill()
|
||||||
|
{
|
||||||
|
Child = pill = new CounterPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Current = { BindTarget = value }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestVisibility()
|
||||||
|
{
|
||||||
|
AddStep("Set value to 0", () => value.Value = 0);
|
||||||
|
AddAssert("Check hidden", () => !pill.IsPresent);
|
||||||
|
AddStep("Set value to 10", () => value.Value = 10);
|
||||||
|
AddAssert("Check visible", () => pill.IsPresent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
Title = "osu!volunteer",
|
Title = "osu!volunteer",
|
||||||
Colour = "ff0000",
|
Colour = "ff0000",
|
||||||
Achievements = new User.UserAchievement[0],
|
Achievements = Array.Empty<User.UserAchievement>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
public TestSceneUserProfileOverlay()
|
public TestSceneUserProfileOverlay()
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
new User { PreviousUsernames = new[] { "longusername", "longerusername" } },
|
new User { PreviousUsernames = new[] { "longusername", "longerusername" } },
|
||||||
new User { PreviousUsernames = new[] { "test", "angelsim", "verylongusername" } },
|
new User { PreviousUsernames = new[] { "test", "angelsim", "verylongusername" } },
|
||||||
new User { PreviousUsernames = new[] { "ihavenoidea", "howcani", "makethistext", "anylonger" } },
|
new User { PreviousUsernames = new[] { "ihavenoidea", "howcani", "makethistext", "anylonger" } },
|
||||||
new User { PreviousUsernames = new string[0] },
|
new User { PreviousUsernames = Array.Empty<string>() },
|
||||||
null
|
null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
foreach (var type in requiredGameDependencies)
|
foreach (var type in requiredGameDependencies)
|
||||||
{
|
{
|
||||||
if (game.Dependencies.Get(type) == null)
|
if (game.Dependencies.Get(type) == null)
|
||||||
throw new Exception($"{type} has not been cached");
|
throw new InvalidOperationException($"{type} has not been cached");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
foreach (var type in requiredGameBaseDependencies)
|
foreach (var type in requiredGameBaseDependencies)
|
||||||
{
|
{
|
||||||
if (gameBase.Dependencies.Get(type) == null)
|
if (gameBase.Dependencies.Get(type) == null)
|
||||||
throw new Exception($"{type} has not been cached");
|
throw new InvalidOperationException($"{type} has not been cached");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (editorInfo == null)
|
if (editorInfo == null)
|
||||||
return new MenuItem[0];
|
return Array.Empty<MenuItem>();
|
||||||
|
|
||||||
return new MenuItem[]
|
return new MenuItem[]
|
||||||
{
|
{
|
||||||
|
@ -192,7 +192,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (editorInfo == null)
|
if (editorInfo == null)
|
||||||
return new MenuItem[0];
|
return Array.Empty<MenuItem>();
|
||||||
|
|
||||||
return new MenuItem[]
|
return new MenuItem[]
|
||||||
{
|
{
|
||||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
Bookmarks = new int[0];
|
Bookmarks = Array.Empty<int>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int[] Bookmarks { get; set; } = new int[0];
|
public int[] Bookmarks { get; set; } = Array.Empty<int>();
|
||||||
|
|
||||||
public double DistanceSpacing { get; set; }
|
public double DistanceSpacing { get; set; }
|
||||||
public int BeatDivisor { get; set; }
|
public int BeatDivisor { get; set; }
|
||||||
|
@ -158,7 +158,9 @@ namespace osu.Game.Beatmaps
|
|||||||
void resetIds() => beatmapSet.Beatmaps.ForEach(b => b.OnlineBeatmapID = null);
|
void resetIds() => beatmapSet.Beatmaps.ForEach(b => b.OnlineBeatmapID = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CheckLocalAvailability(BeatmapSetInfo model, IQueryable<BeatmapSetInfo> items) => items.Any(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID);
|
protected override bool CheckLocalAvailability(BeatmapSetInfo model, IQueryable<BeatmapSetInfo> items)
|
||||||
|
=> base.CheckLocalAvailability(model, items)
|
||||||
|
|| (model.OnlineBeatmapSetID != null && items.Any(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a beatmap difficulty.
|
/// Delete a beatmap difficulty.
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getPathForFile(string filename) => BeatmapSetInfo.Files.FirstOrDefault(f => string.Equals(f.Filename, filename, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
private string getPathForFile(string filename) => BeatmapSetInfo.Files.FirstOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
||||||
|
|
||||||
private TextureStore textureStore;
|
private TextureStore textureStore;
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SampleControlPoint _:
|
case SampleControlPoint _:
|
||||||
existing = SamplePointAt(time);
|
existing = binarySearch(SamplePoints, time);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DifficultyControlPoint _:
|
case DifficultyControlPoint _:
|
||||||
|
@ -70,6 +70,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
|
|
||||||
public override bool EquivalentTo(ControlPoint other) =>
|
public override bool EquivalentTo(ControlPoint other) =>
|
||||||
other is SampleControlPoint otherTyped &&
|
other is SampleControlPoint otherTyped &&
|
||||||
string.Equals(SampleBank, otherTyped.SampleBank) && SampleVolume == otherTyped.SampleVolume;
|
SampleBank == otherTyped.SampleBank && SampleVolume == otherTyped.SampleVolume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
private class DummyRuleset : Ruleset
|
private class DummyRuleset : Ruleset
|
||||||
{
|
{
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[] { };
|
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
|
||||||
|
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,8 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
private readonly MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore;
|
private readonly MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore;
|
||||||
|
|
||||||
protected DownloadableArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, IAPIProvider api, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore, IIpcHost importHost = null)
|
protected DownloadableArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, IAPIProvider api, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore,
|
||||||
|
IIpcHost importHost = null)
|
||||||
: base(storage, contextFactory, modelStore, importHost)
|
: base(storage, contextFactory, modelStore, importHost)
|
||||||
{
|
{
|
||||||
this.api = api;
|
this.api = api;
|
||||||
@ -124,7 +125,8 @@ namespace osu.Game.Database
|
|||||||
/// <param name="model">The <typeparamref name="TModel"/> whose existence needs to be checked.</param>
|
/// <param name="model">The <typeparamref name="TModel"/> whose existence needs to be checked.</param>
|
||||||
/// <param name="items">The usable items present in the store.</param>
|
/// <param name="items">The usable items present in the store.</param>
|
||||||
/// <returns>Whether the <typeparamref name="TModel"/> exists.</returns>
|
/// <returns>Whether the <typeparamref name="TModel"/> exists.</returns>
|
||||||
protected abstract bool CheckLocalAvailability(TModel model, IQueryable<TModel> items);
|
protected virtual bool CheckLocalAvailability(TModel model, IQueryable<TModel> items)
|
||||||
|
=> model.ID > 0 && items.Any(i => i.ID == model.ID && i.Files.Any());
|
||||||
|
|
||||||
public ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model) => currentDownloads.Find(r => r.Model.Equals(model));
|
public ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model) => currentDownloads.Find(r => r.Model.Equals(model));
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ using osu.Framework.Platform;
|
|||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
{
|
{
|
||||||
public abstract class MutableDatabaseBackedStoreWithFileIncludes<T, U> : MutableDatabaseBackedStore<T>
|
public abstract class MutableDatabaseBackedStoreWithFileIncludes<T, TFileInfo> : MutableDatabaseBackedStore<T>
|
||||||
where T : class, IHasPrimaryKey, ISoftDelete, IHasFiles<U>
|
where T : class, IHasPrimaryKey, ISoftDelete, IHasFiles<TFileInfo>
|
||||||
where U : INamedFileInfo
|
where TFileInfo : INamedFileInfo
|
||||||
{
|
{
|
||||||
protected MutableDatabaseBackedStoreWithFileIncludes(IDatabaseContextFactory contextFactory, Storage storage = null)
|
protected MutableDatabaseBackedStoreWithFileIncludes(IDatabaseContextFactory contextFactory, Storage storage = null)
|
||||||
: base(contextFactory, storage)
|
: base(contextFactory, storage)
|
||||||
|
@ -119,7 +119,7 @@ namespace osu.Game.Graphics
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(screenshotFormat));
|
throw new InvalidOperationException($"Unknown enum member {nameof(ScreenshotFormat)} {screenshotFormat.Value}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationOverlay.Post(new SimpleNotification
|
notificationOverlay.Post(new SimpleNotification
|
||||||
|
@ -7,15 +7,15 @@ using osu.Framework.Graphics.UserInterface;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterfaceV2
|
namespace osu.Game.Graphics.UserInterfaceV2
|
||||||
{
|
{
|
||||||
public abstract class LabelledComponent<T, U> : LabelledDrawable<T>, IHasCurrentValue<U>
|
public abstract class LabelledComponent<TDrawable, TValue> : LabelledDrawable<TDrawable>, IHasCurrentValue<TValue>
|
||||||
where T : Drawable, IHasCurrentValue<U>
|
where TDrawable : Drawable, IHasCurrentValue<TValue>
|
||||||
{
|
{
|
||||||
protected LabelledComponent(bool padded)
|
protected LabelledComponent(bool padded)
|
||||||
: base(padded)
|
: base(padded)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bindable<U> Current
|
public Bindable<TValue> Current
|
||||||
{
|
{
|
||||||
get => Component.Current;
|
get => Component.Current;
|
||||||
set => Component.Current = value;
|
set => Component.Current = value;
|
||||||
|
@ -116,13 +116,13 @@ namespace osu.Game.IO.Legacy
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Reads a generic Dictionary from the buffer. </summary>
|
/// <summary> Reads a generic Dictionary from the buffer. </summary>
|
||||||
public IDictionary<T, U> ReadDictionary<T, U>()
|
public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>()
|
||||||
{
|
{
|
||||||
int count = ReadInt32();
|
int count = ReadInt32();
|
||||||
if (count < 0) return null;
|
if (count < 0) return null;
|
||||||
|
|
||||||
IDictionary<T, U> d = new Dictionary<T, U>();
|
IDictionary<TKey, TValue> d = new Dictionary<TKey, TValue>();
|
||||||
for (int i = 0; i < count; i++) d[(T)ReadObject()] = (U)ReadObject();
|
for (int i = 0; i < count; i++) d[(TKey)ReadObject()] = (TValue)ReadObject();
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ namespace osu.Game.IO.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DynamicDeserializer
|
public static class DynamicDeserializer
|
||||||
{
|
{
|
||||||
private static VersionConfigToNamespaceAssemblyObjectBinder versionBinder;
|
private static VersionConfigToNamespaceAssemblyObjectBinder versionBinder;
|
||||||
private static BinaryFormatter formatter;
|
private static BinaryFormatter formatter;
|
||||||
|
@ -102,7 +102,7 @@ namespace osu.Game.IO.Legacy
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Writes a generic IDictionary to the buffer. </summary>
|
/// <summary> Writes a generic IDictionary to the buffer. </summary>
|
||||||
public void Write<T, U>(IDictionary<T, U> d)
|
public void Write<TKey, TValue>(IDictionary<TKey, TValue> d)
|
||||||
{
|
{
|
||||||
if (d == null)
|
if (d == null)
|
||||||
{
|
{
|
||||||
@ -112,7 +112,7 @@ namespace osu.Game.IO.Legacy
|
|||||||
{
|
{
|
||||||
Write(d.Count);
|
Write(d.Count);
|
||||||
|
|
||||||
foreach (KeyValuePair<T, U> kvp in d)
|
foreach (KeyValuePair<TKey, TValue> kvp in d)
|
||||||
{
|
{
|
||||||
WriteObject(kvp.Key);
|
WriteObject(kvp.Key);
|
||||||
WriteObject(kvp.Value);
|
WriteObject(kvp.Value);
|
||||||
|
@ -10,6 +10,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ExceptionExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -249,7 +250,7 @@ namespace osu.Game.Online.API
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// if we couldn't deserialize the error message let's throw the original exception outwards.
|
// if we couldn't deserialize the error message let's throw the original exception outwards.
|
||||||
throw e;
|
e.Rethrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ namespace osu.Game.Online.API
|
|||||||
// attempt to decode a displayable error string.
|
// attempt to decode a displayable error string.
|
||||||
var error = JsonConvert.DeserializeObject<DisplayableError>(responseString);
|
var error = JsonConvert.DeserializeObject<DisplayableError>(responseString);
|
||||||
if (error != null)
|
if (error != null)
|
||||||
e = new Exception(error.ErrorMessage, e);
|
e = new APIException(error.ErrorMessage, e);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -154,6 +154,14 @@ namespace osu.Game.Online.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class APIException : InvalidOperationException
|
||||||
|
{
|
||||||
|
public APIException(string messsage, Exception innerException)
|
||||||
|
: base(messsage, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public delegate void APIFailureHandler(Exception e);
|
public delegate void APIFailureHandler(Exception e);
|
||||||
|
|
||||||
public delegate void APISuccessHandler();
|
public delegate void APISuccessHandler();
|
||||||
|
@ -20,7 +20,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Online.Leaderboards
|
namespace osu.Game.Online.Leaderboards
|
||||||
{
|
{
|
||||||
public abstract class Leaderboard<TScope, ScoreInfo> : Container, IOnlineComponent
|
public abstract class Leaderboard<TScope, TScoreInfo> : Container, IOnlineComponent
|
||||||
{
|
{
|
||||||
private const double fade_duration = 300;
|
private const double fade_duration = 300;
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
private IEnumerable<ScoreInfo> scores;
|
private IEnumerable<TScoreInfo> scores;
|
||||||
|
|
||||||
public IEnumerable<ScoreInfo> Scores
|
public IEnumerable<TScoreInfo> Scores
|
||||||
{
|
{
|
||||||
get => scores;
|
get => scores;
|
||||||
set
|
set
|
||||||
@ -293,7 +293,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scoresCallback">A callback which should be called when fetching is completed. Scheduling is not required.</param>
|
/// <param name="scoresCallback">A callback which should be called when fetching is completed. Scheduling is not required.</param>
|
||||||
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
|
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
|
||||||
protected abstract APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback);
|
protected abstract APIRequest FetchScores(Action<IEnumerable<TScoreInfo>> scoresCallback);
|
||||||
|
|
||||||
private Placeholder currentPlaceholder;
|
private Placeholder currentPlaceholder;
|
||||||
|
|
||||||
@ -364,6 +364,6 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract LeaderboardScore CreateDrawableScore(ScoreInfo model, int index);
|
protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -54,9 +55,11 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
private FillFlowContainer<ModIcon> modsContainer;
|
private FillFlowContainer<ModIcon> modsContainer;
|
||||||
|
|
||||||
private List<ScoreComponentLabel> statisticsLabels;
|
private List<ScoreComponentLabel> statisticsLabels;
|
||||||
|
|
||||||
private DialogOverlay dialogOverlay;
|
private DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
|
public Action RefreshAction { get; set; }
|
||||||
|
|
||||||
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
|
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
|
||||||
{
|
{
|
||||||
this.score = score;
|
this.score = score;
|
||||||
@ -367,9 +370,15 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
public MenuItem[] ContextMenuItems
|
||||||
{
|
{
|
||||||
new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new BeatmapClearScoresDialog(this.score, null)))
|
get
|
||||||
};
|
{
|
||||||
|
return (this.allowHighlight) ? null : new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new BeatmapClearScoresDialog(this.score, () => Schedule(this.RefreshAction))))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
Filter.Search.Current.ValueChanged += text =>
|
Filter.Search.Current.ValueChanged += text =>
|
||||||
{
|
{
|
||||||
if (text.NewValue != string.Empty)
|
if (!string.IsNullOrEmpty(text.NewValue))
|
||||||
{
|
{
|
||||||
Header.Tabs.Current.Value = DirectTab.Search;
|
Header.Tabs.Current.Value = DirectTab.Search;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModButton[] buttons = { };
|
private ModButton[] buttons = Array.Empty<ModButton>();
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
|
@ -239,7 +239,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
|
|
||||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||||
{
|
{
|
||||||
public IEnumerable<string> FilterTerms => new string[] { };
|
public IEnumerable<string> FilterTerms => Array.Empty<string>();
|
||||||
|
|
||||||
public bool MatchingFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays
|
|||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
};
|
};
|
||||||
|
|
||||||
private class OverlayHeaderTabItem : OverlayTabItem<string>
|
private class OverlayHeaderTabItem : OverlayTabItem
|
||||||
{
|
{
|
||||||
public OverlayHeaderTabItem(string value)
|
public OverlayHeaderTabItem(string value)
|
||||||
: base(value)
|
: base(value)
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
foreach (TabItem<T> tabItem in TabContainer)
|
foreach (TabItem<T> tabItem in TabContainer)
|
||||||
{
|
{
|
||||||
((OverlayTabItem<T>)tabItem).AccentColour = value;
|
((OverlayTabItem)tabItem).AccentColour = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,9 +59,9 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
protected override Dropdown<T> CreateDropdown() => null;
|
protected override Dropdown<T> CreateDropdown() => null;
|
||||||
|
|
||||||
protected override TabItem<T> CreateTabItem(T value) => new OverlayTabItem<T>(value);
|
protected override TabItem<T> CreateTabItem(T value) => new OverlayTabItem(value);
|
||||||
|
|
||||||
protected class OverlayTabItem<U> : TabItem<U>
|
protected class OverlayTabItem : TabItem<T>
|
||||||
{
|
{
|
||||||
private readonly ExpandingBar bar;
|
private readonly ExpandingBar bar;
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OverlayTabItem(U value)
|
public OverlayTabItem(T value)
|
||||||
: base(value)
|
: base(value)
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.X;
|
AutoSizeAxes = Axes.X;
|
||||||
|
@ -38,5 +38,15 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
|
|||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected override int GetCount(User user) => type switch
|
||||||
|
{
|
||||||
|
BeatmapSetType.Favourite => user.FavouriteBeatmapsetCount,
|
||||||
|
BeatmapSetType.Graveyard => user.GraveyardBeatmapsetCount,
|
||||||
|
BeatmapSetType.Loved => user.LovedBeatmapsetCount,
|
||||||
|
BeatmapSetType.RankedAndApproved => user.RankedAndApprovedBeatmapsetCount,
|
||||||
|
BeatmapSetType.Unranked => user.UnrankedBeatmapsetCount,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
osu.Game/Overlays/Profile/Sections/CounterPill.cs
Normal file
61
osu.Game/Overlays/Profile/Sections/CounterPill.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Sections
|
||||||
|
{
|
||||||
|
public class CounterPill : CircularContainer
|
||||||
|
{
|
||||||
|
private const int duration = 200;
|
||||||
|
|
||||||
|
public readonly BindableInt Current = new BindableInt();
|
||||||
|
|
||||||
|
private readonly OsuSpriteText counter;
|
||||||
|
|
||||||
|
public CounterPill()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Alpha = 0;
|
||||||
|
Masking = true;
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuColour.Gray(0.05f)
|
||||||
|
},
|
||||||
|
counter = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Margin = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||||
|
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
Current.BindValueChanged(onCurrentChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCurrentChanged(ValueChangedEvent<int> value)
|
||||||
|
{
|
||||||
|
if (value.NewValue == 0)
|
||||||
|
{
|
||||||
|
this.FadeOut(duration, Easing.OutQuint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter.Text = value.NewValue.ToString();
|
||||||
|
this.FadeIn(duration, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
private readonly OsuSpriteText missingText;
|
private readonly OsuSpriteText missingText;
|
||||||
private APIRequest<List<TModel>> retrievalRequest;
|
private APIRequest<List<TModel>> retrievalRequest;
|
||||||
private CancellationTokenSource loadCancellation;
|
private CancellationTokenSource loadCancellation;
|
||||||
|
private readonly BindableInt count = new BindableInt();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
@ -44,11 +45,28 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Text = header,
|
AutoSizeAxes = Axes.Both,
|
||||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold),
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5, 0),
|
||||||
Margin = new MarginPadding { Top = 10, Bottom = 10 },
|
Margin = new MarginPadding { Top = 10, Bottom = 10 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Text = header,
|
||||||
|
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold),
|
||||||
|
},
|
||||||
|
new CounterPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Current = { BindTarget = count }
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ItemsContainer = new FillFlowContainer
|
ItemsContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -91,7 +109,10 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
ItemsContainer.Clear();
|
ItemsContainer.Clear();
|
||||||
|
|
||||||
if (e.NewValue != null)
|
if (e.NewValue != null)
|
||||||
|
{
|
||||||
showMore();
|
showMore();
|
||||||
|
count.Value = GetCount(e.NewValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMore()
|
private void showMore()
|
||||||
@ -124,6 +145,8 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
}, loadCancellation.Token);
|
}, loadCancellation.Token);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
protected virtual int GetCount(User user) => 0;
|
||||||
|
|
||||||
protected abstract APIRequest<List<TModel>> CreateRequest();
|
protected abstract APIRequest<List<TModel>> CreateRequest();
|
||||||
|
|
||||||
protected abstract Drawable CreateDrawableItem(TModel model);
|
protected abstract Drawable CreateDrawableItem(TModel model);
|
||||||
|
@ -32,6 +32,12 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
|||||||
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
|
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
|
||||||
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
||||||
|
|
||||||
|
protected override int GetCount(User user) => type switch
|
||||||
|
{
|
||||||
|
ScoreType.Firsts => user.ScoresFirstCount,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
protected override Drawable CreateDrawableItem(APILegacyScoreInfo model)
|
protected override Drawable CreateDrawableItem(APILegacyScoreInfo model)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -12,11 +12,11 @@ namespace osu.Game.Overlays.Settings
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SettingsSlider<T, U> : SettingsItem<T>
|
public class SettingsSlider<TValue, TSlider> : SettingsItem<TValue>
|
||||||
where T : struct, IEquatable<T>, IComparable<T>, IConvertible
|
where TValue : struct, IEquatable<TValue>, IComparable<TValue>, IConvertible
|
||||||
where U : OsuSliderBar<T>, new()
|
where TSlider : OsuSliderBar<TValue>, new()
|
||||||
{
|
{
|
||||||
protected override Drawable CreateControl() => new U
|
protected override Drawable CreateControl() => new TSlider
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding { Top = 5, Bottom = 5 },
|
Margin = new MarginPadding { Top = 5, Bottom = 5 },
|
||||||
RelativeSizeAxes = Axes.X
|
RelativeSizeAxes = Axes.X
|
||||||
@ -24,14 +24,14 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public bool TransferValueOnCommit
|
public bool TransferValueOnCommit
|
||||||
{
|
{
|
||||||
get => ((U)Control).TransferValueOnCommit;
|
get => ((TSlider)Control).TransferValueOnCommit;
|
||||||
set => ((U)Control).TransferValueOnCommit = value;
|
set => ((TSlider)Control).TransferValueOnCommit = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float KeyboardStep
|
public float KeyboardStep
|
||||||
{
|
{
|
||||||
get => ((U)Control).KeyboardStep;
|
get => ((TSlider)Control).KeyboardStep;
|
||||||
set => ((U)Control).KeyboardStep = value;
|
set => ((TSlider)Control).KeyboardStep = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -55,10 +56,7 @@ namespace osu.Game.Overlays
|
|||||||
new BeatmapsSection(),
|
new BeatmapsSection(),
|
||||||
new KudosuSection()
|
new KudosuSection()
|
||||||
}
|
}
|
||||||
: new ProfileSection[]
|
: Array.Empty<ProfileSection>();
|
||||||
{
|
|
||||||
//new AboutSection(),
|
|
||||||
};
|
|
||||||
|
|
||||||
tabs = new ProfileTabControl
|
tabs = new ProfileTabControl
|
||||||
{
|
{
|
||||||
@ -167,7 +165,7 @@ namespace osu.Game.Overlays
|
|||||||
AccentColour = colours.Seafoam;
|
AccentColour = colours.Seafoam;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProfileTabItem : OverlayTabItem<ProfileSection>
|
private class ProfileTabItem : OverlayTabItem
|
||||||
{
|
{
|
||||||
public ProfileTabItem(ProfileSection value)
|
public ProfileTabItem(ProfileSection value)
|
||||||
: base(value)
|
: base(value)
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Difficulty.Utils
|
|||||||
public LimitedCapacityStack(int capacity)
|
public LimitedCapacityStack(int capacity)
|
||||||
{
|
{
|
||||||
if (capacity < 0)
|
if (capacity < 0)
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||||
|
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
array = new T[capacity];
|
array = new T[capacity];
|
||||||
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Difficulty.Utils
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (i < 0 || i > Count - 1)
|
if (i < 0 || i > Count - 1)
|
||||||
throw new IndexOutOfRangeException();
|
throw new ArgumentOutOfRangeException(nameof(i));
|
||||||
|
|
||||||
i += marker;
|
i += marker;
|
||||||
if (i > capacity - 1)
|
if (i > capacity - 1)
|
||||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// The mods this mod cannot be enabled with.
|
/// The mods this mod cannot be enabled with.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual Type[] IncompatibleMods => new Type[] { };
|
public virtual Type[] IncompatibleMods => Array.Empty<Type>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
|
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
|
||||||
|
@ -150,8 +150,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
|
|
||||||
if (HitObject.SampleControlPoint == null)
|
if (HitObject.SampleControlPoint == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
|
throw new InvalidOperationException($"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
|
||||||
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray();
|
samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray();
|
||||||
|
@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
int repeatCount = Parsing.ParseInt(split[6]);
|
int repeatCount = Parsing.ParseInt(split[6]);
|
||||||
|
|
||||||
if (repeatCount > 9000)
|
if (repeatCount > 9000)
|
||||||
throw new ArgumentOutOfRangeException(nameof(repeatCount), @"Repeat count is way too high");
|
throw new FormatException(@"Repeat count is way too high");
|
||||||
|
|
||||||
// osu-stable treated the first span of the slider as a repeat, but no repeats are happening
|
// osu-stable treated the first span of the slider as a repeat, but no repeats are happening
|
||||||
repeatCount = Math.Max(0, repeatCount - 1);
|
repeatCount = Math.Max(0, repeatCount - 1);
|
||||||
|
@ -18,6 +18,7 @@ using osu.Game.Beatmaps.Legacy;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Configuration;
|
using osu.Game.Rulesets.Configuration;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ namespace osu.Game.Rulesets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mods">The legacy enum which will be converted</param>
|
/// <param name="mods">The legacy enum which will be converted</param>
|
||||||
/// <returns>An enumerable of constructed <see cref="Mod"/>s</returns>
|
/// <returns>An enumerable of constructed <see cref="Mod"/>s</returns>
|
||||||
public virtual IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) => new Mod[] { };
|
public virtual IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) => Array.Empty<Mod>();
|
||||||
|
|
||||||
public ModAutoplay GetAutoplayMod() => GetAllMods().OfType<ModAutoplay>().First();
|
public ModAutoplay GetAutoplayMod() => GetAllMods().OfType<ModAutoplay>().First();
|
||||||
|
|
||||||
@ -62,6 +63,12 @@ namespace osu.Game.Rulesets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null);
|
public abstract DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="ScoreProcessor"/> for a beatmap converted to this ruleset.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The score processor.</returns>
|
||||||
|
public virtual ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ScoreProcessor(beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
|
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -116,7 +123,7 @@ namespace osu.Game.Rulesets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="variant">A variant.</param>
|
/// <param name="variant">A variant.</param>
|
||||||
/// <returns>A list of valid <see cref="KeyBinding"/>s.</returns>
|
/// <returns>A list of valid <see cref="KeyBinding"/>s.</returns>
|
||||||
public virtual IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new KeyBinding[] { };
|
public virtual IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => Array.Empty<KeyBinding>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name for a key binding variant. This is used for display in the settings overlay.
|
/// Gets the name for a key binding variant. This is used for display in the settings overlay.
|
||||||
|
@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
return miss;
|
return miss;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException(nameof(result));
|
throw new ArgumentException("Unknown enum member", nameof(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,8 +305,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <returns>The Playfield.</returns>
|
/// <returns>The Playfield.</returns>
|
||||||
protected abstract Playfield CreatePlayfield();
|
protected abstract Playfield CreatePlayfield();
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor(Beatmap);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the active mods to this DrawableRuleset.
|
/// Applies the active mods to this DrawableRuleset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -475,13 +473,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// Invoked when the user requests to pause while the resume overlay is active.
|
/// Invoked when the user requests to pause while the resume overlay is active.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void CancelResume();
|
public abstract void CancelResume();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a <see cref="ScoreProcessor"/> for the associated ruleset and link with this
|
|
||||||
/// <see cref="DrawableRuleset"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A score processor.</returns>
|
|
||||||
public abstract ScoreProcessor CreateScoreProcessor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BeatmapInvalidForRulesetException : ArgumentException
|
public class BeatmapInvalidForRulesetException : ArgumentException
|
||||||
@ -515,34 +506,34 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
public Stream GetStream(string name) => primary.GetStream(name) ?? secondary.GetStream(name);
|
public Stream GetStream(string name) => primary.GetStream(name) ?? secondary.GetStream(name);
|
||||||
|
|
||||||
public IEnumerable<string> GetAvailableResources() => throw new NotImplementedException();
|
public IEnumerable<string> GetAvailableResources() => throw new NotSupportedException();
|
||||||
|
|
||||||
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotImplementedException();
|
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotSupportedException();
|
||||||
|
|
||||||
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotImplementedException();
|
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotSupportedException();
|
||||||
|
|
||||||
public BindableNumber<double> Volume => throw new NotImplementedException();
|
public BindableNumber<double> Volume => throw new NotSupportedException();
|
||||||
|
|
||||||
public BindableNumber<double> Balance => throw new NotImplementedException();
|
public BindableNumber<double> Balance => throw new NotSupportedException();
|
||||||
|
|
||||||
public BindableNumber<double> Frequency => throw new NotImplementedException();
|
public BindableNumber<double> Frequency => throw new NotSupportedException();
|
||||||
|
|
||||||
public BindableNumber<double> Tempo => throw new NotImplementedException();
|
public BindableNumber<double> Tempo => throw new NotSupportedException();
|
||||||
|
|
||||||
public IBindable<double> GetAggregate(AdjustableProperty type) => throw new NotImplementedException();
|
public IBindable<double> GetAggregate(AdjustableProperty type) => throw new NotSupportedException();
|
||||||
|
|
||||||
public IBindable<double> AggregateVolume => throw new NotImplementedException();
|
public IBindable<double> AggregateVolume => throw new NotSupportedException();
|
||||||
|
|
||||||
public IBindable<double> AggregateBalance => throw new NotImplementedException();
|
public IBindable<double> AggregateBalance => throw new NotSupportedException();
|
||||||
|
|
||||||
public IBindable<double> AggregateFrequency => throw new NotImplementedException();
|
public IBindable<double> AggregateFrequency => throw new NotSupportedException();
|
||||||
|
|
||||||
public IBindable<double> AggregateTempo => throw new NotImplementedException();
|
public IBindable<double> AggregateTempo => throw new NotSupportedException();
|
||||||
|
|
||||||
public int PlaybackConcurrency
|
public int PlaybackConcurrency
|
||||||
{
|
{
|
||||||
get => throw new NotImplementedException();
|
get => throw new NotSupportedException();
|
||||||
set => throw new NotImplementedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<string> GetStableImportPaths(Storage stableStorage)
|
protected override IEnumerable<string> GetStableImportPaths(Storage stableStorage)
|
||||||
=> stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.InvariantCultureIgnoreCase) ?? false));
|
=> stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false));
|
||||||
|
|
||||||
public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store);
|
public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store);
|
||||||
|
|
||||||
@ -69,6 +69,8 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
protected override ArchiveDownloadRequest<ScoreInfo> CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
protected override ArchiveDownloadRequest<ScoreInfo> CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
||||||
|
|
||||||
protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable<ScoreInfo> items) => items.Any(s => s.Equals(model) && s.Files.Any());
|
protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable<ScoreInfo> items)
|
||||||
|
=> base.CheckLocalAvailability(model, items)
|
||||||
|
|| (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);
|
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);
|
||||||
|
|
||||||
ScoreProcessor = DrawableRuleset.CreateScoreProcessor();
|
ScoreProcessor = ruleset.CreateScoreProcessor(playableBeatmap);
|
||||||
ScoreProcessor.Mods.BindTo(Mods);
|
ScoreProcessor.Mods.BindTo(Mods);
|
||||||
|
|
||||||
if (!ScoreProcessor.Mode.Disabled)
|
if (!ScoreProcessor.Mode.Disabled)
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play
|
|||||||
: base(() => new ReplayPlayer(score))
|
: base(() => new ReplayPlayer(score))
|
||||||
{
|
{
|
||||||
if (score.Replay == null)
|
if (score.Replay == null)
|
||||||
throw new ArgumentNullException(nameof(score.Replay), $"{nameof(score)} must have a non-null {nameof(score.Replay)}.");
|
throw new ArgumentException($"{nameof(score)} must have a non-null {nameof(score.Replay)}.", nameof(score));
|
||||||
|
|
||||||
scoreInfo = score.ScoreInfo;
|
scoreInfo = score.ScoreInfo;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float[] calculatedValues = { }; // values but adjusted to fit the amount of columns
|
private float[] calculatedValues = Array.Empty<float>(); // values but adjusted to fit the amount of columns
|
||||||
|
|
||||||
private int[] values;
|
private int[] values;
|
||||||
|
|
||||||
|
@ -52,11 +52,7 @@ namespace osu.Game.Screens.Select
|
|||||||
new PopupDialogOkButton
|
new PopupDialogOkButton
|
||||||
{
|
{
|
||||||
Text = @"Yes. Please.",
|
Text = @"Yes. Please.",
|
||||||
Action = () =>
|
Action = (() => scoreManager.Delete(score)) + onCompletion
|
||||||
{
|
|
||||||
Task.Run(() => scoreManager.Delete(score))
|
|
||||||
.ContinueWith(_ => onCompletion);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new PopupDialogCancelButton
|
new PopupDialogCancelButton
|
||||||
{
|
{
|
||||||
|
@ -37,13 +37,13 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case SortMode.Artist:
|
case SortMode.Artist:
|
||||||
return string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase);
|
return string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
case SortMode.Title:
|
case SortMode.Title:
|
||||||
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase);
|
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
case SortMode.Author:
|
case SortMode.Author:
|
||||||
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.InvariantCultureIgnoreCase);
|
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
case SortMode.DateAdded:
|
case SortMode.DateAdded:
|
||||||
return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded);
|
return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded);
|
||||||
|
@ -27,8 +27,8 @@ namespace osu.Game.Screens.Select.Details
|
|||||||
|
|
||||||
metrics = value;
|
metrics = value;
|
||||||
|
|
||||||
var retries = Metrics?.Retries ?? new int[0];
|
var retries = Metrics?.Retries ?? Array.Empty<int>();
|
||||||
var fails = Metrics?.Fails ?? new int[0];
|
var fails = Metrics?.Fails ?? Array.Empty<int>();
|
||||||
|
|
||||||
float maxValue = fails.Any() ? fails.Zip(retries, (fail, retry) => fail + retry).Max() : 0;
|
float maxValue = fails.Any() ? fails.Zip(retries, (fail, retry) => fail + retry).Max() : 0;
|
||||||
failGraph.MaxValue = maxValue;
|
failGraph.MaxValue = maxValue;
|
||||||
|
@ -105,7 +105,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public string SearchTerm;
|
public string SearchTerm;
|
||||||
|
|
||||||
public bool Equals(OptionalTextFilter other) => SearchTerm?.Equals(other.SearchTerm) ?? true;
|
public bool Equals(OptionalTextFilter other) => SearchTerm == other.SearchTerm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,12 +182,14 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index){
|
protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index)
|
||||||
|
{
|
||||||
model.Beatmap = beatmap;
|
model.Beatmap = beatmap;
|
||||||
|
|
||||||
return new LeaderboardScore(model, index, IsOnlineScope)
|
return new LeaderboardScore(model, index, IsOnlineScope)
|
||||||
{
|
{
|
||||||
Action = () => ScoreSelected?.Invoke(model)
|
Action = () => ScoreSelected?.Invoke(model),
|
||||||
|
RefreshAction = () => this.RefreshScores()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string getPathForFile(string filename) =>
|
private string getPathForFile(string filename) =>
|
||||||
source.Files.Find(f => string.Equals(f.Filename, filename, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
source.Files.Find(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
||||||
|
|
||||||
public override IEnumerable<string> GetAvailableResources() => source.Files.Select(f => f.Filename);
|
public override IEnumerable<string> GetAvailableResources() => source.Files.Select(f => f.Filename);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,11 @@ namespace osu.Game.Skinning
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SkinReloadableDrawable : CompositeDrawable
|
public abstract class SkinReloadableDrawable : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when <see cref="CurrentSkin"/> has changed.
|
||||||
|
/// </summary>
|
||||||
|
public event Action OnSkinChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current skin source.
|
/// The current skin source.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -43,12 +48,18 @@ namespace osu.Game.Skinning
|
|||||||
private void onChange() =>
|
private void onChange() =>
|
||||||
// schedule required to avoid calls after disposed.
|
// schedule required to avoid calls after disposed.
|
||||||
// note that this has the side-effect of components only performing a skin change when they are alive.
|
// note that this has the side-effect of components only performing a skin change when they are alive.
|
||||||
Scheduler.AddOnce(() => SkinChanged(CurrentSkin, allowDefaultFallback));
|
Scheduler.AddOnce(skinChanged);
|
||||||
|
|
||||||
protected override void LoadAsyncComplete()
|
protected override void LoadAsyncComplete()
|
||||||
{
|
{
|
||||||
base.LoadAsyncComplete();
|
base.LoadAsyncComplete();
|
||||||
|
skinChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skinChanged()
|
||||||
|
{
|
||||||
SkinChanged(CurrentSkin, allowDefaultFallback);
|
SkinChanged(CurrentSkin, allowDefaultFallback);
|
||||||
|
OnSkinChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -66,6 +77,8 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
if (CurrentSkin != null)
|
if (CurrentSkin != null)
|
||||||
CurrentSkin.SourceChanged -= onChange;
|
CurrentSkin.SourceChanged -= onChange;
|
||||||
|
|
||||||
|
OnSkinChanged = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
{
|
{
|
||||||
var framePath = Animation.Path.Replace(".", frame + ".");
|
var framePath = Animation.Path.Replace(".", frame + ".");
|
||||||
|
|
||||||
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IBindable<WorkingBeatmap> beatmap, TextureStore textureStore)
|
private void load(IBindable<WorkingBeatmap> beatmap, TextureStore textureStore)
|
||||||
{
|
{
|
||||||
var path = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
var path = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -126,6 +126,24 @@ namespace osu.Game.Users
|
|||||||
[JsonProperty(@"follower_count")]
|
[JsonProperty(@"follower_count")]
|
||||||
public int FollowerCount;
|
public int FollowerCount;
|
||||||
|
|
||||||
|
[JsonProperty(@"favourite_beatmapset_count")]
|
||||||
|
public int FavouriteBeatmapsetCount;
|
||||||
|
|
||||||
|
[JsonProperty(@"graveyard_beatmapset_count")]
|
||||||
|
public int GraveyardBeatmapsetCount;
|
||||||
|
|
||||||
|
[JsonProperty(@"loved_beatmapset_count")]
|
||||||
|
public int LovedBeatmapsetCount;
|
||||||
|
|
||||||
|
[JsonProperty(@"ranked_and_approved_beatmapset_count")]
|
||||||
|
public int RankedAndApprovedBeatmapsetCount;
|
||||||
|
|
||||||
|
[JsonProperty(@"unranked_beatmapset_count")]
|
||||||
|
public int UnrankedBeatmapsetCount;
|
||||||
|
|
||||||
|
[JsonProperty(@"scores_first_count")]
|
||||||
|
public int ScoresFirstCount;
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
private string[] playstyle
|
private string[] playstyle
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Users
|
|||||||
private void load(UserProfileOverlay profile)
|
private void load(UserProfileOverlay profile)
|
||||||
{
|
{
|
||||||
if (colours == null)
|
if (colours == null)
|
||||||
throw new ArgumentNullException(nameof(colours));
|
throw new InvalidOperationException($"{nameof(colours)} not initialized!");
|
||||||
|
|
||||||
FillFlowContainer infoContainer;
|
FillFlowContainer infoContainer;
|
||||||
|
|
||||||
|
1
osu.sln
1
osu.sln
@ -60,6 +60,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
global.json = global.json
|
global.json = global.json
|
||||||
osu.Android.props = osu.Android.props
|
osu.Android.props = osu.Android.props
|
||||||
osu.iOS.props = osu.iOS.props
|
osu.iOS.props = osu.iOS.props
|
||||||
|
CodeAnalysis\osu.ruleset = CodeAnalysis\osu.ruleset
|
||||||
osu.sln.DotSettings = osu.sln.DotSettings
|
osu.sln.DotSettings = osu.sln.DotSettings
|
||||||
osu.TestProject.props = osu.TestProject.props
|
osu.TestProject.props = osu.TestProject.props
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
|
Loading…
Reference in New Issue
Block a user