Merge branch 'master' into fix-effect-points
@ -176,8 +176,8 @@ dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
|||||||
#Style - C# 8 features
|
#Style - C# 8 features
|
||||||
csharp_prefer_static_local_function = true:warning
|
csharp_prefer_static_local_function = true:warning
|
||||||
csharp_prefer_simple_using_statement = true:silent
|
csharp_prefer_simple_using_statement = true:silent
|
||||||
csharp_style_prefer_index_operator = false:none
|
csharp_style_prefer_index_operator = true:warning
|
||||||
csharp_style_prefer_range_operator = false:none
|
csharp_style_prefer_range_operator = true:warning
|
||||||
csharp_style_prefer_switch_expression = false:none
|
csharp_style_prefer_switch_expression = false:none
|
||||||
|
|
||||||
#Supressing roslyn built-in analyzers
|
#Supressing roslyn built-in analyzers
|
||||||
|
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>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#addin "nuget:?package=CodeFileSanity&version=0.0.33"
|
#addin "nuget:?package=CodeFileSanity&version=0.0.33"
|
||||||
#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2019.2.1"
|
#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2019.3.0"
|
||||||
#tool "nuget:?package=NVika.MSBuild&version=1.0.1"
|
#tool "nuget:?package=NVika.MSBuild&version=1.0.1"
|
||||||
var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First();
|
var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First();
|
||||||
|
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"sdk": {
|
||||||
|
"allowPrerelease": false,
|
||||||
|
"rollForward": "minor",
|
||||||
|
"version": "3.1.100"
|
||||||
|
},
|
||||||
"msbuild-sdks": {
|
"msbuild-sdks": {
|
||||||
"Microsoft.Build.Traversal": "2.0.24"
|
"Microsoft.Build.Traversal": "2.0.24"
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1215.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1212.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1215.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
|
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||||
return base.CreatePlayer(ruleset);
|
return base.CreatePlayer(ruleset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
|
|
||||||
private void addToPlayfield(DrawableCatchHitObject drawable)
|
private void addToPlayfield(DrawableCatchHitObject drawable)
|
||||||
{
|
{
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
|
|
||||||
drawableRuleset.Playfield.Add(drawable);
|
drawableRuleset.Playfield.Add(drawable);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Game.Rulesets.Catch.Mods;
|
using osu.Game.Rulesets.Catch.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
@ -12,9 +13,10 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(CatchModHidden) }).ToList();
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(CatchModHidden) }).ToList();
|
||||||
|
|
||||||
public TestSceneDrawableHitObjectsHidden()
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
Mods.Value = new[] { new CatchModHidden() };
|
SelectedMods.Value = new[] { new CatchModHidden() };
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
@ -51,7 +57,9 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||||
yield return new CatchModSuddenDeath();
|
yield return new CatchModSuddenDeath();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
if (mods.HasFlag(LegacyMods.Cinema))
|
||||||
|
yield return new CatchModCinema();
|
||||||
|
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
yield return new CatchModAutoplay();
|
yield return new CatchModAutoplay();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Easy))
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
@ -101,7 +109,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
return new Mod[]
|
return new Mod[]
|
||||||
{
|
{
|
||||||
new MultiMod(new CatchModAutoplay(), new ModCinema()),
|
new MultiMod(new CatchModAutoplay(), new CatchModCinema()),
|
||||||
new CatchModRelax(),
|
new CatchModRelax(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -112,7 +120,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new Mod[] { };
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Mods
|
||||||
|
{
|
||||||
|
public class CatchModCinema : ModCinema<CatchHitObject>
|
||||||
|
{
|
||||||
|
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||||
|
{
|
||||||
|
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
|
||||||
|
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
|
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
path.ControlPoints.AddRange(value.ControlPoints);
|
path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position.Value, c.Type.Value)));
|
||||||
path.ExpectedDistance.Value = value.ExpectedDistance.Value;
|
path.ExpectedDistance.Value = value.ExpectedDistance.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
prevNoteTimes.RemoveAt(0);
|
prevNoteTimes.RemoveAt(0);
|
||||||
prevNoteTimes.Add(newNoteTime);
|
prevNoteTimes.Add(newNoteTime);
|
||||||
|
|
||||||
density = (prevNoteTimes[prevNoteTimes.Count - 1] - prevNoteTimes[0]) / prevNoteTimes.Count;
|
density = (prevNoteTimes[^1] - prevNoteTimes[0]) / prevNoteTimes.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double lastTime;
|
private double lastTime;
|
||||||
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Difficulty.Skills;
|
using osu.Game.Rulesets.Difficulty.Skills;
|
||||||
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
||||||
{
|
{
|
||||||
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
|||||||
protected override double StrainValueOf(DifficultyHitObject current)
|
protected override double StrainValueOf(DifficultyHitObject current)
|
||||||
{
|
{
|
||||||
var maniaCurrent = (ManiaDifficultyHitObject)current;
|
var maniaCurrent = (ManiaDifficultyHitObject)current;
|
||||||
var endTime = (maniaCurrent.BaseObject as HoldNote)?.EndTime ?? maniaCurrent.BaseObject.StartTime;
|
var endTime = maniaCurrent.BaseObject.GetEndTime();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Difficulty.Skills;
|
using osu.Game.Rulesets.Difficulty.Skills;
|
||||||
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
||||||
{
|
{
|
||||||
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
|||||||
protected override double StrainValueOf(DifficultyHitObject current)
|
protected override double StrainValueOf(DifficultyHitObject current)
|
||||||
{
|
{
|
||||||
var maniaCurrent = (ManiaDifficultyHitObject)current;
|
var maniaCurrent = (ManiaDifficultyHitObject)current;
|
||||||
var endTime = (maniaCurrent.BaseObject as HoldNote)?.EndTime ?? maniaCurrent.BaseObject.StartTime;
|
var endTime = maniaCurrent.BaseObject.GetEndTime();
|
||||||
|
|
||||||
double holdFactor = 1.0; // Factor in case something else is held
|
double holdFactor = 1.0; // Factor in case something else is held
|
||||||
double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly
|
double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly
|
||||||
|
@ -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";
|
||||||
@ -51,7 +57,9 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||||
yield return new ManiaModSuddenDeath();
|
yield return new ManiaModSuddenDeath();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
if (mods.HasFlag(LegacyMods.Cinema))
|
||||||
|
yield return new ManiaModCinema();
|
||||||
|
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
yield return new ManiaModAutoplay();
|
yield return new ManiaModAutoplay();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Easy))
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
@ -148,7 +156,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
return new Mod[]
|
return new Mod[]
|
||||||
{
|
{
|
||||||
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
|
new MultiMod(new ManiaModAutoplay(), new ManiaModCinema()),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Fun:
|
case ModType.Fun:
|
||||||
@ -158,7 +166,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new Mod[] { };
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,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)
|
||||||
|
22
osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
|
{
|
||||||
|
public class ManiaModCinema : ModCinema<ManiaHitObject>
|
||||||
|
{
|
||||||
|
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||||
|
{
|
||||||
|
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
|
||||||
|
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
After Width: | Height: | Size: 4.4 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-0.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-2.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-3.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-4.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-5.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-6.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-7.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-8.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-9.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit0.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit100.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit300.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit50.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hitcircle.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 6.9 KiB |
2
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[General]
|
||||||
|
Version: 1.0
|
@ -19,9 +19,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
private Skin metricsSkin;
|
private Skin metricsSkin;
|
||||||
private Skin defaultSkin;
|
private Skin defaultSkin;
|
||||||
private Skin specialSkin;
|
private Skin specialSkin;
|
||||||
|
private Skin oldSkin;
|
||||||
|
|
||||||
protected SkinnableTestScene()
|
protected SkinnableTestScene()
|
||||||
: base(2, 2)
|
: base(2, 3)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/metrics_skin"), audio, true);
|
metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/metrics_skin"), audio, true);
|
||||||
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
|
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
|
||||||
specialSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/special_skin"), audio, true);
|
specialSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/special_skin"), audio, true);
|
||||||
|
oldSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/old_skin"), audio, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetContents(Func<Drawable> creationFunction)
|
public void SetContents(Func<Drawable> creationFunction)
|
||||||
@ -41,6 +43,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Cell(1).Child = createProvider(metricsSkin, creationFunction);
|
Cell(1).Child = createProvider(metricsSkin, creationFunction);
|
||||||
Cell(2).Child = createProvider(defaultSkin, creationFunction);
|
Cell(2).Child = createProvider(defaultSkin, creationFunction);
|
||||||
Cell(3).Child = createProvider(specialSkin, creationFunction);
|
Cell(3).Child = createProvider(specialSkin, creationFunction);
|
||||||
|
Cell(4).Child = createProvider(oldSkin, creationFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable createProvider(Skin skin, Func<Drawable> creationFunction)
|
private Drawable createProvider(Skin skin, Func<Drawable> creationFunction)
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var drawable = CreateDrawableHitCircle(circle, auto);
|
var drawable = CreateDrawableHitCircle(circle, auto);
|
||||||
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
|
|
||||||
return drawable;
|
return drawable;
|
||||||
|
@ -14,9 +14,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
|
||||||
|
|
||||||
public TestSceneHitCircleHidden()
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
Mods.Value = new[] { new OsuModHidden() };
|
SelectedMods.Value = new[] { new OsuModHidden() };
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), };
|
SelectedMods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), };
|
||||||
|
|
||||||
return base.CreatePlayer(ruleset);
|
return base.CreatePlayer(ruleset);
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var drawable = CreateDrawableSlider(slider);
|
var drawable = CreateDrawableSlider(slider);
|
||||||
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
|
|
||||||
drawable.OnNewResult += onNewResult;
|
drawable.OnNewResult += onNewResult;
|
||||||
|
@ -14,9 +14,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
|
||||||
|
|
||||||
public TestSceneSliderHidden()
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
Mods.Value = new[] { new OsuModHidden() };
|
SelectedMods.Value = new[] { new OsuModHidden() };
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,11 +286,11 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
|
private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
|
||||||
|
|
||||||
private bool assertHeadMissTailTracked() => judgementResults[judgementResults.Count - 2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
|
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
|
||||||
|
|
||||||
private bool assertMidSliderJudgements() => judgementResults[judgementResults.Count - 2].Type == HitResult.Great;
|
private bool assertMidSliderJudgements() => judgementResults[^2].Type == HitResult.Great;
|
||||||
|
|
||||||
private bool assertMidSliderJudgementFail() => judgementResults[judgementResults.Count - 2].Type == HitResult.Miss;
|
private bool assertMidSliderJudgementFail() => judgementResults[^2].Type == HitResult.Miss;
|
||||||
|
|
||||||
private ScoreAccessibleReplayPlayer currentPlayer;
|
private ScoreAccessibleReplayPlayer currentPlayer;
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Depth = depthIndex++
|
Depth = depthIndex++
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
|
|
||||||
Add(drawable);
|
Add(drawable);
|
||||||
|
@ -14,9 +14,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
|
||||||
|
|
||||||
public TestSceneSpinnerHidden()
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
Mods.Value = new[] { new OsuModHidden() };
|
SelectedMods.Value = new[] { new OsuModHidden() };
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Lines;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A visualisation of the line between two <see cref="PathControlPointPiece"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public class PathControlPointConnectionPiece : CompositeDrawable
|
||||||
|
{
|
||||||
|
public PathControlPoint ControlPoint;
|
||||||
|
|
||||||
|
private readonly Path path;
|
||||||
|
private readonly Slider slider;
|
||||||
|
|
||||||
|
private IBindable<Vector2> sliderPosition;
|
||||||
|
private IBindable<int> pathVersion;
|
||||||
|
|
||||||
|
public PathControlPointConnectionPiece(Slider slider, PathControlPoint controlPoint)
|
||||||
|
{
|
||||||
|
this.slider = slider;
|
||||||
|
ControlPoint = controlPoint;
|
||||||
|
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChild = path = new SmoothPath
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
PathRadius = 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
sliderPosition = slider.PositionBindable.GetBoundCopy();
|
||||||
|
sliderPosition.BindValueChanged(_ => updateConnectingPath());
|
||||||
|
|
||||||
|
pathVersion = slider.Path.Version.GetBoundCopy();
|
||||||
|
pathVersion.BindValueChanged(_ => updateConnectingPath());
|
||||||
|
|
||||||
|
updateConnectingPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the path connecting this control point to the next one.
|
||||||
|
/// </summary>
|
||||||
|
private void updateConnectingPath()
|
||||||
|
{
|
||||||
|
Position = slider.StackedPosition + ControlPoint.Position.Value;
|
||||||
|
|
||||||
|
path.ClearVertices();
|
||||||
|
|
||||||
|
int index = slider.Path.ControlPoints.IndexOf(ControlPoint) + 1;
|
||||||
|
|
||||||
|
if (index == 0 || index == slider.Path.ControlPoints.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
path.AddVertex(Vector2.Zero);
|
||||||
|
path.AddVertex(slider.Path.ControlPoints[index].Position.Value - ControlPoint.Position.Value);
|
||||||
|
|
||||||
|
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Lines;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -19,6 +18,9 @@ using osuTK.Input;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A visualisation of a single <see cref="PathControlPoint"/> in a <see cref="Slider"/>.
|
||||||
|
/// </summary>
|
||||||
public class PathControlPointPiece : BlueprintPiece<Slider>
|
public class PathControlPointPiece : BlueprintPiece<Slider>
|
||||||
{
|
{
|
||||||
public Action<PathControlPointPiece, MouseButtonEvent> RequestSelection;
|
public Action<PathControlPointPiece, MouseButtonEvent> RequestSelection;
|
||||||
@ -28,7 +30,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
public readonly PathControlPoint ControlPoint;
|
public readonly PathControlPoint ControlPoint;
|
||||||
|
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
private readonly Path path;
|
|
||||||
private readonly Container marker;
|
private readonly Container marker;
|
||||||
private readonly Drawable markerRing;
|
private readonly Drawable markerRing;
|
||||||
|
|
||||||
@ -39,12 +40,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
private OsuColour colours { get; set; }
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
private IBindable<Vector2> sliderPosition;
|
private IBindable<Vector2> sliderPosition;
|
||||||
private IBindable<int> pathVersion;
|
private IBindable<Vector2> controlPointPosition;
|
||||||
|
|
||||||
public PathControlPointPiece(Slider slider, PathControlPoint controlPoint)
|
public PathControlPointPiece(Slider slider, PathControlPoint controlPoint)
|
||||||
{
|
{
|
||||||
this.slider = slider;
|
this.slider = slider;
|
||||||
|
|
||||||
ControlPoint = controlPoint;
|
ControlPoint = controlPoint;
|
||||||
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
@ -52,11 +52,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
path = new SmoothPath
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
PathRadius = 1
|
|
||||||
},
|
|
||||||
marker = new Container
|
marker = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -96,20 +91,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
sliderPosition = slider.PositionBindable.GetBoundCopy();
|
sliderPosition = slider.PositionBindable.GetBoundCopy();
|
||||||
sliderPosition.BindValueChanged(_ => updateDisplay());
|
sliderPosition.BindValueChanged(_ => updateMarkerDisplay());
|
||||||
|
|
||||||
pathVersion = slider.Path.Version.GetBoundCopy();
|
controlPointPosition = ControlPoint.Position.GetBoundCopy();
|
||||||
pathVersion.BindValueChanged(_ => updateDisplay());
|
controlPointPosition.BindValueChanged(_ => updateMarkerDisplay());
|
||||||
|
|
||||||
IsSelected.BindValueChanged(_ => updateMarkerDisplay());
|
IsSelected.BindValueChanged(_ => updateMarkerDisplay());
|
||||||
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDisplay()
|
|
||||||
{
|
|
||||||
updateMarkerDisplay();
|
updateMarkerDisplay();
|
||||||
updateConnectingPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The connecting path is excluded from positional input
|
// The connecting path is excluded from positional input
|
||||||
@ -189,26 +178,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
colour = Color4.White;
|
colour = Color4.White;
|
||||||
marker.Colour = colour;
|
marker.Colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the path connecting this control point to the previous one.
|
|
||||||
/// </summary>
|
|
||||||
private void updateConnectingPath()
|
|
||||||
{
|
|
||||||
path.ClearVertices();
|
|
||||||
|
|
||||||
int index = slider.Path.ControlPoints.IndexOf(ControlPoint);
|
|
||||||
|
|
||||||
if (index == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (++index != slider.Path.ControlPoints.Count)
|
|
||||||
{
|
|
||||||
path.AddVertex(Vector2.Zero);
|
|
||||||
path.AddVertex(slider.Path.ControlPoints[index].Position.Value - ControlPoint.Position.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
{
|
{
|
||||||
internal readonly Container<PathControlPointPiece> Pieces;
|
internal readonly Container<PathControlPointPiece> Pieces;
|
||||||
|
|
||||||
|
private readonly Container<PathControlPointConnectionPiece> connections;
|
||||||
|
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
|
|
||||||
private readonly bool allowSelection;
|
private readonly bool allowSelection;
|
||||||
@ -42,7 +44,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChild = Pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both };
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
connections = new Container<PathControlPointConnectionPiece> { RelativeSizeAxes = Axes.Both },
|
||||||
|
Pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -62,19 +68,23 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
{
|
{
|
||||||
foreach (var point in controlPoints)
|
foreach (var point in controlPoints)
|
||||||
{
|
{
|
||||||
var piece = new PathControlPointPiece(slider, point);
|
Pieces.Add(new PathControlPointPiece(slider, point).With(d =>
|
||||||
|
{
|
||||||
|
if (allowSelection)
|
||||||
|
d.RequestSelection = selectPiece;
|
||||||
|
}));
|
||||||
|
|
||||||
if (allowSelection)
|
connections.Add(new PathControlPointConnectionPiece(slider, point));
|
||||||
piece.RequestSelection = selectPiece;
|
|
||||||
|
|
||||||
Pieces.Add(piece);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeControlPoints(IEnumerable<PathControlPoint> controlPoints)
|
private void removeControlPoints(IEnumerable<PathControlPoint> controlPoints)
|
||||||
{
|
{
|
||||||
foreach (var point in controlPoints)
|
foreach (var point in controlPoints)
|
||||||
|
{
|
||||||
Pieces.RemoveAll(p => p.ControlPoint == point);
|
Pieces.RemoveAll(p => p.ControlPoint == point);
|
||||||
|
connections.RemoveAll(c => c.ControlPoint == point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
|
@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
protected override bool OnDoubleClick(DoubleClickEvent e)
|
protected override bool OnDoubleClick(DoubleClickEvent e)
|
||||||
{
|
{
|
||||||
// Todo: This should all not occur on double click, but rather if the previous control point is hovered.
|
// Todo: This should all not occur on double click, but rather if the previous control point is hovered.
|
||||||
segmentStart = HitObject.Path.ControlPoints[HitObject.Path.ControlPoints.Count - 1];
|
segmentStart = HitObject.Path.ControlPoints[^1];
|
||||||
segmentStart.Type.Value = PathType.Linear;
|
segmentStart.Type.Value = PathType.Linear;
|
||||||
|
|
||||||
currentSegmentLength = 1;
|
currentSegmentLength = 1;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
25
osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
|
{
|
||||||
|
public class OsuModCinema : ModCinema<OsuHitObject>
|
||||||
|
{
|
||||||
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
||||||
|
|
||||||
|
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||||
|
{
|
||||||
|
ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } },
|
||||||
|
Replay = new OsuAutoGenerator(beatmap).Generate()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
path.ControlPoints.AddRange(value.ControlPoints);
|
path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position.Value, c.Type.Value)));
|
||||||
path.ExpectedDistance.Value = value.ExpectedDistance.Value;
|
path.ExpectedDistance.Value = value.ExpectedDistance.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
@ -60,7 +67,9 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
if (mods.HasFlag(LegacyMods.Autopilot))
|
if (mods.HasFlag(LegacyMods.Autopilot))
|
||||||
yield return new OsuModAutopilot();
|
yield return new OsuModAutopilot();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
if (mods.HasFlag(LegacyMods.Cinema))
|
||||||
|
yield return new OsuModCinema();
|
||||||
|
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
yield return new OsuModAutoplay();
|
yield return new OsuModAutoplay();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Easy))
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
@ -126,7 +135,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
return new Mod[]
|
return new Mod[]
|
||||||
{
|
{
|
||||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
new MultiMod(new OsuModAutoplay(), new OsuModCinema()),
|
||||||
new OsuModRelax(),
|
new OsuModRelax(),
|
||||||
new OsuModAutopilot(),
|
new OsuModAutopilot(),
|
||||||
};
|
};
|
||||||
@ -149,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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,9 +156,9 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
// TODO: Shouldn't the spinner always spin in the same direction?
|
// TODO: Shouldn't the spinner always spin in the same direction?
|
||||||
if (h is Spinner)
|
if (h is Spinner)
|
||||||
{
|
{
|
||||||
calcSpinnerStartPosAndDirection(((OsuReplayFrame)Frames[Frames.Count - 1]).Position, out startPosition, out spinnerDirection);
|
calcSpinnerStartPosAndDirection(((OsuReplayFrame)Frames[^1]).Position, out startPosition, out spinnerDirection);
|
||||||
|
|
||||||
Vector2 spinCentreOffset = SPINNER_CENTRE - ((OsuReplayFrame)Frames[Frames.Count - 1]).Position;
|
Vector2 spinCentreOffset = SPINNER_CENTRE - ((OsuReplayFrame)Frames[^1]).Position;
|
||||||
|
|
||||||
if (spinCentreOffset.Length > SPIN_RADIUS)
|
if (spinCentreOffset.Length > SPIN_RADIUS)
|
||||||
{
|
{
|
||||||
@ -230,7 +230,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
|
|
||||||
private void moveToHitObject(OsuHitObject h, Vector2 targetPos, Easing easing)
|
private void moveToHitObject(OsuHitObject h, Vector2 targetPos, Easing easing)
|
||||||
{
|
{
|
||||||
OsuReplayFrame lastFrame = (OsuReplayFrame)Frames[Frames.Count - 1];
|
OsuReplayFrame lastFrame = (OsuReplayFrame)Frames[^1];
|
||||||
|
|
||||||
// Wait until Auto could "see and react" to the next note.
|
// Wait until Auto could "see and react" to the next note.
|
||||||
double waitTime = h.StartTime - Math.Max(0.0, h.TimePreempt - reactionTime);
|
double waitTime = h.StartTime - Math.Max(0.0, h.TimePreempt - reactionTime);
|
||||||
@ -363,7 +363,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We only want to let go of our button if we are at the end of the current replay. Otherwise something is still going on after us so we need to keep the button pressed!
|
// We only want to let go of our button if we are at the end of the current replay. Otherwise something is still going on after us so we need to keep the button pressed!
|
||||||
if (Frames[Frames.Count - 1].Time <= endFrame.Time)
|
if (Frames[^1].Time <= endFrame.Time)
|
||||||
AddFrameToReplay(endFrame);
|
AddFrameToReplay(endFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,18 +28,18 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
|
ExpandTarget = new NonPlayfieldSprite
|
||||||
|
{
|
||||||
|
Texture = skin.GetTexture("cursor"),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
new NonPlayfieldSprite
|
new NonPlayfieldSprite
|
||||||
{
|
{
|
||||||
Texture = skin.GetTexture("cursormiddle"),
|
Texture = skin.GetTexture("cursormiddle"),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
ExpandTarget = new NonPlayfieldSprite
|
|
||||||
{
|
|
||||||
Texture = skin.GetTexture("cursor"),
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
private void addPart(Vector2 screenSpacePosition)
|
private void addPart(Vector2 screenSpacePosition)
|
||||||
{
|
{
|
||||||
parts[currentIndex].Position = screenSpacePosition;
|
parts[currentIndex].Position = screenSpacePosition;
|
||||||
parts[currentIndex].Time = time;
|
parts[currentIndex].Time = time + 1;
|
||||||
++parts[currentIndex].InvalidationID;
|
++parts[currentIndex].InvalidationID;
|
||||||
|
|
||||||
currentIndex = (currentIndex + 1) % max_sprites;
|
currentIndex = (currentIndex + 1) % max_sprites;
|
||||||
@ -201,7 +201,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
|
|
||||||
private readonly TrailBatch vertexBatch = new TrailBatch(max_sprites, 1);
|
private readonly QuadBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
||||||
|
|
||||||
public TrailDrawNode(CursorTrail source)
|
public TrailDrawNode(CursorTrail source)
|
||||||
: base(source)
|
: base(source)
|
||||||
@ -227,23 +227,52 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
shader.Bind();
|
shader.Bind();
|
||||||
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
||||||
|
|
||||||
for (int i = 0; i < parts.Length; ++i)
|
texture.TextureGL.Bind();
|
||||||
|
|
||||||
|
RectangleF textureRect = texture.GetTextureRect();
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
{
|
{
|
||||||
if (parts[i].InvalidationID == -1)
|
if (part.InvalidationID == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vertexBatch.DrawTime = parts[i].Time;
|
if (time - part.Time >= 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
Vector2 pos = parts[i].Position;
|
vertexBatch.Add(new TexturedTrailVertex
|
||||||
|
{
|
||||||
|
Position = new Vector2(part.Position.X - size.X / 2, part.Position.Y + size.Y / 2),
|
||||||
|
TexturePosition = textureRect.BottomLeft,
|
||||||
|
Colour = DrawColourInfo.Colour.BottomLeft.Linear,
|
||||||
|
Time = part.Time
|
||||||
|
});
|
||||||
|
|
||||||
DrawQuad(
|
vertexBatch.Add(new TexturedTrailVertex
|
||||||
texture,
|
{
|
||||||
new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
|
Position = new Vector2(part.Position.X + size.X / 2, part.Position.Y + size.Y / 2),
|
||||||
DrawColourInfo.Colour,
|
TexturePosition = textureRect.BottomRight,
|
||||||
null,
|
Colour = DrawColourInfo.Colour.BottomRight.Linear,
|
||||||
vertexBatch.AddAction);
|
Time = part.Time
|
||||||
|
});
|
||||||
|
|
||||||
|
vertexBatch.Add(new TexturedTrailVertex
|
||||||
|
{
|
||||||
|
Position = new Vector2(part.Position.X + size.X / 2, part.Position.Y - size.Y / 2),
|
||||||
|
TexturePosition = textureRect.TopRight,
|
||||||
|
Colour = DrawColourInfo.Colour.TopRight.Linear,
|
||||||
|
Time = part.Time
|
||||||
|
});
|
||||||
|
|
||||||
|
vertexBatch.Add(new TexturedTrailVertex
|
||||||
|
{
|
||||||
|
Position = new Vector2(part.Position.X - size.X / 2, part.Position.Y - size.Y / 2),
|
||||||
|
TexturePosition = textureRect.TopLeft,
|
||||||
|
Colour = DrawColourInfo.Colour.TopLeft.Linear,
|
||||||
|
Time = part.Time
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vertexBatch.Draw();
|
||||||
shader.Unbind();
|
shader.Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,25 +282,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
vertexBatch.Dispose();
|
vertexBatch.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo: This shouldn't exist, but is currently used to reduce allocations by caching variable-capturing closures.
|
|
||||||
private class TrailBatch : QuadBatch<TexturedTrailVertex>
|
|
||||||
{
|
|
||||||
public new readonly Action<TexturedVertex2D> AddAction;
|
|
||||||
public float DrawTime;
|
|
||||||
|
|
||||||
public TrailBatch(int size, int maxBuffers)
|
|
||||||
: base(size, maxBuffers)
|
|
||||||
{
|
|
||||||
AddAction = v => Add(new TexturedTrailVertex
|
|
||||||
{
|
|
||||||
Position = v.Position,
|
|
||||||
TexturePosition = v.TexturePosition,
|
|
||||||
Time = DrawTime + 1,
|
|
||||||
Colour = v.Colour,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
@ -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);
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = Mods.Value.Concat(new[] { new TaikoModSuddenDeath() }).ToArray();
|
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new TaikoModSuddenDeath() }).ToArray();
|
||||||
return new ScoreAccessiblePlayer();
|
return new ScoreAccessiblePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Mods
|
||||||
|
{
|
||||||
|
public class TaikoModCinema : ModCinema<TaikoHitObject>
|
||||||
|
{
|
||||||
|
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||||
|
{
|
||||||
|
ScoreInfo = new ScoreInfo { User = new User { Username = "mekkadosu!" } },
|
||||||
|
Replay = new TaikoAutoGenerator(beatmap).Generate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
using osu.Game.Rulesets.Taiko.Scoring;
|
using osu.Game.Rulesets.Taiko.Scoring;
|
||||||
@ -38,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
base.CreateNestedHitObjects();
|
base.CreateNestedHitObjects();
|
||||||
|
|
||||||
if (IsStrong)
|
if (IsStrong)
|
||||||
AddNested(new StrongHitObject { StartTime = (this as IHasEndTime)?.EndTime ?? StartTime });
|
AddNested(new StrongHitObject { StartTime = this.GetEndTime() });
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Judgement CreateJudgement() => new TaikoJudgement();
|
public override Judgement CreateJudgement() => new TaikoJudgement();
|
||||||
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays;
|
using osu.Game.Replays;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
@ -39,9 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
|||||||
for (int i = 0; i < Beatmap.HitObjects.Count; i++)
|
for (int i = 0; i < Beatmap.HitObjects.Count; i++)
|
||||||
{
|
{
|
||||||
TaikoHitObject h = Beatmap.HitObjects[i];
|
TaikoHitObject h = Beatmap.HitObjects[i];
|
||||||
|
double endTime = h.GetEndTime();
|
||||||
IHasEndTime endTimeData = h as IHasEndTime;
|
|
||||||
double endTime = endTimeData?.EndTime ?? h.StartTime;
|
|
||||||
|
|
||||||
switch (h)
|
switch (h)
|
||||||
{
|
{
|
||||||
|
@ -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";
|
||||||
@ -50,7 +56,9 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||||
yield return new TaikoModSuddenDeath();
|
yield return new TaikoModSuddenDeath();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
if (mods.HasFlag(LegacyMods.Cinema))
|
||||||
|
yield return new TaikoModCinema();
|
||||||
|
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
yield return new TaikoModAutoplay();
|
yield return new TaikoModAutoplay();
|
||||||
|
|
||||||
if (mods.HasFlag(LegacyMods.Easy))
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
@ -100,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
return new Mod[]
|
return new Mod[]
|
||||||
{
|
{
|
||||||
new MultiMod(new TaikoModAutoplay(), new ModCinema()),
|
new MultiMod(new TaikoModAutoplay(), new TaikoModCinema()),
|
||||||
new TaikoModRelax(),
|
new TaikoModRelax(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,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);
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||||
AddStep("Set default user settings", () =>
|
AddStep("Set default user settings", () =>
|
||||||
{
|
{
|
||||||
Mods.Value = Mods.Value.Concat(new[] { new OsuModNoFail() }).ToArray();
|
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new OsuModNoFail() }).ToArray();
|
||||||
songSelect.DimLevel.Value = 0.7f;
|
songSelect.DimLevel.Value = 0.7f;
|
||||||
songSelect.BlurLevel.Value = 0.4f;
|
songSelect.BlurLevel.Value = 0.4f;
|
||||||
});
|
});
|
||||||
|
@ -88,6 +88,20 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
AddUntilStep("not lightened", () => userDimContainer.DimEqual(test_user_dim));
|
AddUntilStep("not lightened", () => userDimContainer.DimEqual(test_user_dim));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestIgnoreUserSettings()
|
||||||
|
{
|
||||||
|
AddStep("set dim level 0.6", () => userDimContainer.UserDimLevel.Value = test_user_dim);
|
||||||
|
AddUntilStep("dim reached", () => userDimContainer.DimEqual(test_user_dim));
|
||||||
|
|
||||||
|
AddStep("ignore settings", () => userDimContainer.IgnoreUserSettings.Value = true);
|
||||||
|
AddUntilStep("no dim", () => userDimContainer.DimEqual(0));
|
||||||
|
AddStep("set break", () => isBreakTime.Value = true);
|
||||||
|
AddAssert("no dim", () => userDimContainer.DimEqual(0));
|
||||||
|
AddStep("clear break", () => isBreakTime.Value = false);
|
||||||
|
AddAssert("no dim", () => userDimContainer.DimEqual(0));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestUserDimContainer : UserDimContainer
|
private class TestUserDimContainer : UserDimContainer
|
||||||
{
|
{
|
||||||
public bool DimEqual(float expectedDimLevel) => Content.Colour == OsuColour.Gray(1f - expectedDimLevel);
|
public bool DimEqual(float expectedDimLevel) => Content.Colour == OsuColour.Gray(1f - expectedDimLevel);
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||||
return new ScoreAccessiblePlayer();
|
return new ScoreAccessiblePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = Array.Empty<Mod>();
|
SelectedMods.Value = Array.Empty<Mod>();
|
||||||
return new FailPlayer();
|
return new FailPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = Array.Empty<Mod>();
|
SelectedMods.Value = Array.Empty<Mod>();
|
||||||
return new FailPlayer();
|
return new FailPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected override Player CreatePlayer(Ruleset ruleset)
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||||
return new RulesetExposingPlayer();
|
return new RulesetExposingPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public class TestSceneHUDOverlay : ManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
private HUDOverlay hudOverlay;
|
||||||
|
|
||||||
|
private Drawable hideTarget => hudOverlay.KeyCounter; // best way of checking hideTargets without exposing.
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestShownByDefault()
|
||||||
|
{
|
||||||
|
createNew();
|
||||||
|
|
||||||
|
AddAssert("showhud is set", () => hudOverlay.ShowHud.Value);
|
||||||
|
|
||||||
|
AddAssert("hidetarget is visible", () => hideTarget.IsPresent);
|
||||||
|
AddAssert("pause button is visible", () => hudOverlay.HoldToQuit.IsPresent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFadesInOnLoadComplete()
|
||||||
|
{
|
||||||
|
float? initialAlpha = null;
|
||||||
|
|
||||||
|
createNew(h => h.OnLoadComplete += _ => initialAlpha = hideTarget.Alpha);
|
||||||
|
AddUntilStep("wait for load", () => hudOverlay.IsAlive);
|
||||||
|
AddAssert("initial alpha was less than 1", () => initialAlpha != null && initialAlpha < 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHideExternally()
|
||||||
|
{
|
||||||
|
createNew();
|
||||||
|
|
||||||
|
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||||
|
|
||||||
|
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
|
||||||
|
AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestExternalHideDoesntAffectConfig()
|
||||||
|
{
|
||||||
|
bool originalConfigValue = false;
|
||||||
|
|
||||||
|
createNew();
|
||||||
|
|
||||||
|
AddStep("get original config value", () => originalConfigValue = config.Get<bool>(OsuSetting.ShowInterface));
|
||||||
|
|
||||||
|
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||||
|
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
|
||||||
|
|
||||||
|
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||||
|
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createNew(Action<HUDOverlay> action = null)
|
||||||
|
{
|
||||||
|
AddStep("create overlay", () =>
|
||||||
|
{
|
||||||
|
Child = hudOverlay = new HUDOverlay(null, null, Array.Empty<Mod>());
|
||||||
|
|
||||||
|
action?.Invoke(hudOverlay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
beforeLoadAction?.Invoke();
|
beforeLoadAction?.Invoke();
|
||||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
|
||||||
mod.ApplyToTrack(Beatmap.Value.Track);
|
mod.ApplyToTrack(Beatmap.Value.Track);
|
||||||
|
|
||||||
InputManager.Child = container = new TestPlayerLoaderContainer(
|
InputManager.Child = container = new TestPlayerLoaderContainer(
|
||||||
@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestEarlyExit()
|
public void TestEarlyExit()
|
||||||
{
|
{
|
||||||
AddStep("load dummy beatmap", () => ResetPlayer(false, () => Mods.Value = new[] { new OsuModNightcore() }));
|
AddStep("load dummy beatmap", () => ResetPlayer(false, () => SelectedMods.Value = new[] { new OsuModNightcore() }));
|
||||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||||
AddAssert("mod rate applied", () => Beatmap.Value.Track.Rate != 1);
|
AddAssert("mod rate applied", () => Beatmap.Value.Track.Rate != 1);
|
||||||
AddStep("exit loader", () => loader.Exit());
|
AddStep("exit loader", () => loader.Exit());
|
||||||
@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
TestMod playerMod1 = null;
|
TestMod playerMod1 = null;
|
||||||
TestMod playerMod2 = null;
|
TestMod playerMod2 = null;
|
||||||
|
|
||||||
AddStep("load player", () => { ResetPlayer(true, () => Mods.Value = new[] { gameMod = new TestMod() }); });
|
AddStep("load player", () => { ResetPlayer(true, () => SelectedMods.Value = new[] { gameMod = new TestMod() }); });
|
||||||
|
|
||||||
AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
|
AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
|
||||||
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
|
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("set second set", () => details.BeatmapSet = secondSet);
|
AddStep("set second set", () => details.BeatmapSet = secondSet);
|
||||||
AddAssert("ratings set", () => details.Ratings.Metrics == secondSet.Metrics);
|
AddAssert("ratings set", () => details.Ratings.Metrics == secondSet.Metrics);
|
||||||
|
|
||||||
BeatmapSetInfo createSet() => new BeatmapSetInfo
|
static BeatmapSetInfo createSet() => new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray() },
|
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray() },
|
||||||
Beatmaps = new List<BeatmapInfo>
|
Beatmaps = new List<BeatmapInfo>
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -256,17 +256,17 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("change ruleset", () =>
|
AddStep("change ruleset", () =>
|
||||||
{
|
{
|
||||||
Mods.ValueChanged += onModChange;
|
SelectedMods.ValueChanged += onModChange;
|
||||||
songSelect.Ruleset.ValueChanged += onRulesetChange;
|
songSelect.Ruleset.ValueChanged += onRulesetChange;
|
||||||
|
|
||||||
Ruleset.Value = new TaikoRuleset().RulesetInfo;
|
Ruleset.Value = new TaikoRuleset().RulesetInfo;
|
||||||
|
|
||||||
Mods.ValueChanged -= onModChange;
|
SelectedMods.ValueChanged -= onModChange;
|
||||||
songSelect.Ruleset.ValueChanged -= onRulesetChange;
|
songSelect.Ruleset.ValueChanged -= onRulesetChange;
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("mods changed before ruleset", () => modChangeIndex < rulesetChangeIndex);
|
AddAssert("mods changed before ruleset", () => modChangeIndex < rulesetChangeIndex);
|
||||||
AddAssert("empty mods", () => !Mods.Value.Any());
|
AddAssert("empty mods", () => !SelectedMods.Value.Any());
|
||||||
|
|
||||||
void onModChange(ValueChangedEvent<IReadOnlyList<Mod>> e) => modChangeIndex = actionIndex++;
|
void onModChange(ValueChangedEvent<IReadOnlyList<Mod>> e) => modChangeIndex = actionIndex++;
|
||||||
void onRulesetChange(ValueChangedEvent<RulesetInfo> e) => rulesetChangeIndex = actionIndex++;
|
void onRulesetChange(ValueChangedEvent<RulesetInfo> e) => rulesetChangeIndex = actionIndex++;
|
||||||
@ -275,7 +275,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestModsRetainedBetweenSongSelect()
|
public void TestModsRetainedBetweenSongSelect()
|
||||||
{
|
{
|
||||||
AddAssert("empty mods", () => !Mods.Value.Any());
|
AddAssert("empty mods", () => !SelectedMods.Value.Any());
|
||||||
|
|
||||||
createSongSelect();
|
createSongSelect();
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
createSongSelect();
|
createSongSelect();
|
||||||
|
|
||||||
AddAssert("mods retained", () => Mods.Value.Any());
|
AddAssert("mods retained", () => SelectedMods.Value.Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -332,7 +332,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
private void checkMusicPlaying(bool playing) =>
|
private void checkMusicPlaying(bool playing) =>
|
||||||
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
|
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
|
||||||
|
|
||||||
private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.Acronym))}", () => Mods.Value = mods);
|
private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.Acronym))}", () => SelectedMods.Value = mods);
|
||||||
|
|
||||||
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));
|
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -157,7 +157,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private TimingControlPoint getNextTimingPoint(TimingControlPoint current)
|
private TimingControlPoint getNextTimingPoint(TimingControlPoint current)
|
||||||
{
|
{
|
||||||
if (timingPoints[timingPoints.Count - 1] == current)
|
if (timingPoints[^1] == current)
|
||||||
return current;
|
return current;
|
||||||
|
|
||||||
int index = timingPoints.IndexOf(current); // -1 means that this is a "default beat"
|
int index = timingPoints.IndexOf(current); // -1 means that this is a "default beat"
|
||||||
@ -169,7 +169,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
if (timingPoints.Count == 0) return 0;
|
if (timingPoints.Count == 0) return 0;
|
||||||
|
|
||||||
if (timingPoints[timingPoints.Count - 1] == current)
|
if (timingPoints[^1] == current)
|
||||||
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);
|
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);
|
||||||
|
|
||||||
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
|
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
|
||||||
|
@ -8,13 +8,16 @@ using NUnit.Framework;
|
|||||||
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.Framework.Testing;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Overlays.Mods.Sections;
|
using osu.Game.Overlays.Mods.Sections;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Mania.Mods;
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
@ -48,42 +51,48 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
private void load(RulesetStore rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
|
}
|
||||||
|
|
||||||
Add(modSelect = new TestModSelectOverlay
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
modSelect = new TestModSelectOverlay
|
||||||
Origin = Anchor.BottomCentre,
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
RelativeSizeAxes = Axes.X,
|
||||||
});
|
Origin = Anchor.BottomCentre,
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
},
|
||||||
|
|
||||||
Add(modDisplay = new ModDisplay
|
modDisplay = new ModDisplay
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Position = new Vector2(0, 25),
|
Position = new Vector2(0, 25),
|
||||||
});
|
Current = { BindTarget = modSelect.SelectedMods }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
modDisplay.Current.UnbindBindings();
|
[SetUpSteps]
|
||||||
modDisplay.Current.BindTo(modSelect.SelectedMods);
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
AddStep("Show", modSelect.Show);
|
AddStep("show", () => modSelect.Show());
|
||||||
AddStep("Toggle", modSelect.ToggleVisibility);
|
|
||||||
AddStep("Toggle", modSelect.ToggleVisibility);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestOsuMods()
|
public void TestOsuMods()
|
||||||
{
|
{
|
||||||
var ruleset = rulesets.AvailableRulesets.First(r => r.ID == 0);
|
changeRuleset(0);
|
||||||
changeRuleset(ruleset);
|
|
||||||
|
|
||||||
var instance = ruleset.CreateInstance();
|
var osu = new OsuRuleset();
|
||||||
|
|
||||||
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
|
var easierMods = osu.GetModsFor(ModType.DifficultyReduction);
|
||||||
var harderMods = instance.GetModsFor(ModType.DifficultyIncrease);
|
var harderMods = osu.GetModsFor(ModType.DifficultyIncrease);
|
||||||
|
|
||||||
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
|
var noFailMod = osu.GetModsFor(ModType.DifficultyReduction).FirstOrDefault(m => m is OsuModNoFail);
|
||||||
var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden);
|
var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden);
|
||||||
|
|
||||||
var doubleTimeMod = harderMods.OfType<MultiMod>().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime));
|
var doubleTimeMod = harderMods.OfType<MultiMod>().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime));
|
||||||
@ -97,8 +106,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
testMultiMod(doubleTimeMod);
|
testMultiMod(doubleTimeMod);
|
||||||
testIncompatibleMods(easy, hardRock);
|
testIncompatibleMods(easy, hardRock);
|
||||||
testDeselectAll(easierMods.Where(m => !(m is MultiMod)));
|
testDeselectAll(easierMods.Where(m => !(m is MultiMod)));
|
||||||
testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour);
|
testMultiplierTextColour(noFailMod, () => modSelect.LowMultiplierColour);
|
||||||
testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour);
|
testMultiplierTextColour(hiddenMod, () => modSelect.HighMultiplierColour);
|
||||||
|
|
||||||
testUnimplementedMod(spunOutMod);
|
testUnimplementedMod(spunOutMod);
|
||||||
}
|
}
|
||||||
@ -106,37 +115,31 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestManiaMods()
|
public void TestManiaMods()
|
||||||
{
|
{
|
||||||
var ruleset = rulesets.AvailableRulesets.First(r => r.ID == 3);
|
changeRuleset(3);
|
||||||
changeRuleset(ruleset);
|
|
||||||
|
|
||||||
testRankedText(ruleset.CreateInstance().GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom));
|
testRankedText(new ManiaRuleset().GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRulesetChanges()
|
public void TestRulesetChanges()
|
||||||
{
|
{
|
||||||
var rulesetOsu = rulesets.AvailableRulesets.First(r => r.ID == 0);
|
changeRuleset(0);
|
||||||
var rulesetMania = rulesets.AvailableRulesets.First(r => r.ID == 3);
|
|
||||||
|
|
||||||
changeRuleset(null);
|
var noFailMod = new OsuRuleset().GetModsFor(ModType.DifficultyReduction).FirstOrDefault(m => m is OsuModNoFail);
|
||||||
|
|
||||||
var instance = rulesetOsu.CreateInstance();
|
AddStep("set mods externally", () => { SelectedMods.Value = new[] { noFailMod }; });
|
||||||
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
|
|
||||||
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
|
|
||||||
|
|
||||||
AddStep("set mods externally", () => { modDisplay.Current.Value = new[] { noFailMod }; });
|
changeRuleset(0);
|
||||||
|
|
||||||
changeRuleset(rulesetOsu);
|
|
||||||
|
|
||||||
AddAssert("ensure mods still selected", () => modDisplay.Current.Value.Single(m => m is OsuModNoFail) != null);
|
AddAssert("ensure mods still selected", () => modDisplay.Current.Value.Single(m => m is OsuModNoFail) != null);
|
||||||
|
|
||||||
changeRuleset(rulesetMania);
|
changeRuleset(3);
|
||||||
|
|
||||||
AddAssert("ensure mods not selected", () => !modDisplay.Current.Value.Any(m => m is OsuModNoFail));
|
AddAssert("ensure mods not selected", () => modDisplay.Current.Value.Count == 0);
|
||||||
|
|
||||||
changeRuleset(rulesetOsu);
|
changeRuleset(0);
|
||||||
|
|
||||||
AddAssert("ensure mods not selected", () => !modDisplay.Current.Value.Any());
|
AddAssert("ensure mods not selected", () => modDisplay.Current.Value.Count == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testSingleMod(Mod mod)
|
private void testSingleMod(Mod mod)
|
||||||
@ -198,19 +201,19 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
selectNext(mod);
|
selectNext(mod);
|
||||||
|
|
||||||
AddAssert("check for any selection", () => modSelect.SelectedMods.Value.Any());
|
AddAssert("check for any selection", () => modSelect.SelectedMods.Value.Any());
|
||||||
AddStep("deselect all", modSelect.DeselectAllButton.Action.Invoke);
|
AddStep("deselect all", () => modSelect.DeselectAllButton.Action.Invoke());
|
||||||
AddAssert("check for no selection", () => !modSelect.SelectedMods.Value.Any());
|
AddAssert("check for no selection", () => !modSelect.SelectedMods.Value.Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testMultiplierTextColour(Mod mod, Color4 colour)
|
private void testMultiplierTextColour(Mod mod, Func<Color4> getCorrectColour)
|
||||||
{
|
{
|
||||||
checkLabelColor(Color4.White);
|
checkLabelColor(() => Color4.White);
|
||||||
selectNext(mod);
|
selectNext(mod);
|
||||||
AddWaitStep("wait for changing colour", 1);
|
AddWaitStep("wait for changing colour", 1);
|
||||||
checkLabelColor(colour);
|
checkLabelColor(getCorrectColour);
|
||||||
selectPrevious(mod);
|
selectPrevious(mod);
|
||||||
AddWaitStep("wait for changing colour", 1);
|
AddWaitStep("wait for changing colour", 1);
|
||||||
checkLabelColor(Color4.White);
|
checkLabelColor(() => Color4.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testRankedText(Mod mod)
|
private void testRankedText(Mod mod)
|
||||||
@ -235,9 +238,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeRuleset(RulesetInfo ruleset)
|
private void changeRuleset(int? id)
|
||||||
{
|
{
|
||||||
AddStep($"change ruleset to {ruleset}", () => { Ruleset.Value = ruleset; });
|
AddStep($"change ruleset to {(id?.ToString() ?? "none")}", () => { Ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(r => r.ID == id); });
|
||||||
waitForLoad();
|
waitForLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +256,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLabelColor(Color4 color) => AddAssert("check label has expected colour", () => modSelect.MultiplierLabel.Colour.AverageColour == color);
|
private void checkLabelColor(Func<Color4> getColour) => AddAssert("check label has expected colour", () => modSelect.MultiplierLabel.Colour.AverageColour == getColour());
|
||||||
|
|
||||||
private class TestModSelectOverlay : ModSelectOverlay
|
private class TestModSelectOverlay : ModSelectOverlay
|
||||||
{
|
{
|
||||||
|
@ -2,15 +2,20 @@
|
|||||||
// 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
@ -18,28 +23,51 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
private TestModSelectOverlay modSelect;
|
private TestModSelectOverlay modSelect;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
private readonly Mod testCustomisableMod = new TestModCustomisable1();
|
||||||
private void load()
|
|
||||||
|
[Test]
|
||||||
|
public void TestButtonShowsOnCustomisableMod()
|
||||||
{
|
{
|
||||||
Add(modSelect = new TestModSelectOverlay
|
createModSelect();
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
});
|
|
||||||
|
|
||||||
var testMod = new TestModCustomisable1();
|
AddStep("open", () => modSelect.Show());
|
||||||
|
|
||||||
AddStep("open", modSelect.Show);
|
|
||||||
AddAssert("button disabled", () => !modSelect.CustomiseButton.Enabled.Value);
|
AddAssert("button disabled", () => !modSelect.CustomiseButton.Enabled.Value);
|
||||||
AddUntilStep("wait for button load", () => modSelect.ButtonsLoaded);
|
AddUntilStep("wait for button load", () => modSelect.ButtonsLoaded);
|
||||||
AddStep("select mod", () => modSelect.SelectMod(testMod));
|
AddStep("select mod", () => modSelect.SelectMod(testCustomisableMod));
|
||||||
AddAssert("button enabled", () => modSelect.CustomiseButton.Enabled.Value);
|
AddAssert("button enabled", () => modSelect.CustomiseButton.Enabled.Value);
|
||||||
AddStep("open Customisation", () => modSelect.CustomiseButton.Click());
|
AddStep("open Customisation", () => modSelect.CustomiseButton.Click());
|
||||||
AddStep("deselect mod", () => modSelect.SelectMod(testMod));
|
AddStep("deselect mod", () => modSelect.SelectMod(testCustomisableMod));
|
||||||
AddAssert("controls hidden", () => modSelect.ModSettingsContainer.Alpha == 0);
|
AddAssert("controls hidden", () => modSelect.ModSettingsContainer.Alpha == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestButtonShowsOnModAlreadyAdded()
|
||||||
|
{
|
||||||
|
AddStep("set active mods", () => SelectedMods.Value = new List<Mod> { testCustomisableMod });
|
||||||
|
|
||||||
|
createModSelect();
|
||||||
|
|
||||||
|
AddAssert("mods still active", () => SelectedMods.Value.Count == 1);
|
||||||
|
|
||||||
|
AddStep("open", () => modSelect.Show());
|
||||||
|
AddAssert("button enabled", () => modSelect.CustomiseButton.Enabled.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createModSelect()
|
||||||
|
{
|
||||||
|
AddStep("create mod select", () =>
|
||||||
|
{
|
||||||
|
Ruleset.Value = new TestRulesetInfo();
|
||||||
|
|
||||||
|
Child = modSelect = new TestModSelectOverlay
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private class TestModSelectOverlay : ModSelectOverlay
|
private class TestModSelectOverlay : ModSelectOverlay
|
||||||
{
|
{
|
||||||
public new Container ModSettingsContainer => base.ModSettingsContainer;
|
public new Container ModSettingsContainer => base.ModSettingsContainer;
|
||||||
@ -50,24 +78,41 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
public void SelectMod(Mod mod) =>
|
public void SelectMod(Mod mod) =>
|
||||||
ModSectionsContainer.Children.Single(s => s.ModType == mod.Type)
|
ModSectionsContainer.Children.Single(s => s.ModType == mod.Type)
|
||||||
.ButtonsContainer.OfType<ModButton>().Single(b => b.Mods.Any(m => m.GetType() == mod.GetType())).SelectNext(1);
|
.ButtonsContainer.OfType<ModButton>().Single(b => b.Mods.Any(m => m.GetType() == mod.GetType())).SelectNext(1);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
public class TestRulesetInfo : RulesetInfo
|
||||||
|
{
|
||||||
|
public override Ruleset CreateInstance() => new TestCustomisableModRuleset();
|
||||||
|
|
||||||
|
public TestRulesetInfo()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
Available = true;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var section in ModSectionsContainer)
|
public class TestCustomisableModRuleset : Ruleset
|
||||||
|
{
|
||||||
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
if (section.ModType == ModType.Conversion)
|
if (type == ModType.Conversion)
|
||||||
{
|
{
|
||||||
section.Mods = new Mod[]
|
return new Mod[]
|
||||||
{
|
{
|
||||||
new TestModCustomisable1(),
|
new TestModCustomisable1(),
|
||||||
new TestModCustomisable2()
|
new TestModCustomisable2()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
section.Mods = Array.Empty<Mod>();
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override string Description { get; } = "test";
|
||||||
|
public override string ShortName { get; } = "tst";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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; }
|
||||||
|