1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-02 01:49:56 +08:00

Compare commits

..

159 Commits

547 changed files with 13421 additions and 2662 deletions
+2 -2
View File
@@ -10,7 +10,7 @@
"rollForward": false
},
"codefilesanity": {
"version": "0.0.37",
"version": "0.0.41",
"commands": [
"CodeFileSanity"
],
@@ -24,4 +24,4 @@
"rollForward": false
}
}
}
}
+4
View File
@@ -2,6 +2,10 @@
Thank you for showing interest in the development of osu!. We aim to provide a good collaborating environment for everyone involved, and as such have decided to list some of the most important things to keep in mind in the process. The guidelines below have been chosen based on past experience.
## Foreword on AI usage
Our team believes in **human contributions**. Any contribution be it an issue report or a pull request which is created by, documented by, or aided by AI/LLM usage will typically be **closed and locked without further discussion**.
## Table of contents
1. [Reporting bugs](#reporting-bugs)
+1 -1
View File
@@ -136,7 +136,7 @@ When it comes to contributing to the project, the two main things you can do to
If you wish to help with localisation efforts, head over to [crowdin](https://crowdin.com/project/osu-web).
We love to reward quality contributions. If you have made a large contribution, or are a regular contributor, you are welcome to [submit an expense via opencollective](https://opencollective.com/ppy/expenses/new). If you have any questions, feel free to [reach out to peppy](mailto:pe@ppy.sh) before doing so.
Our team believes in **human contributions**. Any contribution be it an issue report or a pull request which is created by, documented by, or aided by AI/LLM usage will typically be **closed and locked without further discussion**.
## Licence
+1 -1
View File
@@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.318.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.527.0" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.
+18 -7
View File
@@ -20,13 +20,24 @@ using Uri = Android.Net.Uri;
namespace osu.Android
{
[Activity(ConfigurationChanges = DEFAULT_CONFIG_CHANGES, Exported = true, LaunchMode = DEFAULT_LAUNCH_MODE, MainLauncher = true)]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osr", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-beatmap-archive")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-skin-archive")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")]
[IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import beatmap", DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*",
DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import skin", DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*",
DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import replay", DataScheme = "content", DataPathPattern = ".*\\\\.osr", DataHost = "*",
DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import beatmap", DataScheme = "content", DataMimeType = "application/x-osu-beatmap-archive")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import skin", DataScheme = "content", DataMimeType = "application/x-osu-skin-archive")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import replay", DataScheme = "content", DataMimeType = "application/x-osu-replay")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, Label = "Import file", DataScheme = "content", DataMimeTypes = new[]
{
"application/zip",
"application/octet-stream",
"application/download",
"application/x-zip",
"application/x-zip-compressed",
})]
[IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, Label = "Import", DataMimeTypes = new[]
{
"application/zip",
"application/octet-stream",
+1 -1
View File
@@ -190,7 +190,7 @@ namespace osu.Desktop
}
// user party
if (!hideIdentifiableInformation && multiplayerClient.Room != null && multiplayerClient.Room.Settings.MatchType != MatchType.Matchmaking)
if (!hideIdentifiableInformation && multiplayerClient.Room != null && !multiplayerClient.Room.Settings.MatchType.IsMatchmakingType())
{
MultiplayerRoom room = multiplayerClient.Room;
@@ -0,0 +1,13 @@
// 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 Newtonsoft.Json;
namespace osu.Desktop.IPC.Messages
{
public class HitCountMessage : OsuWebSocketMessage
{
[JsonProperty("new_hits")]
public long NewHits { get; init; }
}
}
@@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using Newtonsoft.Json;
using osu.Framework.Extensions.TypeExtensions;
namespace osu.Desktop.IPC.Messages
{
public abstract class OsuWebSocketMessage
{
[JsonProperty("type")]
public string Type { get; }
protected OsuWebSocketMessage()
{
Type = GetType().ReadableName();
}
}
}
+75
View File
@@ -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 System;
using System.Linq;
using System.Threading;
using osu.Desktop.IPC.Messages;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Game.Configuration;
using osu.Game.IPC;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using JsonConvert = Newtonsoft.Json.JsonConvert;
namespace osu.Desktop.IPC
{
public partial class OsuWebSocketProvider : Component
{
private WebSocketServer? server;
private readonly Bindable<ScoreInfo> lastLocalScore = new Bindable<ScoreInfo>();
[BackgroundDependencyLoader]
private void load(SessionStatics sessionStatics)
{
server = new WebSocketServer(49727);
server.StartAsync().FireAndForget(onError: ex => Logger.Error(ex, "Failed to start websocket"));
sessionStatics.BindWith(Static.LastLocalUserScore, lastLocalScore);
}
protected override void LoadComplete()
{
base.LoadComplete();
lastLocalScore.BindValueChanged(val =>
{
if (val.NewValue == null)
return;
if (server?.IsRunning != true)
return;
var msg = new HitCountMessage { NewHits = val.NewValue.Statistics.Where(kv => kv.Key.IsBasic() && kv.Key.IsHit()).Sum(kv => kv.Value) };
broadcast(msg);
});
}
private void broadcast(OsuWebSocketMessage message)
{
if (server?.IsRunning != true)
return;
string messageString = JsonConvert.SerializeObject(message);
server.BroadcastAsync(messageString).FireAndForget();
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (server?.IsRunning == true)
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(10));
server.StopAsync(cts.Token).WaitSafely();
server = null;
}
}
}
}
+6
View File
@@ -6,6 +6,7 @@ using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using Microsoft.Win32;
using osu.Desktop.IPC;
using osu.Desktop.Performance;
using osu.Desktop.Security;
using osu.Framework.Platform;
@@ -35,6 +36,8 @@ namespace osu.Desktop
public bool IsFirstRun { get; init; }
public bool EnableWebSocketServer { get; init; }
public OsuGameDesktop(string[]? args = null)
: base(args)
{
@@ -148,6 +151,9 @@ namespace osu.Desktop
osuSchemeLinkIPCChannel = new OsuSchemeLinkIPCChannel(Host, this);
archiveImportIPCChannel = new ArchiveImportIPCChannel(Host, this);
if (EnableWebSocketServer)
Add(new OsuWebSocketProvider());
}
public override void SetHost(GameHost host)
+2 -1
View File
@@ -140,7 +140,8 @@ namespace osu.Desktop
{
host.Run(new OsuGameDesktop(args)
{
IsFirstRun = isFirstRun
IsFirstRun = isFirstRun,
EnableWebSocketServer = Environment.GetEnvironmentVariable("OSU_WEBSOCKET_SERVER") == "1",
});
}
}
+2 -1
View File
@@ -25,7 +25,8 @@
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="System.IO.Packaging" Version="10.0.5" />
<PackageReference Include="DiscordRichPresence" Version="1.6.1.70" />
<!-- Held back due to invite bug in newer versions. See https://github.com/Lachee/discord-rpc-csharp/issues/286-->
<PackageReference Include="DiscordRichPresence" Version="1.5.0.51" />
<PackageReference Include="Velopack" Version="0.0.1298" />
</ItemGroup>
<ItemGroup Label="Resources">
@@ -0,0 +1,67 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Benchmarks
{
public class BenchmarkScoreMultiplierCalculator : BenchmarkTest
{
private ScoreMultiplierCalculator calculator = null!;
[Params(1, 10, 100)]
public int Times { get; set; }
public record ModTestCase(string Description, IEnumerable<Mod> Mods)
{
public override string ToString() => Description;
}
public static IEnumerable<ModTestCase> ValuesForMods =>
[
new ModTestCase("no mods", []),
new ModTestCase("single mod", [new OsuModHardRock()]),
new ModTestCase("single mod 2", [new OsuModEasy()]),
new ModTestCase("multiple mods", [new OsuModHidden(), new OsuModHardRock(), new OsuModDoubleTime()]),
new ModTestCase("mods with adjusted settings", [
new OsuModDoubleTime { SpeedChange = { Value = 2 } },
new OsuModHidden { OnlyFadeApproachCircles = { Value = true } },
new OsuModHardRock()
]),
];
[ParamsSource(nameof(ValuesForMods))]
public ModTestCase Mods { get; set; } = null!;
public override void SetUp()
{
base.SetUp();
calculator = new OsuRuleset().CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
}
[Benchmark]
public double ViaCalculator()
=> viaCalculator(Times, Mods);
[Test]
public void ViaCalculator([Values(100)] int times, [ValueSource(nameof(ValuesForMods))] ModTestCase mods)
=> viaCalculator(times, mods);
private double viaCalculator(int times, ModTestCase mods)
{
double scoreMultiplier = 1;
for (int i = 0; i < times; ++i)
scoreMultiplier = calculator.CalculateFor(mods.Mods);
return scoreMultiplier;
}
}
}
@@ -0,0 +1,155 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Tests.Rulesets;
namespace osu.Game.Rulesets.Catch.Tests
{
public class CatchScoreMultiplierTest : RulesetScoreMultiplierTest
{
public CatchScoreMultiplierTest()
: base(new CatchRuleset())
{
}
private static readonly object[][] test_cases =
[
#region Difficulty Reduction
[new Mod[] { new CatchModEasy() }, 0.5],
[new Mod[] { new CatchModNoFail() }, 0.5],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.50 } } }, 0.1],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.55 } } }, 0.1],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.60 } } }, 0.2],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.65 } } }, 0.2],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.70 } } }, 0.3],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.75 } } }, 0.3],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.80 } } }, 0.4],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.85 } } }, 0.4],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.90 } } }, 0.5],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.95 } } }, 0.5],
[new Mod[] { new CatchModHalfTime { SpeedChange = { Value = 0.99 } } }, 0.5],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.50 } } }, 0.1],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.55 } } }, 0.1],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.60 } } }, 0.2],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.65 } } }, 0.2],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.70 } } }, 0.3],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.75 } } }, 0.3],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.80 } } }, 0.4],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.85 } } }, 0.4],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.90 } } }, 0.5],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.95 } } }, 0.5],
[new Mod[] { new CatchModDaycore { SpeedChange = { Value = 0.99 } } }, 0.5],
#endregion
#region Difficulty Increase
[new Mod[] { new CatchModHardRock() }, 1.12],
[new Mod[] { new CatchModSuddenDeath() }, 1],
[new Mod[] { new CatchModPerfect() }, 1],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.01 } } }, 1.00],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.05 } } }, 1.00],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.10 } } }, 1.02],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.15 } } }, 1.02],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.20 } } }, 1.04],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.25 } } }, 1.04],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.30 } } }, 1.06],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.35 } } }, 1.06],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.40 } } }, 1.08],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.45 } } }, 1.08],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.50 } } }, 1.10],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.55 } } }, 1.10],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.60 } } }, 1.12],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.65 } } }, 1.12],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.70 } } }, 1.14],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.75 } } }, 1.14],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.80 } } }, 1.16],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.85 } } }, 1.16],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.90 } } }, 1.18],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 1.95 } } }, 1.18],
[new Mod[] { new CatchModDoubleTime { SpeedChange = { Value = 2.00 } } }, 1.20],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.01 } } }, 1.00],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.05 } } }, 1.00],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.10 } } }, 1.02],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.15 } } }, 1.02],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.20 } } }, 1.04],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.25 } } }, 1.04],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.30 } } }, 1.06],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.35 } } }, 1.06],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.40 } } }, 1.08],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.45 } } }, 1.08],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.50 } } }, 1.10],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.55 } } }, 1.10],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.60 } } }, 1.12],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.65 } } }, 1.12],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.70 } } }, 1.14],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.75 } } }, 1.14],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.80 } } }, 1.16],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.85 } } }, 1.16],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.90 } } }, 1.18],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 1.95 } } }, 1.18],
[new Mod[] { new CatchModNightcore { SpeedChange = { Value = 2.00 } } }, 1.20],
[new Mod[] { new CatchModHidden() }, 1.06],
[new Mod[] { new CatchModFlashlight() }, 1.12],
[new Mod[] { new CatchModFlashlight { ComboBasedSize = { Value = false } } }, 1],
[new Mod[] { new ModAccuracyChallenge() }, 1],
#endregion
#region Conversion
[new Mod[] { new CatchModDifficultyAdjust() }, 0.5],
[new Mod[] { new CatchModClassic() }, 0.96],
[new Mod[] { new CatchModMirror() }, 1],
#endregion
#region Automation
[new Mod[] { new CatchModAutoplay() }, 1],
[new Mod[] { new CatchModCinema() }, 1],
[new Mod[] { new CatchModRelax() }, 0.1],
#endregion
#region Fun
[new Mod[] { new ModWindUp() }, 0.5],
[new Mod[] { new ModWindDown() }, 0.5],
[new Mod[] { new CatchModFloatingFruits() }, 1],
[new Mod[] { new CatchModMuted() }, 1],
[new Mod[] { new CatchModNoScope() }, 1],
[new Mod[] { new CatchModMovingFast() }, 1],
[new Mod[] { new CatchModSynesthesia() }, 0.8],
#endregion
#region System
[new Mod[] { new ModScoreV2() }, 1],
#endregion
#region Combinations
[new Mod[] { new CatchModHidden(), new CatchModHardRock() }, 1.06 * 1.12]
#endregion
];
[TestCaseSource(nameof(test_cases))]
public void TestMultipliers(Mod[] mods, double expectedMultiplier)
=> TestModCombination(mods, expectedMultiplier);
}
}
+2
View File
@@ -169,6 +169,8 @@ namespace osu.Game.Rulesets.Catch
}
}
public override ScoreMultiplierCalculator CreateScoreMultiplierCalculator(ScoreMultiplierContext context) => new CatchScoreMultiplierCalculator(context);
public override string Description => "osu!catch";
public override string ShortName => SHORT_NAME;
@@ -2,9 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
@@ -13,11 +13,11 @@ namespace osu.Game.Rulesets.Catch.Edit
public class BananaShowerCompositionTool : CompositionTool
{
public BananaShowerCompositionTool()
: base(nameof(BananaShower))
: base("Banana shower")
{
}
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Spinners);
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.EditorBananaShower };
public override HitObjectPlacementBlueprint CreatePlacementBlueprint() => new BananaShowerPlacementBlueprint();
}
@@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
private readonly Path drawablePath;
private readonly List<(double Time, float X)> vertices = new List<(double, float)>();
private readonly List<Vector2> sliderVertices = new List<Vector2>();
public ScrollingPath()
{
@@ -47,9 +48,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
private void computeTimeXs(JuiceStream hitObject)
{
vertices.Clear();
var sliderVertices = new List<Vector2>();
hitObject.Path.GetPathToProgress(sliderVertices, 0, 1);
sliderVertices.Clear();
sliderVertices.AddRange(hitObject.Path.CalculatedPath);
if (sliderVertices.Count == 0)
return;
@@ -14,6 +14,9 @@ namespace osu.Game.Rulesets.Catch.Edit
{
private readonly List<ICheck> checks = new List<ICheck>
{
// Audio
new CheckCatchFewHitsounds(),
// Compose
new CheckBananaShowerGap(),
new CheckConcurrentObjects(),
@@ -3,11 +3,16 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit.Components.TernaryButtons;
using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
@@ -22,6 +27,29 @@ namespace osu.Game.Rulesets.Catch.Edit
{
}
protected override Drawable CreateNewComboButton() => new NewComboTernaryButton
{
Current = NewCombo,
CreateIcon = () => new Container
{
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Icon = OsuIcon.EditorFruit,
Size = new Vector2(15),
},
new SpriteIcon
{
Icon = OsuIcon.EditorNewComboSparkles,
Size = new Vector2(20),
}
},
},
};
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new CatchSelectionHandler();
public override HitObjectSelectionBlueprint? CreateHitObjectBlueprintFor(HitObject hitObject)
@@ -0,0 +1,14 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Edit.Checks;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Edit.Checks
{
public class CheckCatchFewHitsounds : CheckFewHitsounds
{
protected override bool IsExcludedFromHitsounding(HitObject hitObject) => hitObject is BananaShower;
}
}
@@ -2,7 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
@@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Edit
{
}
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles);
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.EditorFruit };
public override HitObjectPlacementBlueprint CreatePlacementBlueprint() => new FruitPlacementBlueprint();
}
@@ -2,9 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
@@ -13,11 +13,11 @@ namespace osu.Game.Rulesets.Catch.Edit
public class JuiceStreamCompositionTool : CompositionTool
{
public JuiceStreamCompositionTool()
: base(nameof(JuiceStream))
: base("Juice stream")
{
}
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders);
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.EditorJuiceStream };
public override HitObjectPlacementBlueprint CreatePlacementBlueprint() => new JuiceStreamPlacementBlueprint();
}
@@ -117,6 +117,15 @@ namespace osu.Game.Rulesets.Catch.Edit.Setup
Beatmap.Difficulty.CircleSize = circleSizeSlider.Current.Value;
Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
Beatmap.Difficulty.ApproachRate = approachRateSlider.Current.Value;
// in lazer catch, Overall Difficulty does *nothing* - as it should be in a sane world.
// in stable, it does *one extremely specific thing* which is influence the infamous `difficultyPeppyStars`
// which in turn affects score V1 (see `LegacyRulesetExtensions.CalculateDifficultyPeppyStars()`).
// there is a Ranking Criteria rule saying that Overall Difficulty and Approach Rate should match:
// https://osu.ppy.sh/wiki/en/Ranking_criteria/osu!catch
// the one case wherein that breaks stable is on some marathon maps;
// on those setting Overall Difficulty too high can lead to score V1 exceeding 32 bits ("score overflow").
// that case can be manually handled by mappers.
Beatmap.Difficulty.OverallDifficulty = approachRateSlider.Current.Value;
Beatmap.Difficulty.SliderMultiplier = baseVelocitySlider.Current.Value;
Beatmap.Difficulty.SliderTickRate = tickRateSlider.Current.Value;
@@ -13,8 +13,6 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public partial class CatchModFlashlight : ModFlashlight<CatchHitObject>
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
{
MinValue = 0.5f,
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Catch.Mods
public override string Name => "Floating Fruits";
public override string Acronym => "FF";
public override LocalisableString Description => "The fruits are... floating?";
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModFloatingFruits;
public void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
@@ -10,8 +10,6 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModHardRock : ModHardRock, IApplicableToBeatmapProcessor
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
public void ApplyToBeatmapProcessor(IBeatmapProcessor beatmapProcessor)
{
var catchProcessor = (CatchBeatmapProcessor)beatmapProcessor;
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Catch.Mods
public class CatchModHidden : ModHidden, IApplicableToDrawableRuleset<CatchHitObject>
{
public override LocalisableString Description => @"Play with fading fruits.";
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
private const double fade_out_offset_multiplier = 0.6;
private const double fade_out_duration_multiplier = 0.44;
@@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Catch.Mods
public override string Acronym => "MF";
public override LocalisableString Description => "Dashing by default, slow down!";
public override ModType Type => ModType.Fun;
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModMovingFast;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax) };
@@ -175,8 +175,7 @@ namespace osu.Game.Rulesets.Catch.Objects
/// </remarks>
public void ConvertFromSliderPath(SliderPath sliderPath, double velocity)
{
var sliderPathVertices = new List<Vector2>();
sliderPath.GetPathToProgress(sliderPathVertices, 0, 1);
var sliderPathVertices = sliderPath.CalculatedPath;
double time = 0;
@@ -0,0 +1,86 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Scoring
{
public class CatchScoreMultiplierCalculator : ScoreMultiplierCalculator
{
public CatchScoreMultiplierCalculator(ScoreMultiplierContext context)
: base(context)
{
#region Difficulty Reduction
Single<CatchModEasy>(hasMultiplier: 0.5);
Single<CatchModNoFail>(hasMultiplier: 0.5);
Single<CatchModHalfTime>(hasMultiplier: halfTime => rateAdjustMultiplier(halfTime.SpeedChange.Value));
Single<CatchModDaycore>(hasMultiplier: daycore => rateAdjustMultiplier(daycore.SpeedChange.Value));
#endregion
#region Difficulty Increase
Single<CatchModHardRock>(hasMultiplier: hardRock => hardRock.UsesDefaultConfiguration ? 1.12 : 1);
// Sudden Death
// Perfect
Single<CatchModDoubleTime>(hasMultiplier: doubleTime => rateAdjustMultiplier(doubleTime.SpeedChange.Value));
Single<CatchModNightcore>(hasMultiplier: nightcore => rateAdjustMultiplier(nightcore.SpeedChange.Value));
Single<CatchModHidden>(hasMultiplier: hidden => hidden.UsesDefaultConfiguration ? 1.06 : 1);
Single<CatchModFlashlight>(hasMultiplier: flashlight => flashlight.UsesDefaultConfiguration ? 1.12 : 1);
// Accuracy Challenge
#endregion
#region Conversion
Single<CatchModDifficultyAdjust>(hasMultiplier: 0.5);
Single<CatchModClassic>(hasMultiplier: 0.96);
// Mirror
#endregion
#region Automation
// Autoplay
// Cinema
Single<CatchModRelax>(hasMultiplier: 0.1);
#endregion
#region Fun
Single<ModWindUp>(hasMultiplier: 0.5);
Single<ModWindDown>(hasMultiplier: 0.5);
// Floating Fruits
// Muted
// No Scope
// Moving Fast
Single<CatchModSynesthesia>(hasMultiplier: 0.8);
#endregion
#region System
// Score V2
#endregion
}
private static double rateAdjustMultiplier(double speedChange)
{
// Round to the nearest multiple of 0.1.
double value = (int)(speedChange * 10) / 10.0;
// Offset back to 0.
value -= 1;
if (speedChange >= 1)
return 1 + value / 5;
else
return 0.6 + value;
}
}
}
@@ -19,6 +19,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup>
</Project>
@@ -13,6 +13,7 @@
</Compile>
</ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
</ItemGroup>
@@ -20,10 +20,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
[Test]
public void TestKeyCountChange()
{
FormSliderBar<float> keyCount = null!;
FormSliderBar<int> keyCount = null!;
AddStep("go to setup screen", () => InputManager.Key(Key.F4));
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormSliderBar<float>>().First(), () => Is.Not.Null);
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormSliderBar<int>>().First(), () => Is.Not.Null);
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
AddStep("change key count to 8", () =>
{
@@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
});
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
AddStep("refuse", () => InputManager.Key(Key.Number2));
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
AddUntilStep("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
AddStep("change key count to 8 again", () =>
{
@@ -41,5 +41,32 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
AddStep("acquiesce", () => InputManager.Key(Key.Number1));
AddUntilStep("beatmap became 8K", () => Game.Beatmap.Value.BeatmapInfo.Difficulty.CircleSize, () => Is.EqualTo(8));
}
[Test]
public void TestDualStagesChange()
{
FormCheckBox dualStages = null!;
FormSliderBar<int> keyCount = null!;
AddStep("go to setup screen", () => InputManager.Key(Key.F4));
AddUntilStep("retrieve dual stages checkbox", () => dualStages = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormCheckBox>().First(), () => Is.Not.Null);
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormSliderBar<int>>().First(), () => Is.Not.Null);
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
AddStep("set dual stages", () =>
{
dualStages.Current.Value = true;
});
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
AddStep("refuse", () => InputManager.Key(Key.Number2));
AddUntilStep("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
AddStep("set dual stages again", () =>
{
dualStages.Current.Value = true;
});
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().Single().CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
AddStep("acquiesce", () => InputManager.Key(Key.Number1));
AddUntilStep("beatmap became 12K", () => Game.Beatmap.Value.BeatmapInfo.Difficulty.CircleSize, () => Is.EqualTo(12));
}
}
}
@@ -57,6 +57,28 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
AddAssert("time is unchanged", () => EditorClock.CurrentTime, () => Is.EqualTo(initialTime));
}
[Test]
public void TestNoTwoObjectsAtSameTimeAndColumn()
{
AddStep("change seek setting to false", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, false));
AddStep("clear beatmap", () => EditorBeatmap.Clear());
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
AddStep("move mouse to centre of last column", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Last().ScreenSpaceDrawQuad.Centre));
AddStep("place note", () => InputManager.Click(MouseButton.Left));
AddAssert("beatmap has 1 object", () => EditorBeatmap.HitObjects, () => Has.Count.EqualTo(1));
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
AddStep("move mouse to centre of first column", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().First().ScreenSpaceDrawQuad.Centre));
AddStep("place note", () => InputManager.Click(MouseButton.Left));
AddAssert("beatmap has 2 objects", () => EditorBeatmap.HitObjects, () => Has.Count.EqualTo(2));
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
AddStep("move mouse to centre of last column", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Last().ScreenSpaceDrawQuad.Centre));
AddStep("place note", () => InputManager.Click(MouseButton.Left));
AddAssert("beatmap has 2 objects", () => EditorBeatmap.HitObjects, () => Has.Count.EqualTo(2));
}
private void placeObject()
{
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
@@ -27,6 +27,24 @@ namespace osu.Game.Rulesets.Mania.Tests
[TestCase("100374")]
[TestCase("1450162")]
[TestCase("4869637")]
[TestCase("1K")]
[TestCase("2K")]
[TestCase("3K")]
[TestCase("4K")]
[TestCase("5K")]
[TestCase("6K")]
[TestCase("7K")]
[TestCase("8K")]
[TestCase("9K")]
[TestCase("10K")]
// [TestCase("11K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("12K")]
// [TestCase("13K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("14K")]
// [TestCase("15K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("16K")]
// [TestCase("17K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("18K")]
public void Test(string name) => base.Test(name);
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
@@ -0,0 +1,45 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.IO.Stores;
using static osu.Game.Tests.Beatmaps.Formats.LegacyBeatmapEncoderTest;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class ManiaLegacyBeatmapEncoderTest
{
private static readonly DllResourceStore beatmaps_resource_store = new DllResourceStore(typeof(ManiaLegacyBeatmapEncoderTest).Assembly);
[TestCase("1K")]
[TestCase("2K")]
[TestCase("3K")]
[TestCase("4K")]
[TestCase("5K")]
[TestCase("6K")]
[TestCase("7K")]
[TestCase("8K")]
[TestCase("9K")]
[TestCase("10K")]
// [TestCase("11K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("12K")]
// [TestCase("13K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("14K")]
// [TestCase("15K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("16K")]
// [TestCase("17K")] <- See comment in `ManiaBeatmapConverter` ctor for disable reason.
[TestCase("18K")]
[TestCase("7K+1")]
public void TestEncodeDecodeStability(string name)
{
var decoded = DecodeFromLegacy(beatmaps_resource_store.GetStream($"Resources/Testing/Beatmaps/{name}.osu"), beatmaps_resource_store, name);
var decodedAfterEncode = DecodeFromLegacy(EncodeToLegacy(decoded), beatmaps_resource_store, name);
Sort(decoded.Beatmap);
Sort(decodedAfterEncode.Beatmap);
CompareBeatmaps(decoded, decodedAfterEncode);
}
}
}
@@ -0,0 +1,224 @@
// 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.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Tests.Rulesets;
namespace osu.Game.Rulesets.Mania.Tests
{
public class ManiaScoreMultiplierTest : RulesetScoreMultiplierTest
{
public ManiaScoreMultiplierTest()
: base(new ManiaRuleset())
{
}
private static readonly object[][] test_cases =
[
#region Difficulty Reduction
[new Mod[] { new ManiaModEasy() }, 0.5],
[new Mod[] { new ManiaModNoFail() }, 0.5],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.50 } } }, 0.1],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.55 } } }, 0.1],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.60 } } }, 0.2],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.65 } } }, 0.2],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.70 } } }, 0.3],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.75 } } }, 0.3],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.80 } } }, 0.4],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.85 } } }, 0.4],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.90 } } }, 0.5],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.95 } } }, 0.5],
[new Mod[] { new ManiaModHalfTime { SpeedChange = { Value = 0.99 } } }, 0.5],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.50 } } }, 0.1],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.55 } } }, 0.1],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.60 } } }, 0.2],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.65 } } }, 0.2],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.70 } } }, 0.3],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.75 } } }, 0.3],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.80 } } }, 0.4],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.85 } } }, 0.4],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.90 } } }, 0.5],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.95 } } }, 0.5],
[new Mod[] { new ManiaModDaycore { SpeedChange = { Value = 0.99 } } }, 0.5],
[new Mod[] { new ManiaModNoRelease() }, 0.9],
#endregion
#region Difficulty Increase
[new Mod[] { new ManiaModHardRock() }, 1],
[new Mod[] { new ManiaModSuddenDeath() }, 1],
[new Mod[] { new ManiaModPerfect() }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.01 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.05 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.10 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.15 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.20 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.25 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.30 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.35 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.40 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.45 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.50 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.55 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.60 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.65 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.70 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.75 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.80 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.85 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.90 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 1.95 } } }, 1],
[new Mod[] { new ManiaModDoubleTime { SpeedChange = { Value = 2.00 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.01 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.05 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.10 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.15 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.20 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.25 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.30 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.35 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.40 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.45 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.50 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.55 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.60 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.65 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.70 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.75 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.80 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.85 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.90 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 1.95 } } }, 1],
[new Mod[] { new ManiaModNightcore { SpeedChange = { Value = 2.00 } } }, 1],
[new Mod[] { new ManiaModFadeIn() }, 1],
[new Mod[] { new ManiaModHidden() }, 1],
[new Mod[] { new ManiaModCover() }, 1],
[new Mod[] { new ManiaModFlashlight() }, 1],
[new Mod[] { new ModAccuracyChallenge() }, 1],
#endregion
#region Conversion
[new Mod[] { new ManiaModRandom() }, 1],
[new Mod[] { new ManiaModDualStages() }, 1],
[new Mod[] { new ManiaModMirror() }, 1],
[new Mod[] { new ManiaModDifficultyAdjust() }, 0.5],
[new Mod[] { new ManiaModClassic() }, 0.96],
[new Mod[] { new ManiaModInvert() }, 1],
[new Mod[] { new ManiaModConstantSpeed() }, 0.9],
[new Mod[] { new ManiaModHoldOff() }, 0.9],
[new Mod[] { new ManiaModKey1() }, 0.9],
[new Mod[] { new ManiaModKey2() }, 0.9],
[new Mod[] { new ManiaModKey3() }, 0.9],
[new Mod[] { new ManiaModKey4() }, 0.9],
[new Mod[] { new ManiaModKey5() }, 0.9],
[new Mod[] { new ManiaModKey6() }, 0.9],
[new Mod[] { new ManiaModKey7() }, 0.9],
[new Mod[] { new ManiaModKey8() }, 0.9],
[new Mod[] { new ManiaModKey9() }, 0.9],
[new Mod[] { new ManiaModKey10() }, 0.9],
#endregion
#region Automation
[new Mod[] { new ManiaModAutoplay() }, 1],
[new Mod[] { new ManiaModCinema() }, 1],
#endregion
#region Fun
[new Mod[] { new ModWindUp() }, 0.5],
[new Mod[] { new ModWindDown() }, 0.5],
[new Mod[] { new ManiaModMuted() }, 1],
[new Mod[] { new ModAdaptiveSpeed() }, 0.5],
#endregion
#region System
[new Mod[] { new ManiaModScoreV2() }, 1],
#endregion
#region Combinations
[new Mod[] { new ManiaModEasy(), new ManiaModKey4() }, 0.5 * 0.9]
#endregion
];
[TestCaseSource(nameof(test_cases))]
public void TestMultipliers(Mod[] mods, double expectedMultiplier)
=> TestModCombination(mods, expectedMultiplier);
private static readonly object[][] key_mod_multiplier_test_cases =
[
// score end date, client version, expected multiplier
// scores verifiably from old clients.
[new DateTimeOffset(2024, 1, 31, 11, 0, 0, TimeSpan.Zero), "2024.130.2", 1],
[new DateTimeOffset(2024, 12, 9, 11, 0, 0, TimeSpan.Zero), "2024.1208.0", 1],
[new DateTimeOffset(2025, 6, 12, 11, 0, 0, TimeSpan.Zero), "2025.605.3", 1],
[new DateTimeOffset(2025, 6, 28, 11, 0, 0, TimeSpan.Zero), "2025.625.0-tachyon", 1],
[new DateTimeOffset(2025, 7, 11, 11, 0, 0, TimeSpan.Zero), "2025.710.0-lazer", 1],
[new DateTimeOffset(2025, 7, 15, 11, 0, 0, TimeSpan.Zero), "2025.711.0-tachyon", 1],
// scores without explicit client versions, predating the change of multiplier.
// those MUST have used the old multiplier.
[new DateTimeOffset(2024, 1, 31, 11, 0, 0, TimeSpan.Zero), "", 1],
[new DateTimeOffset(2024, 12, 9, 11, 0, 0, TimeSpan.Zero), "", 1],
[new DateTimeOffset(2025, 6, 12, 11, 0, 0, TimeSpan.Zero), "", 1],
[new DateTimeOffset(2025, 6, 28, 11, 0, 0, TimeSpan.Zero), "", 1],
[new DateTimeOffset(2025, 7, 11, 11, 0, 0, TimeSpan.Zero), "", 1],
[new DateTimeOffset(2025, 7, 15, 11, 0, 0, TimeSpan.Zero), "", 1],
// scores without explicit client versions, AFTER the change of multiplier.
// there is NO way of verifying whether these scores use the new or old multiplier, therefore GUESS that it's the new one.
// "thankfully" the window of opportunity for this occurring *should* be slim
// (from client release with new key mod multipliers on July 18, 2025
// until spectator server release which added client version writing to server-side replays on August 1, 2025).
[new DateTimeOffset(2025, 7, 19, 0, 20, 15, 0, TimeSpan.Zero), "", 0.9],
[new DateTimeOffset(2025, 7, 23, 0, 20, 15, 0, TimeSpan.Zero), "", 0.9],
[new DateTimeOffset(2025, 8, 19, 0, 20, 15, 0, TimeSpan.Zero), "", 0.9],
[new DateTimeOffset(2026, 6, 18, 0, 20, 15, 0, TimeSpan.Zero), "", 0.9],
[new DateTimeOffset(2026, 7, 18, 0, 20, 15, 0, TimeSpan.Zero), "", 0.9],
// scores verifiably from new clients.
[new DateTimeOffset(2025, 7, 19, 0, 20, 15, 0, TimeSpan.Zero), "2025.718.0-tachyon", 0.9],
[new DateTimeOffset(2025, 7, 23, 0, 20, 15, 0, TimeSpan.Zero), "2025.721.0-tachyon", 0.9],
[new DateTimeOffset(2025, 8, 19, 0, 20, 15, 0, TimeSpan.Zero), "2025.816.0-lazer", 0.9],
[new DateTimeOffset(2026, 6, 18, 0, 20, 15, 0, TimeSpan.Zero), "2026.518.0-lazer", 0.9],
[new DateTimeOffset(2026, 7, 18, 0, 20, 15, 0, TimeSpan.Zero), "2026.522.1-tachyon", 0.9],
];
[TestCaseSource(nameof(key_mod_multiplier_test_cases))]
public void TestKeyModMultiplierCompatibility(DateTimeOffset endDate, string clientVersion, double expectedMultiplier)
{
var calculator = Ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty(), new ScoreInfo
{
Date = endDate,
ClientVersion = clientVersion
}));
Assert.That(calculator.CalculateFor([new ManiaModKey4()]), Is.EqualTo(expectedMultiplier).Within(Precision.DOUBLE_EPSILON));
}
}
}
@@ -8,8 +8,10 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests.Mods
@@ -54,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
Mod = doubleTime,
PassCondition = () => Player.ScoreProcessor.JudgedHits > 0
&& Player.ScoreProcessor.Accuracy.Value == 1
&& Player.ScoreProcessor.TotalScore.Value == (long)(1_000_000 * doubleTime.ScoreMultiplier),
&& Player.ScoreProcessor.TotalScore.Value == (long)(1_000_000 * new ManiaScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty())).CalculateFor([doubleTime])),
Autoplay = false,
CreateBeatmap = () => new Beatmap
{
@@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
{
public partial class TestSceneManiaModNoRelease : RateAdjustedBeatmapTestScene
{
protected override Ruleset CreateRuleset() => new ManiaRuleset();
private const double time_before_head = 250;
private const double time_head = 1500;
private const double time_during_hold_1 = 2500;
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":511,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]}]}
@@ -0,0 +1,46 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:10K
[Difficulty]
HPDrainRate:5
CircleSize:10
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
25,192,0,1,0,0:0:0:0:
76,192,125,1,0,0:0:0:0:
128,192,250,1,0,0:0:0:0:
179,192,375,1,0,0:0:0:0:
230,192,500,1,0,0:0:0:0:
281,192,625,1,0,0:0:0:0:
332,192,750,1,0,0:0:0:0:
384,192,875,1,0,0:0:0:0:
435,192,1000,1,0,0:0:0:0:
486,192,1125,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":531,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]}]}
@@ -0,0 +1,47 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:11K
[Difficulty]
HPDrainRate:5
CircleSize:11
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
23,192,0,1,0,0:0:0:0:
69,192,125,1,0,0:0:0:0:
116,192,250,1,0,0:0:0:0:
162,192,375,1,0,0:0:0:0:
209,192,500,1,0,0:0:0:0:
256,192,625,1,0,0:0:0:0:
302,192,750,1,0,0:0:0:0:
349,192,875,1,0,0:0:0:0:
395,192,1000,1,0,0:0:0:0:
442,192,1125,1,0,0:0:0:0:
488,192,1250,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":551,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]}]}
@@ -0,0 +1,48 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:12K
[Difficulty]
HPDrainRate:5
CircleSize:12
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
21,192,0,1,0,0:0:0:0:
64,192,125,1,0,0:0:0:0:
106,192,250,1,0,0:0:0:0:
149,192,375,1,0,0:0:0:0:
192,192,500,1,0,0:0:0:0:
234,192,625,1,0,0:0:0:0:
277,192,750,1,0,0:0:0:0:
320,192,875,1,0,0:0:0:0:
362,192,1000,1,0,0:0:0:0:
405,192,1125,1,0,0:0:0:0:
448,192,1250,1,0,0:0:0:0:
490,192,1375,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]},{"RandomW":273326509,"RandomX":571,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"Column":12}]}]}
@@ -0,0 +1,49 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:13K
[Difficulty]
HPDrainRate:5
CircleSize:13
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
19,192,0,1,0,0:0:0:0:
59,192,125,1,0,0:0:0:0:
98,192,250,1,0,0:0:0:0:
137,192,375,1,0,0:0:0:0:
177,192,500,1,0,0:0:0:0:
216,192,625,1,0,0:0:0:0:
256,192,750,1,0,0:0:0:0:
295,192,875,1,0,0:0:0:0:
334,192,1000,1,0,0:0:0:0:
374,192,1125,1,0,0:0:0:0:
413,192,1250,1,0,0:0:0:0:
452,192,1375,1,0,0:0:0:0:
492,192,1500,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"Column":12}]},{"RandomW":273326509,"RandomX":591,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1625.0,"Objects":[{"StartTime":1625.0,"EndTime":1625.0,"Column":13}]}]}
@@ -0,0 +1,50 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:14K
[Difficulty]
HPDrainRate:5
CircleSize:14
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
18,192,0,1,0,0:0:0:0:
54,192,125,1,0,0:0:0:0:
91,192,250,1,0,0:0:0:0:
128,192,375,1,0,0:0:0:0:
164,192,500,1,0,0:0:0:0:
201,192,625,1,0,0:0:0:0:
237,192,750,1,0,0:0:0:0:
274,192,875,1,0,0:0:0:0:
310,192,1000,1,0,0:0:0:0:
347,192,1125,1,0,0:0:0:0:
384,192,1250,1,0,0:0:0:0:
420,192,1375,1,0,0:0:0:0:
457,192,1500,1,0,0:0:0:0:
493,192,1625,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"Column":12}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1625.0,"Objects":[{"StartTime":1625.0,"EndTime":1625.0,"Column":13}]},{"RandomW":273326509,"RandomX":611,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1750.0,"Objects":[{"StartTime":1750.0,"EndTime":1750.0,"Column":14}]}]}
@@ -0,0 +1,51 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:15K
[Difficulty]
HPDrainRate:5
CircleSize:15
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
17,192,0,1,0,0:0:0:0:
51,192,125,1,0,0:0:0:0:
85,192,250,1,0,0:0:0:0:
119,192,375,1,0,0:0:0:0:
153,192,500,1,0,0:0:0:0:
187,192,625,1,0,0:0:0:0:
221,192,750,1,0,0:0:0:0:
256,192,875,1,0,0:0:0:0:
290,192,1000,1,0,0:0:0:0:
324,192,1125,1,0,0:0:0:0:
358,192,1250,1,0,0:0:0:0:
392,192,1375,1,0,0:0:0:0:
426,192,1500,1,0,0:0:0:0:
460,192,1625,1,0,0:0:0:0:
494,192,1750,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"Column":12}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1625.0,"Objects":[{"StartTime":1625.0,"EndTime":1625.0,"Column":13}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1750.0,"Objects":[{"StartTime":1750.0,"EndTime":1750.0,"Column":14}]},{"RandomW":273326509,"RandomX":631,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1875.0,"Objects":[{"StartTime":1875.0,"EndTime":1875.0,"Column":15}]}]}
@@ -0,0 +1,52 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:16K
[Difficulty]
HPDrainRate:5
CircleSize:16
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
16,192,0,1,0,0:0:0:0:
48,192,125,1,0,0:0:0:0:
80,192,250,1,0,0:0:0:0:
112,192,375,1,0,0:0:0:0:
144,192,500,1,0,0:0:0:0:
176,192,625,1,0,0:0:0:0:
208,192,750,1,0,0:0:0:0:
240,192,875,1,0,0:0:0:0:
272,192,1000,1,0,0:0:0:0:
304,192,1125,1,0,0:0:0:0:
336,192,1250,1,0,0:0:0:0:
368,192,1375,1,0,0:0:0:0:
400,192,1500,1,0,0:0:0:0:
432,192,1625,1,0,0:0:0:0:
464,192,1750,1,0,0:0:0:0:
496,192,1875,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"Column":12}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1625.0,"Objects":[{"StartTime":1625.0,"EndTime":1625.0,"Column":13}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1750.0,"Objects":[{"StartTime":1750.0,"EndTime":1750.0,"Column":14}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1875.0,"Objects":[{"StartTime":1875.0,"EndTime":1875.0,"Column":15}]},{"RandomW":273326509,"RandomX":651,"RandomY":842502087,"RandomZ":3579807591,"StartTime":2000.0,"Objects":[{"StartTime":2000.0,"EndTime":2000.0,"Column":16}]}]}
@@ -0,0 +1,53 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:17K
[Difficulty]
HPDrainRate:5
CircleSize:17
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
15,192,0,1,0,0:0:0:0:
45,192,125,1,0,0:0:0:0:
75,192,250,1,0,0:0:0:0:
105,192,375,1,0,0:0:0:0:
135,192,500,1,0,0:0:0:0:
165,192,625,1,0,0:0:0:0:
195,192,750,1,0,0:0:0:0:
225,192,875,1,0,0:0:0:0:
256,192,1000,1,0,0:0:0:0:
286,192,1125,1,0,0:0:0:0:
316,192,1250,1,0,0:0:0:0:
346,192,1375,1,0,0:0:0:0:
376,192,1500,1,0,0:0:0:0:
406,192,1625,1,0,0:0:0:0:
436,192,1750,1,0,0:0:0:0:
466,192,1875,1,0,0:0:0:0:
496,192,2000,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1125.0,"Objects":[{"StartTime":1125.0,"EndTime":1125.0,"Column":9}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1250.0,"Objects":[{"StartTime":1250.0,"EndTime":1250.0,"Column":10}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1375.0,"Objects":[{"StartTime":1375.0,"EndTime":1375.0,"Column":11}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"Column":12}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1625.0,"Objects":[{"StartTime":1625.0,"EndTime":1625.0,"Column":13}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1750.0,"Objects":[{"StartTime":1750.0,"EndTime":1750.0,"Column":14}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1875.0,"Objects":[{"StartTime":1875.0,"EndTime":1875.0,"Column":15}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":2000.0,"Objects":[{"StartTime":2000.0,"EndTime":2000.0,"Column":16}]},{"RandomW":273326509,"RandomX":671,"RandomY":842502087,"RandomZ":3579807591,"StartTime":2125.0,"Objects":[{"StartTime":2125.0,"EndTime":2125.0,"Column":17}]}]}
@@ -0,0 +1,54 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:18K
[Difficulty]
HPDrainRate:5
CircleSize:18
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
14,192,0,1,0,0:0:0:0:
42,192,125,1,0,0:0:0:0:
71,192,250,1,0,0:0:0:0:
99,192,375,1,0,0:0:0:0:
128,192,500,1,0,0:0:0:0:
156,192,625,1,0,0:0:0:0:
184,192,750,1,0,0:0:0:0:
213,192,875,1,0,0:0:0:0:
241,192,1000,1,0,0:0:0:0:
270,192,1125,1,0,0:0:0:0:
298,192,1250,1,0,0:0:0:0:
327,192,1375,1,0,0:0:0:0:
355,192,1500,1,0,0:0:0:0:
384,192,1625,1,0,0:0:0:0:
412,192,1750,1,0,0:0:0:0:
440,192,1875,1,0,0:0:0:0:
469,192,2000,1,0,0:0:0:0:
497,192,2125,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":331,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]}]}
@@ -0,0 +1,37 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:1K
[Difficulty]
HPDrainRate:5
CircleSize:1
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
256,192,0,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":351,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":351,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]}]}
@@ -0,0 +1,38 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:2K
[Difficulty]
HPDrainRate:5
CircleSize:2
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
128,192,0,1,0,0:0:0:0:
384,192,125,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":371,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":371,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":371,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]}]}
@@ -0,0 +1,39 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:3K
[Difficulty]
HPDrainRate:5
CircleSize:3
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
85,192,0,1,0,0:0:0:0:
256,192,125,1,0,0:0:0:0:
426,192,250,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":391,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":391,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":391,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":391,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]}]}
@@ -0,0 +1,40 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:4K
[Difficulty]
HPDrainRate:5
CircleSize:4
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
64,192,0,1,0,0:0:0:0:
192,192,125,1,0,0:0:0:0:
320,192,250,1,0,0:0:0:0:
448,192,375,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":411,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":411,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":411,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":411,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":411,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]}]}
@@ -0,0 +1,41 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:5K
[Difficulty]
HPDrainRate:5
CircleSize:5
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
51,192,0,1,0,0:0:0:0:
153,192,125,1,0,0:0:0:0:
256,192,250,1,0,0:0:0:0:
358,192,375,1,0,0:0:0:0:
460,192,500,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":431,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":431,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":431,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":431,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":431,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":431,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]}]}
@@ -0,0 +1,42 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:6K
[Difficulty]
HPDrainRate:5
CircleSize:6
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
42,192,0,1,0,0:0:0:0:
128,192,125,1,0,0:0:0:0:
213,192,250,1,0,0:0:0:0:
298,192,375,1,0,0:0:0:0:
384,192,500,1,0,0:0:0:0:
469,192,625,1,0,0:0:0:0:
@@ -0,0 +1,45 @@
osu file format v14
[General]
Mode: 3
SpecialStyle:1
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:8K
[Difficulty]
HPDrainRate:5
CircleSize:8
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
32,192,0,1,0,0:0:0:0:
96,192,125,1,0,0:0:0:0:
160,192,250,1,0,0:0:0:0:
224,192,375,1,0,0:0:0:0:
288,192,500,1,0,0:0:0:0:
352,192,625,1,0,0:0:0:0:
416,192,750,1,0,0:0:0:0:
480,192,875,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":451,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]}]}
@@ -0,0 +1,43 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:7K
[Difficulty]
HPDrainRate:5
CircleSize:7
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
36,192,0,1,0,0:0:0:0:
109,192,125,1,0,0:0:0:0:
182,192,250,1,0,0:0:0:0:
256,192,375,1,0,0:0:0:0:
329,192,500,1,0,0:0:0:0:
402,192,625,1,0,0:0:0:0:
475,192,750,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":471,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]}]}
@@ -0,0 +1,44 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:8K
[Difficulty]
HPDrainRate:5
CircleSize:8
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
32,192,0,1,0,0:0:0:0:
96,192,125,1,0,0:0:0:0:
160,192,250,1,0,0:0:0:0:
224,192,375,1,0,0:0:0:0:
288,192,500,1,0,0:0:0:0:
352,192,625,1,0,0:0:0:0:
416,192,750,1,0,0:0:0:0:
480,192,875,1,0,0:0:0:0:
@@ -0,0 +1 @@
{"Mappings":[{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":0.0,"Objects":[{"StartTime":0.0,"EndTime":0.0,"Column":0}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":125.0,"Objects":[{"StartTime":125.0,"EndTime":125.0,"Column":1}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":250.0,"Objects":[{"StartTime":250.0,"EndTime":250.0,"Column":2}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":375.0,"Objects":[{"StartTime":375.0,"EndTime":375.0,"Column":3}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"Column":4}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":625.0,"Objects":[{"StartTime":625.0,"EndTime":625.0,"Column":5}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":750.0,"Objects":[{"StartTime":750.0,"EndTime":750.0,"Column":6}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":875.0,"Objects":[{"StartTime":875.0,"EndTime":875.0,"Column":7}]},{"RandomW":273326509,"RandomX":491,"RandomY":842502087,"RandomZ":3579807591,"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"Column":8}]}]}
@@ -0,0 +1,45 @@
osu file format v14
[General]
Mode: 3
[Metadata]
Title:keycount test
TitleUnicode:keycount test
Artist:mania
ArtistUnicode:mania
Creator:spaceman_atlas
Version:9K
[Difficulty]
HPDrainRate:5
CircleSize:9
OverallDifficulty:5
ApproachRate:5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Layer 4 (Overlay)
//Storyboard Sound Samples
[TimingPoints]
0,500,4,2,0,100,1,0
[HitObjects]
28,192,0,1,0,0:0:0:0:
85,192,125,1,0,0:0:0:0:
142,192,250,1,0,0:0:0:0:
199,192,375,1,0,0:0:0:0:
256,192,500,1,0,0:0:0:0:
312,192,625,1,0,0:0:0:0:
369,192,750,1,0,0:0:0:0:
426,192,875,1,0,0:0:0:0:
483,192,1000,1,0,0:0:0:0:
@@ -33,6 +33,8 @@ namespace osu.Game.Rulesets.Mania.Tests
/// </summary>
public partial class TestSceneHoldNoteInput : RateAdjustedBeatmapTestScene
{
protected override Ruleset CreateRuleset() => new ManiaRuleset();
private const double time_before_head = 250;
private const double time_head = 1500;
private const double time_during_hold_1 = 2500;
@@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Mania.Tests
{
public partial class TestSceneMaximumScore : RateAdjustedBeatmapTestScene
{
protected override Ruleset CreateRuleset() => new ManiaRuleset();
private ScoreAccessibleReplayPlayer currentPlayer = null!;
private List<JudgementResult> judgementResults = new List<JudgementResult>();
@@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Mania.Tests
{
public partial class TestSceneOutOfOrderHits : RateAdjustedBeatmapTestScene
{
protected override Ruleset CreateRuleset() => new ManiaRuleset();
[Test]
public void TestPreviousHitWindowDoesNotExtendPastNextObject()
{
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Mania.Tests
{
public partial class TestSceneReplayRewinding : RateAdjustedBeatmapTestScene
{
protected override Ruleset CreateRuleset() => new ManiaRuleset();
private ReplayPlayer currentPlayer = null!;
[Test]
@@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Mania.Tests
[TestFixture]
public partial class TestSceneTimingBasedNoteColouring : OsuTestScene
{
protected override Ruleset CreateRuleset() => new ManiaRuleset();
private Bindable<bool> configTimingBasedNoteColouring;
private ManualClock clock;
@@ -11,5 +11,6 @@
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
</ItemGroup>
</Project>
@@ -66,6 +66,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
if (IsForCurrentRuleset && TargetColumns > ManiaRuleset.MAX_STAGE_KEYS)
{
// If support for odd key counts above 10 (11 / 13 / 15 / 17K) is ever desired, this code needs to go.
// For now, it's probably fine, as stable doesn't support them outside of manual .osu edits either.
TargetColumns /= 2;
Dual = true;
}
@@ -9,6 +9,8 @@ using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Skinning.Default;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
using osuTK.Input;
@@ -90,5 +92,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
private float getNoteHeight(Column resultPlayfield) =>
resultPlayfield.ToScreenSpace(new Vector2(DefaultNotePiece.NOTE_HEIGHT)).Y -
resultPlayfield.ToScreenSpace(Vector2.Zero).Y;
public override bool ReplacesExistingObject(HitObject existing)
=> base.ReplacesExistingObject(existing) && HitObject.Column == ((IHasColumn)existing).Column;
}
}
@@ -2,7 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
@@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Edit
{
}
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders);
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.EditorHoldNote };
public override HitObjectPlacementBlueprint CreatePlacementBlueprint() => new HoldNotePlacementBlueprint();
}
@@ -3,11 +3,16 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit.Components.TernaryButtons;
using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
@@ -22,6 +27,29 @@ namespace osu.Game.Rulesets.Mania.Edit
{
}
protected override Drawable CreateNewComboButton() => new NewComboTernaryButton
{
Current = NewCombo,
CreateIcon = () => new Container
{
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Icon = OsuIcon.EditorNote,
Size = new Vector2(15),
},
new SpriteIcon
{
Icon = OsuIcon.EditorNewComboSparkles,
Size = new Vector2(20),
}
},
},
};
public override HitObjectSelectionBlueprint? CreateHitObjectBlueprintFor(HitObject hitObject)
{
switch (hitObject)
@@ -2,7 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
@@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Edit
{
}
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles);
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.EditorNote };
public override HitObjectPlacementBlueprint CreatePlacementBlueprint() => new NotePlacementBlueprint();
}
@@ -7,6 +7,7 @@ using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Resources.Localisation.Web;
@@ -19,13 +20,22 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
{
public override LocalisableString Title => EditorSetupStrings.DifficultyHeader;
private FormSliderBar<float> keyCountSlider { get; set; } = null!;
private FormSliderBar<int> keyCountSlider { get; set; } = null!;
private FormCheckBox dualStages { get; set; } = null!;
private FormCheckBox specialStyle { get; set; } = null!;
private FormSliderBar<float> healthDrainSlider { get; set; } = null!;
private FormSliderBar<float> overallDifficultySlider { get; set; } = null!;
private FormSliderBar<double> baseVelocitySlider { get; set; } = null!;
private FormSliderBar<double> tickRateSlider { get; set; } = null!;
private readonly BindableInt singleStageKeyCount = new BindableInt
{
Default = (int)BeatmapDifficulty.DEFAULT_DIFFICULTY,
Precision = 1,
};
private readonly BindableInt actualKeyCount = new BindableInt();
[Resolved]
private Editor? editor { get; set; }
@@ -37,20 +47,19 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
{
Children = new Drawable[]
{
keyCountSlider = new FormSliderBar<float>
keyCountSlider = new FormSliderBar<int>
{
Caption = BeatmapsetsStrings.ShowStatsCsMania,
HintText = "The number of columns in the beatmap",
Current = new BindableFloat(Beatmap.Difficulty.CircleSize)
{
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
MinValue = 0,
MaxValue = 10,
Precision = 1,
},
Current = singleStageKeyCount,
TransferValueOnCommit = true,
TabbableContentContainer = this,
},
dualStages = new FormCheckBox
{
Caption = "Dual stages",
HintText = "Doubles the number of keys by adding a second stage."
},
specialStyle = new FormCheckBox
{
Caption = "Use special (N+1) style",
@@ -117,16 +126,54 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
},
};
keyCountSlider.Current.BindValueChanged(updateKeyCount);
setStateFromActualKeyCount((int)Beatmap.Difficulty.CircleSize);
keyCountSlider.Current.BindValueChanged(_ => calculateActualKeyCount());
dualStages.Current.BindValueChanged(_ =>
{
updateSingleStageKeyCountBounds();
calculateActualKeyCount();
});
actualKeyCount.BindValueChanged(updateKeyCount);
healthDrainSlider.Current.BindValueChanged(_ => updateValues());
overallDifficultySlider.Current.BindValueChanged(_ => updateValues());
baseVelocitySlider.Current.BindValueChanged(_ => updateValues());
tickRateSlider.Current.BindValueChanged(_ => updateValues());
}
private void updateSingleStageKeyCountBounds()
{
singleStageKeyCount.MinValue = dualStages.Current.Value ? ManiaRuleset.MAX_STAGE_KEYS / 2 + 1 : 1;
singleStageKeyCount.MaxValue = dualStages.Current.Value ? LegacyBeatmapDecoder.MAX_MANIA_KEY_COUNT / 2 : ManiaRuleset.MAX_STAGE_KEYS;
}
private void setStateFromActualKeyCount(int keyCount)
{
actualKeyCount.Value = keyCount;
if (keyCount > 10)
{
dualStages.Current.Value = true;
singleStageKeyCount.Value = keyCount / 2;
}
else
{
dualStages.Current.Value = false;
singleStageKeyCount.Value = keyCount;
}
updateSingleStageKeyCountBounds();
}
private void calculateActualKeyCount()
{
actualKeyCount.Value = keyCountSlider.Current.Value * (dualStages.Current.Value ? 2 : 1);
}
private bool updatingKeyCount;
private void updateKeyCount(ValueChangedEvent<float> keyCount)
private void updateKeyCount(ValueChangedEvent<int> keyCount)
{
if (updatingKeyCount) return;
@@ -143,7 +190,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
Schedule(() =>
{
changeHandler!.RestoreState(-1);
Beatmap.Difficulty.CircleSize = keyCountSlider.Current.Value = keyCount.OldValue;
Beatmap.Difficulty.CircleSize = keyCount.OldValue;
setStateFromActualKeyCount(keyCount.OldValue);
updatingKeyCount = false;
});
}
@@ -158,7 +206,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
{
// for now, update these on commit rather than making BeatmapMetadata bindables.
// after switching database engines we can reconsider if switching to bindables is a good direction.
Beatmap.Difficulty.CircleSize = keyCountSlider.Current.Value;
Beatmap.Difficulty.CircleSize = actualKeyCount.Value;
Beatmap.SpecialStyle = specialStyle.Current.Value;
Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
@@ -98,9 +98,9 @@ namespace osu.Game.Rulesets.Mania
return false;
}
public bool FilterMayChangeFromMods(ValueChangedEvent<IReadOnlyList<Mod>> mods)
public bool FilterMayChangeFromMods(FilterCriteria criteria, ValueChangedEvent<IReadOnlyList<Mod>> mods)
{
if (includedKeyCounts.Count != LegacyBeatmapDecoder.MAX_MANIA_KEY_COUNT)
if (includedKeyCounts.Count != LegacyBeatmapDecoder.MAX_MANIA_KEY_COUNT || criteria.Group == GroupMode.Variant)
{
// Interpreting as the Mod type is required for equality comparison.
HashSet<Mod> oldSet = mods.OldValue.OfType<ManiaKeyMod>().AsEnumerable<Mod>().ToHashSet();
+23
View File
@@ -307,6 +307,8 @@ namespace osu.Game.Rulesets.Mania
}
}
public override ScoreMultiplierCalculator CreateScoreMultiplierCalculator(ScoreMultiplierContext context) => new ManiaScoreMultiplierCalculator(context);
public override string Description => "osu!mania";
public override string ShortName => SHORT_NAME;
@@ -327,6 +329,8 @@ namespace osu.Game.Rulesets.Mania
public override RulesetSettingsSubsection CreateSettings() => new ManiaSettingsSubsection(this);
public override LocalisableString VariantDescription => "Keys";
public override IEnumerable<int> AvailableVariants
{
get
@@ -483,6 +487,22 @@ namespace osu.Game.Rulesets.Mania
};
}
public override IEnumerable<RulesetBeatmapAttribute> GetBeatmapAttributesForRankedPlayCard(IBeatmapInfo beatmapInfo, IReadOnlyCollection<Mod> mods)
{
var attributes = GetBeatmapAttributesForDisplay(beatmapInfo, mods).ToList();
// Key count attribute isn't relevant to ranked play (it's decided by the pool).
attributes.RemoveAll(a => a.Acronym == "KC");
float holdNoteRatio = beatmapInfo.TotalObjectCount == 0 ? 0 : (float)beatmapInfo.EndTimeObjectCount / beatmapInfo.TotalObjectCount;
attributes.Insert(0, new RulesetBeatmapAttribute("Hold notes", @"HN", holdNoteRatio, holdNoteRatio, 1)
{
ValueFormat = "P0"
});
return attributes;
}
public override IRulesetFilterCriteria CreateRulesetFilterCriteria()
{
return new ManiaFilterCriteria();
@@ -498,6 +518,9 @@ namespace osu.Game.Rulesets.Mania
public int GetKeyCount(IBeatmapInfo beatmapInfo, IReadOnlyList<Mod>? mods = null)
=> ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo), mods);
public override int GetVariantForBeatmap(IBeatmapInfo beatmapInfo, IReadOnlyList<Mod>? mods = null)
=> GetKeyCount(beatmapInfo, mods);
}
public enum PlayfieldType
@@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => Name;
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 0.9;
public override bool Ranked => UsesDefaultConfiguration;
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
@@ -18,8 +18,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => "CS";
public override double ScoreMultiplier => 0.9;
public override LocalisableString Description => "No more tricky speed changes!";
public override IconUsage? Icon => OsuIcon.ModConstantSpeed;
@@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override LocalisableString Description => @"Decrease the playfield's viewing area.";
public override double ScoreMultiplier => 1;
protected override CoverExpandDirection ExpandDirection => Direction.Value;
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
@@ -7,9 +7,5 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModDoubleTime : ModDoubleTime, IManiaRateAdjustmentMod
{
// For now, all rate-increasing mods should be given a 1x multiplier in mania because it doesn't always
// make the map harder and is more of a personal preference.
// In the future, we can consider adjusting this by experimenting with not applying the hitwindow leniency.
public override double ScoreMultiplier => 1;
}
}
@@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override LocalisableString Description => @"Double the stages, double the fun!";
public override IconUsage? Icon => OsuIcon.ModDualStages;
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;
private bool isForCurrentRuleset;
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => "FI";
public override IconUsage? Icon => OsuIcon.ModFadeIn;
public override LocalisableString Description => @"Keys appear out of nowhere!";
public override double ScoreMultiplier => 1;
public override bool ValidForFreestyleAsRequiredMod => false;
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
@@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public partial class ManiaModFlashlight : ModFlashlight<ManiaHitObject>
{
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
@@ -10,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModHardRock : ModHardRock, IApplicableToHitObject
{
public override double ScoreMultiplier => 1;
public override bool Ranked => false;
public const double HIT_WINDOW_DIFFICULTY_MULTIPLIER = 1.4;
@@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Mania.Mods
private const float coverage_increase_per_combo = 0.5f;
public override LocalisableString Description => @"Keys fade out before you hit them!";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
{

Some files were not shown because too many files have changed in this diff Show More