mirror of
https://github.com/ppy/osu.git
synced 2026-05-19 11:20:24 +08:00
Compare commits
1592 Commits
@@ -27,10 +27,10 @@
|
||||
]
|
||||
},
|
||||
"ppy.localisationanalyser.tools": {
|
||||
"version": "2021.725.0",
|
||||
"version": "2021.1210.0",
|
||||
"commands": [
|
||||
"localisation"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +77,6 @@ jobs:
|
||||
run: msbuild osu.Android/osu.Android.csproj /restore /p:Configuration=Debug
|
||||
|
||||
build-only-ios:
|
||||
# While this workflow technically *can* run, it fails as iOS builds are blocked by multiple issues.
|
||||
# See https://github.com/ppy/osu-framework/issues/4677 for the details.
|
||||
# The job can be unblocked once those issues are resolved and game deployments can happen again.
|
||||
if: false
|
||||
name: Build only (iOS)
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
osu.Android
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
|
||||
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="2" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
osu.iOS
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
|
||||
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="2" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
|
||||
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu/riderModule.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="1" />
|
||||
<option name="vcsConfiguration" value="2" />
|
||||
</component>
|
||||
</project>
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
Thank you for showing interest in the development of osu!lazer! 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.
|
||||
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.
|
||||
|
||||
These are not "official rules" *per se*, but following them will help everyone deal with things in the most efficient manner.
|
||||
|
||||
@@ -32,7 +32,7 @@ Issues, bug reports and feature suggestions are welcomed, though please keep in
|
||||
|
||||
* **Provide more information when asked to do so.**
|
||||
|
||||
Sometimes when a bug is more elusive or complicated, none of the information listed above will pinpoint a concrete cause of the problem. In this case we will most likely ask you for additional info, such as a Windows Event Log dump or a copy of your local lazer database (`client.db`). Providing that information is beneficial to both parties - we can track down the problem better, and hopefully fix it for you at some point once we know where it is!
|
||||
Sometimes when a bug is more elusive or complicated, none of the information listed above will pinpoint a concrete cause of the problem. In this case we will most likely ask you for additional info, such as a Windows Event Log dump or a copy of your local osu! database (`client.db`). Providing that information is beneficial to both parties - we can track down the problem better, and hopefully fix it for you at some point once we know where it is!
|
||||
|
||||
* **When submitting a feature proposal, please describe it in the most understandable way you can.**
|
||||
|
||||
@@ -54,7 +54,7 @@ Issues, bug reports and feature suggestions are welcomed, though please keep in
|
||||
|
||||
We also welcome pull requests from unaffiliated contributors. The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues that you can work on; we also mark issues that we think would be good for newcomers with the [`good-first-issue`](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) label.
|
||||
|
||||
However, do keep in mind that the core team is committed to bringing osu!lazer up to par with stable first and foremost, so depending on what your contribution concerns, it might not be merged and released right away. Our approach to managing issues and their priorities is described [in the wiki](https://github.com/ppy/osu/wiki/Project-management).
|
||||
However, do keep in mind that the core team is committed to bringing osu!(lazer) up to par with osu!(stable) first and foremost, so depending on what your contribution concerns, it might not be merged and released right away. Our approach to managing issues and their priorities is described [in the wiki](https://github.com/ppy/osu/wiki/Project-management).
|
||||
|
||||
Here are some key things to note before jumping in:
|
||||
|
||||
@@ -128,7 +128,7 @@ Here are some key things to note before jumping in:
|
||||
|
||||
* **Don't mistake criticism of code for criticism of your person.**
|
||||
|
||||
As mentioned before, we are highly committed to quality when it comes to the lazer project. This means that contributions from less experienced community members can take multiple rounds of review to get to a mergeable state. We try our utmost best to never conflate a person with the code they authored, and to keep the discussion focused on the code at all times. Please consider our comments and requests a learning experience, and don't treat it as a personal attack.
|
||||
As mentioned before, we are highly committed to quality when it comes to the osu! project. This means that contributions from less experienced community members can take multiple rounds of review to get to a mergeable state. We try our utmost best to never conflate a person with the code they authored, and to keep the discussion focused on the code at all times. Please consider our comments and requests a learning experience, and don't treat it as a personal attack.
|
||||
|
||||
* **Feel free to reach out for help.**
|
||||
|
||||
|
||||
@@ -8,4 +8,10 @@ M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.
|
||||
M:osu.Framework.Bindables.IBindableList`1.GetBoundCopy();Fails on iOS. Use manual ctor + BindTo instead. (see https://github.com/mono/mono/issues/19900)
|
||||
T:Microsoft.EntityFrameworkCore.Internal.EnumerableExtensions;Don't use internal extension methods.
|
||||
T:Microsoft.EntityFrameworkCore.Internal.TypeExtensions;Don't use internal extension methods.
|
||||
M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.HasFlagFast<T>() instead.
|
||||
T:NuGet.Packaging.CollectionExtensions;Don't use internal extension methods.
|
||||
M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.HasFlagFast<T>() instead.
|
||||
M:Realms.IRealmCollection`1.SubscribeForNotifications`1(Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IRealmCollection<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IQueryable<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IList<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks.
|
||||
P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
A free-to-win rhythm game. Rhythm is just a *click* away!
|
||||
|
||||
The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Currently known by and released under the codename "*lazer*". As in sharper than cutting-edge.
|
||||
The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Currently known by and released under the release codename "*lazer*". As in sharper than cutting-edge.
|
||||
|
||||
## Status
|
||||
|
||||
@@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi
|
||||
|
||||
**Latest build:**
|
||||
|
||||
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.15+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| ------------- | ------------- | ------------- | ------------- | ------------- |
|
||||
|
||||
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
|
||||
@@ -48,7 +48,7 @@ You can see some examples of custom rulesets by visiting the [custom ruleset dir
|
||||
|
||||
Please make sure you have the following prerequisites:
|
||||
|
||||
- A desktop platform with the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) or higher installed.
|
||||
- A desktop platform with the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) installed.
|
||||
- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
|
||||
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
|
||||
public class TestSceneOsuGame : OsuTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, OsuGameBase gameBase)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+2
-2
@@ -13,14 +13,14 @@ namespace osu.Game.Rulesets.EmptyFreeform
|
||||
{
|
||||
public class EmptyFreeformDifficultyCalculator : DifficultyCalculator
|
||||
{
|
||||
public EmptyFreeformDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
public EmptyFreeformDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
return new DifficultyAttributes(mods, skills, 0);
|
||||
return new DifficultyAttributes(mods, 0);
|
||||
}
|
||||
|
||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||
|
||||
+2
-2
@@ -30,8 +30,8 @@ namespace osu.Game.Rulesets.EmptyFreeform
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
||||
new EmptyFreeformBeatmapConverter(beatmap, this);
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) =>
|
||||
new EmptyFreeformDifficultyCalculator(this, beatmap);
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) =>
|
||||
new EmptyFreeformDifficultyCalculator(RulesetInfo, beatmap);
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||
{
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
||||
public class TestSceneOsuGame : OsuTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, OsuGameBase gameBase)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+2
-2
@@ -13,14 +13,14 @@ namespace osu.Game.Rulesets.Pippidon
|
||||
{
|
||||
public class PippidonDifficultyCalculator : DifficultyCalculator
|
||||
{
|
||||
public PippidonDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
public PippidonDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
return new DifficultyAttributes(mods, skills, 0);
|
||||
return new DifficultyAttributes(mods, 0);
|
||||
}
|
||||
|
||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace osu.Game.Rulesets.Pippidon
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) =>
|
||||
new PippidonBeatmapConverter(beatmap, this);
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) =>
|
||||
new PippidonDifficultyCalculator(this, beatmap);
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) =>
|
||||
new PippidonDifficultyCalculator(RulesetInfo, beatmap);
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||
{
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
|
||||
public class TestSceneOsuGame : OsuTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, OsuGameBase gameBase)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+2
-2
@@ -13,14 +13,14 @@ namespace osu.Game.Rulesets.EmptyScrolling
|
||||
{
|
||||
public class EmptyScrollingDifficultyCalculator : DifficultyCalculator
|
||||
{
|
||||
public EmptyScrollingDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
public EmptyScrollingDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
return new DifficultyAttributes(mods, skills, 0);
|
||||
return new DifficultyAttributes(mods, 0);
|
||||
}
|
||||
|
||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.EmptyScrolling
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new EmptyScrollingBeatmapConverter(beatmap, this);
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new EmptyScrollingDifficultyCalculator(this, beatmap);
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new EmptyScrollingDifficultyCalculator(RulesetInfo, beatmap);
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||
{
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
||||
public class TestSceneOsuGame : OsuTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, OsuGameBase gameBase)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+2
-2
@@ -13,14 +13,14 @@ namespace osu.Game.Rulesets.Pippidon
|
||||
{
|
||||
public class PippidonDifficultyCalculator : DifficultyCalculator
|
||||
{
|
||||
public PippidonDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
public PippidonDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
return new DifficultyAttributes(mods, skills, 0);
|
||||
return new DifficultyAttributes(mods, 0);
|
||||
}
|
||||
|
||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Pippidon
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new PippidonBeatmapConverter(beatmap, this);
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new PippidonDifficultyCalculator(this, beatmap);
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new PippidonDifficultyCalculator(RulesetInfo, beatmap);
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||
{
|
||||
|
||||
+1
-2
@@ -7,7 +7,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Pippidon.UI
|
||||
private PippidonCharacter pippidon;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load()
|
||||
{
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
|
||||
+3
-3
@@ -51,11 +51,11 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1112.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1108.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.118.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
<PackageReference Include="Realm" Version="10.6.0" />
|
||||
<PackageReference Include="Realm" Version="10.8.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -17,7 +17,7 @@ using osu.Game.Database;
|
||||
|
||||
namespace osu.Android
|
||||
{
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance, Exported = true)]
|
||||
[Activity(ConfigurationChanges = DEFAULT_CONFIG_CHANGES, Exported = true, LaunchMode = DEFAULT_LAUNCH_MODE, MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser)]
|
||||
[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 = "*/*")]
|
||||
@@ -47,11 +47,6 @@ namespace osu.Android
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
// The default current directory on android is '/'.
|
||||
// On some devices '/' maps to the app data directory. On others it maps to the root of the internal storage.
|
||||
// In order to have a consistent current directory on all devices the full path of the app data directory is set as the current directory.
|
||||
System.Environment.CurrentDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
|
||||
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
// OnNewIntent() only fires for an activity if it's *re-launched* while it's on top of the activity stack.
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" package="sh.ppy.osulazer" android:installLocation="auto" android:versionName="0.1.0">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@drawable/lazer" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,8 @@
|
||||
// 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 Android;
|
||||
using Android.App;
|
||||
|
||||
// used for AndroidBatteryInfo
|
||||
[assembly: UsesPermission(Manifest.Permission.BatteryStats)]
|
||||
@@ -29,6 +29,7 @@
|
||||
<Compile Include="GameplayScreenRotationLocker.cs" />
|
||||
<Compile Include="OsuGameActivity.cs" />
|
||||
<Compile Include="OsuGameAndroid.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
|
||||
@@ -108,7 +108,10 @@ namespace osu.Desktop
|
||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty);
|
||||
|
||||
// update ruleset
|
||||
presence.Assets.SmallImageKey = ruleset.Value.ID <= 3 ? $"mode_{ruleset.Value.ID}" : "mode_custom";
|
||||
int onlineID = ruleset.Value.OnlineID;
|
||||
bool isLegacyRuleset = onlineID >= 0 && onlineID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID;
|
||||
|
||||
presence.Assets.SmallImageKey = isLegacyRuleset ? $"mode_{onlineID}" : "mode_custom";
|
||||
presence.Assets.SmallImageText = ruleset.Value.Name;
|
||||
|
||||
client.SetPresence(presence);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Desktop.LegacyIpc
|
||||
{
|
||||
/// <summary>
|
||||
/// A difficulty calculation request from the legacy client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Synchronise any changes with osu!stable.
|
||||
/// </remarks>
|
||||
public class LegacyIpcDifficultyCalculationRequest
|
||||
{
|
||||
public string BeatmapFile { get; set; }
|
||||
public int RulesetId { get; set; }
|
||||
public int Mods { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Desktop.LegacyIpc
|
||||
{
|
||||
/// <summary>
|
||||
/// A difficulty calculation response returned to the legacy client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Synchronise any changes with osu!stable.
|
||||
/// </remarks>
|
||||
public class LegacyIpcDifficultyCalculationResponse
|
||||
{
|
||||
public double StarRating { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Platform;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace osu.Desktop.LegacyIpc
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IpcMessage"/> that can be used to communicate to and from legacy clients.
|
||||
/// <para>
|
||||
/// In order to deserialise types at either end, types must be serialised as their <see cref="System.Type.AssemblyQualifiedName"/>,
|
||||
/// however this cannot be done since osu!stable and osu!lazer live in two different assemblies.
|
||||
/// <br />
|
||||
/// To get around this, this class exists which serialises a payload (<see cref="LegacyIpcMessage.Data"/>) as an <see cref="System.Object"/> type,
|
||||
/// which can be deserialised at either end because it is part of the core library (mscorlib / System.Private.CorLib).
|
||||
/// The payload contains the data to be sent over the IPC channel.
|
||||
/// <br />
|
||||
/// At either end, Json.NET deserialises the payload into a <see cref="JObject"/> which is manually converted back into the expected <see cref="LegacyIpcMessage.Data"/> type,
|
||||
/// which then further contains another <see cref="JObject"/> representing the data sent over the IPC channel whose type can likewise be lazily matched through
|
||||
/// <see cref="LegacyIpcMessage.Data.MessageType"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Synchronise any changes with osu-stable.
|
||||
/// </remarks>
|
||||
public class LegacyIpcMessage : IpcMessage
|
||||
{
|
||||
public LegacyIpcMessage()
|
||||
{
|
||||
// Types/assemblies are not inter-compatible, so always serialise/deserialise into objects.
|
||||
base.Type = typeof(object).FullName;
|
||||
}
|
||||
|
||||
public new string Type => base.Type; // Hide setter.
|
||||
|
||||
public new object Value
|
||||
{
|
||||
get => base.Value;
|
||||
set => base.Value = new Data
|
||||
{
|
||||
MessageType = value.GetType().Name,
|
||||
MessageData = value
|
||||
};
|
||||
}
|
||||
|
||||
public class Data
|
||||
{
|
||||
public string MessageType { get; set; }
|
||||
public object MessageData { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// 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 Newtonsoft.Json.Linq;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Desktop.LegacyIpc
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides IPC to legacy osu! clients.
|
||||
/// </summary>
|
||||
public class LegacyTcpIpcProvider : TcpIpcProvider
|
||||
{
|
||||
private static readonly Logger logger = Logger.GetLogger("legacy-ipc");
|
||||
|
||||
public LegacyTcpIpcProvider()
|
||||
: base(45357)
|
||||
{
|
||||
MessageReceived += msg =>
|
||||
{
|
||||
try
|
||||
{
|
||||
logger.Add("Processing legacy IPC message...");
|
||||
logger.Add($" {msg.Value}", LogLevel.Debug);
|
||||
|
||||
// See explanation in LegacyIpcMessage for why this is done this way.
|
||||
var legacyData = ((JObject)msg.Value).ToObject<LegacyIpcMessage.Data>();
|
||||
object value = parseObject((JObject)legacyData!.MessageData, legacyData.MessageType);
|
||||
|
||||
return new LegacyIpcMessage
|
||||
{
|
||||
Value = onLegacyIpcMessageReceived(value)
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Add($"Processing IPC message failed: {msg.Value}", exception: ex);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private object parseObject(JObject value, string type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case nameof(LegacyIpcDifficultyCalculationRequest):
|
||||
return value.ToObject<LegacyIpcDifficultyCalculationRequest>()
|
||||
?? throw new InvalidOperationException($"Failed to parse request {value}");
|
||||
|
||||
case nameof(LegacyIpcDifficultyCalculationResponse):
|
||||
return value.ToObject<LegacyIpcDifficultyCalculationResponse>()
|
||||
?? throw new InvalidOperationException($"Failed to parse request {value}");
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported object type {type}");
|
||||
}
|
||||
}
|
||||
|
||||
private object onLegacyIpcMessageReceived(object message)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case LegacyIpcDifficultyCalculationRequest req:
|
||||
try
|
||||
{
|
||||
var ruleset = getLegacyRulesetFromID(req.RulesetId);
|
||||
|
||||
Mod[] mods = ruleset.ConvertFromLegacyMods((LegacyMods)req.Mods).ToArray();
|
||||
WorkingBeatmap beatmap = new FlatFileWorkingBeatmap(req.BeatmapFile, _ => ruleset);
|
||||
|
||||
return new LegacyIpcDifficultyCalculationResponse
|
||||
{
|
||||
StarRating = ruleset.CreateDifficultyCalculator(beatmap).Calculate(mods).StarRating
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new LegacyIpcDifficultyCalculationResponse();
|
||||
}
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported message type {message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static Ruleset getLegacyRulesetFromID(int rulesetId)
|
||||
{
|
||||
switch (rulesetId)
|
||||
{
|
||||
case 0:
|
||||
return new OsuRuleset();
|
||||
|
||||
case 1:
|
||||
return new TaikoRuleset();
|
||||
|
||||
case 2:
|
||||
return new CatchRuleset();
|
||||
|
||||
case 3:
|
||||
return new ManiaRuleset();
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Invalid ruleset id");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,11 @@ using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using osu.Desktop.Security;
|
||||
using osu.Desktop.Overlays;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game;
|
||||
using osu.Desktop.Updater;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Updater;
|
||||
using osu.Desktop.Windows;
|
||||
using osu.Framework.Threading;
|
||||
@@ -27,13 +24,9 @@ namespace osu.Desktop
|
||||
{
|
||||
internal class OsuGameDesktop : OsuGame
|
||||
{
|
||||
private readonly bool noVersionOverlay;
|
||||
private VersionManager versionManager;
|
||||
|
||||
public OsuGameDesktop(string[] args = null)
|
||||
: base(args)
|
||||
{
|
||||
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
|
||||
}
|
||||
|
||||
public override StableStorage GetStorageForStableInstall()
|
||||
@@ -70,7 +63,9 @@ namespace osu.Desktop
|
||||
if (!string.IsNullOrEmpty(stableInstallPath) && checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
|
||||
@@ -93,6 +88,11 @@ namespace osu.Desktop
|
||||
|
||||
protected override UpdateManager CreateUpdateManager()
|
||||
{
|
||||
string packageManaged = Environment.GetEnvironmentVariable("OSU_EXTERNAL_UPDATE_PROVIDER");
|
||||
|
||||
if (!string.IsNullOrEmpty(packageManaged))
|
||||
return new NoActionUpdateManager();
|
||||
|
||||
switch (RuntimeInfo.OS)
|
||||
{
|
||||
case RuntimeInfo.Platform.Windows:
|
||||
@@ -107,9 +107,6 @@ namespace osu.Desktop
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (!noVersionOverlay)
|
||||
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, Add);
|
||||
|
||||
LoadComponentAsync(new DiscordRichPresence(), Add);
|
||||
|
||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||
@@ -118,23 +115,6 @@ namespace osu.Desktop
|
||||
LoadComponentAsync(new ElevatedPrivilegesChecker(), Add);
|
||||
}
|
||||
|
||||
protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
|
||||
{
|
||||
base.ScreenChanged(lastScreen, newScreen);
|
||||
|
||||
switch (newScreen)
|
||||
{
|
||||
case IntroScreen _:
|
||||
case MainMenu _:
|
||||
versionManager?.Show();
|
||||
break;
|
||||
|
||||
default:
|
||||
versionManager?.Hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetHost(GameHost host)
|
||||
{
|
||||
base.SetHost(host);
|
||||
|
||||
+20
-5
@@ -5,6 +5,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Desktop.LegacyIpc;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Development;
|
||||
using osu.Framework.Logging;
|
||||
@@ -18,8 +19,10 @@ namespace osu.Desktop
|
||||
{
|
||||
private const string base_game_name = @"osu";
|
||||
|
||||
private static LegacyTcpIpcProvider legacyIpc;
|
||||
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Back up the cwd before DesktopGameHost changes it
|
||||
string cwd = Environment.CurrentDirectory;
|
||||
@@ -69,14 +72,28 @@ namespace osu.Desktop
|
||||
throw new TimeoutException(@"IPC took too long to send");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// we want to allow multiple instances to be started when in debug.
|
||||
if (!DebugUtils.IsDebugBuild)
|
||||
{
|
||||
Logger.Log(@"osu! does not support multiple running instances.", LoggingTarget.Runtime, LogLevel.Error);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (host.IsPrimaryInstance)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Log("Starting legacy IPC provider...");
|
||||
legacyIpc = new LegacyTcpIpcProvider();
|
||||
legacyIpc.Bind();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "Failed to start legacy IPC provider");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +101,6 @@ namespace osu.Desktop
|
||||
host.Run(new TournamentGame());
|
||||
else
|
||||
host.Run(new OsuGameDesktop(args));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,10 +73,10 @@ namespace osu.Desktop.Security
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, NotificationOverlay notificationOverlay)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Icon = FontAwesome.Solid.ShieldAlt;
|
||||
IconBackgound.Colour = colours.YellowDark;
|
||||
IconBackground.Colour = colours.YellowDark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,10 @@ namespace osu.Desktop.Updater
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the case of an error, a separate notification will be displayed.
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
notification.Close();
|
||||
|
||||
Logger.Error(e, @"update failed!");
|
||||
}
|
||||
}
|
||||
@@ -183,6 +186,19 @@ namespace osu.Desktop.Updater
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
// cancelling updates is not currently supported by the underlying updater.
|
||||
// only allow dismissing for now.
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case ProgressNotificationState.Cancelled:
|
||||
base.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SquirrelLogger : Splat.ILogger, IDisposable
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace osu.Desktop.Windows
|
||||
{
|
||||
private Bindable<bool> disableWinKey;
|
||||
private IBindable<bool> localUserPlaying;
|
||||
private IBindable<bool> isActive;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
@@ -24,13 +25,16 @@ namespace osu.Desktop.Windows
|
||||
localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
|
||||
localUserPlaying.BindValueChanged(_ => updateBlocking());
|
||||
|
||||
isActive = host.IsActive.GetBoundCopy();
|
||||
isActive.BindValueChanged(_ => updateBlocking());
|
||||
|
||||
disableWinKey = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey);
|
||||
disableWinKey.BindValueChanged(_ => updateBlocking(), true);
|
||||
}
|
||||
|
||||
private void updateBlocking()
|
||||
{
|
||||
bool shouldDisable = disableWinKey.Value && localUserPlaying.Value;
|
||||
bool shouldDisable = isActive.Value && disableWinKey.Value && localUserPlaying.Value;
|
||||
|
||||
if (shouldDisable)
|
||||
host.InputThread.Scheduler.Add(WindowsKey.Disable);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// ReSharper disable IdentifierTypo
|
||||
|
||||
namespace osu.Desktop.Windows
|
||||
{
|
||||
internal class WindowsKey
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
||||
<PackageReference Include="nunit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using osu.Framework.Android;
|
||||
using osu.Game.Tests;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests.Android
|
||||
{
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
|
||||
[Activity(ConfigurationChanges = DEFAULT_CONFIG_CHANGES, Exported = true, LaunchMode = DEFAULT_LAUNCH_MODE, MainLauncher = true)]
|
||||
public class MainActivity : AndroidGameActivity
|
||||
{
|
||||
protected override Framework.Game CreateGame() => new OsuTestBrowser();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.iOS;
|
||||
using UIKit;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests.iOS
|
||||
@@ -9,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,7 @@
|
||||
</array>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/AppIcon.appiconset</string>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -14,7 +14,6 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(10000)]
|
||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||
@@ -27,6 +26,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
[TestCase("hardrock-repeat-slider", new[] { typeof(CatchModHardRock) })]
|
||||
[TestCase("hardrock-spinner", new[] { typeof(CatchModHardRock) })]
|
||||
[TestCase("right-bound-hr-offset", new[] { typeof(CatchModHardRock) })]
|
||||
[TestCase("basic-hyperdash")]
|
||||
public new void Test(string name, params Type[] mods) => base.Test(name, mods);
|
||||
|
||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||
@@ -70,6 +70,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
HitObject = hitObject;
|
||||
startTime = 0;
|
||||
position = 0;
|
||||
hyperDash = false;
|
||||
}
|
||||
|
||||
private double startTime;
|
||||
@@ -88,8 +89,17 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
set => position = value;
|
||||
}
|
||||
|
||||
private bool hyperDash;
|
||||
|
||||
public bool HyperDash
|
||||
{
|
||||
get => (HitObject as PalpableCatchHitObject)?.HyperDash ?? hyperDash;
|
||||
set => hyperDash = value;
|
||||
}
|
||||
|
||||
public bool Equals(ConvertValue other)
|
||||
=> Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
|
||||
&& Precision.AlmostEquals(Position, other.Position, conversion_lenience);
|
||||
&& Precision.AlmostEquals(Position, other.Position, conversion_lenience)
|
||||
&& HyperDash == other.HyperDash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public void TestClockRateAdjusted(double expected, string name)
|
||||
=> Test(expected, name, new CatchModDoubleTime());
|
||||
|
||||
protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(new CatchRuleset(), beatmap);
|
||||
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new CatchDifficultyCalculator(new CatchRuleset().RulesetInfo, beatmap);
|
||||
|
||||
protected override Ruleset CreateRuleset() => new CatchRuleset();
|
||||
}
|
||||
|
||||
@@ -168,6 +168,28 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
checkHyperDash(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLastBananaShouldClearPlateOnMiss()
|
||||
{
|
||||
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||
checkPlate(1);
|
||||
AddStep("miss banana", () => attemptCatch(new Banana { X = 100 }));
|
||||
checkPlate(1);
|
||||
AddStep("miss last banana", () => attemptCatch(new Banana { LastInCombo = true, X = 100 }));
|
||||
checkPlate(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLastBananaShouldClearPlateOnCatch()
|
||||
{
|
||||
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||
checkPlate(1);
|
||||
AddStep("catch banana", () => attemptCatch(new Banana()));
|
||||
checkPlate(2);
|
||||
AddStep("catch last banana", () => attemptCatch(new Banana { LastInCombo = true }));
|
||||
checkPlate(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCatcherRandomStacking()
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
var controlPointInfo = new ControlPointInfo();
|
||||
controlPointInfo.Add(0, new TimingControlPoint());
|
||||
|
||||
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
||||
IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject> { new Fruit() },
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
@@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJuicestream()
|
||||
public void TestJuiceStream()
|
||||
{
|
||||
AddStep("hit juicestream", () => spawnJuiceStream(true));
|
||||
AddUntilStep("wait for completion", () => playfieldIsEmpty);
|
||||
|
||||
@@ -37,20 +37,20 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
AddStep("show hyperdash droplet", () => SetContents(_ => createDrawableDroplet(true)));
|
||||
}
|
||||
|
||||
private Drawable createDrawableFruit(int indexInBeatmap, bool hyperdash = false) =>
|
||||
private Drawable createDrawableFruit(int indexInBeatmap, bool hyperDash = false) =>
|
||||
new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit
|
||||
{
|
||||
IndexInBeatmap = indexInBeatmap,
|
||||
HyperDashBindable = { Value = hyperdash }
|
||||
HyperDashBindable = { Value = hyperDash }
|
||||
}));
|
||||
|
||||
private Drawable createDrawableBanana() =>
|
||||
new TestDrawableCatchHitObjectSpecimen(new DrawableBanana(new Banana()));
|
||||
|
||||
private Drawable createDrawableDroplet(bool hyperdash = false) =>
|
||||
private Drawable createDrawableDroplet(bool hyperDash = false) =>
|
||||
new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet
|
||||
{
|
||||
HyperDashBindable = { Value = hyperdash }
|
||||
HyperDashBindable = { Value = hyperDash }
|
||||
}));
|
||||
|
||||
private Drawable createDrawableTinyDroplet() => new TestDrawableCatchHitObjectSpecimen(new DrawableTinyDroplet(new TinyDroplet()));
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
private Drawable setupSkinHierarchy(Drawable child, ISkin skin)
|
||||
{
|
||||
var legacySkinProvider = new SkinProvidingContainer(skins.GetSkin(DefaultLegacySkin.Info));
|
||||
var legacySkinProvider = new SkinProvidingContainer(skins.GetSkin(DefaultLegacySkin.CreateInfo()));
|
||||
var testSkinProvider = new SkinProvidingContainer(skin);
|
||||
var legacySkinTransformer = new SkinProvidingContainer(new CatchLegacySkinTransformer(testSkinProvider));
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
return base.GetDisplayNameForHitResult(result);
|
||||
}
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new CatchDifficultyCalculator(RulesetInfo, beatmap);
|
||||
|
||||
public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new CatchLegacySkinTransformer(skin);
|
||||
|
||||
|
||||
@@ -1,12 +1,35 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
{
|
||||
public class CatchDifficultyAttributes : DifficultyAttributes
|
||||
{
|
||||
[JsonProperty("approach_rate")]
|
||||
public double ApproachRate { get; set; }
|
||||
|
||||
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||
{
|
||||
foreach (var v in base.ToDatabaseAttributes())
|
||||
yield return v;
|
||||
|
||||
// Todo: osu!catch should not output star rating in the 'aim' attribute.
|
||||
yield return (ATTRIB_ID_AIM, StarRating);
|
||||
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
||||
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||
}
|
||||
|
||||
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
|
||||
{
|
||||
base.FromDatabaseAttributes(values);
|
||||
|
||||
StarRating = values[ATTRIB_ID_AIM];
|
||||
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
||||
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
|
||||
private float halfCatcherWidth;
|
||||
|
||||
public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
public CatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
if (beatmap.HitObjects.Count == 0)
|
||||
return new CatchDifficultyAttributes { Mods = mods, Skills = skills };
|
||||
return new CatchDifficultyAttributes { Mods = mods };
|
||||
|
||||
// this is the same as osu!, so there's potential to share the implementation... maybe
|
||||
double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;
|
||||
@@ -42,7 +42,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
Mods = mods,
|
||||
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
|
||||
MaxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType<JuiceStream>().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet)),
|
||||
Skills = skills
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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.Difficulty;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
{
|
||||
public class CatchPerformanceAttributes : PerformanceAttributes
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
{
|
||||
}
|
||||
|
||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||
public override PerformanceAttributes Calculate()
|
||||
{
|
||||
mods = Score.Mods;
|
||||
|
||||
@@ -44,15 +44,11 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
// Longer maps are worth more. "Longer" means how many hits there are which can contribute to combo
|
||||
int numTotalHits = totalComboHits();
|
||||
|
||||
// Longer maps are worth more
|
||||
double lengthBonus =
|
||||
0.95 + 0.3 * Math.Min(1.0, numTotalHits / 2500.0) +
|
||||
(numTotalHits > 2500 ? Math.Log10(numTotalHits / 2500.0) * 0.475 : 0.0);
|
||||
|
||||
// Longer maps are worth more
|
||||
value *= lengthBonus;
|
||||
|
||||
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||
value *= Math.Pow(0.97, misses);
|
||||
|
||||
// Combo scaling
|
||||
@@ -80,17 +76,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
}
|
||||
|
||||
if (mods.Any(m => m is ModFlashlight))
|
||||
// Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
|
||||
value *= 1.35 * lengthBonus;
|
||||
|
||||
// Scale the aim value with accuracy _slightly_
|
||||
value *= Math.Pow(accuracy(), 5.5);
|
||||
|
||||
// Custom multipliers for NoFail. SpunOut is not applicable.
|
||||
if (mods.Any(m => m is ModNoFail))
|
||||
value *= 0.90;
|
||||
|
||||
return value;
|
||||
return new CatchPerformanceAttributes
|
||||
{
|
||||
Total = value
|
||||
};
|
||||
}
|
||||
|
||||
private double accuracy() => totalHits() == 0 ? 0 : Math.Clamp((double)totalSuccessfulHits() / totalHits(), 0, 1);
|
||||
|
||||
@@ -52,16 +52,25 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HandleFlip(Direction direction)
|
||||
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
|
||||
{
|
||||
if (SelectedItems.Count == 0)
|
||||
return false;
|
||||
|
||||
// This could be implemented in the future if there's a requirement for it.
|
||||
if (direction == Direction.Vertical)
|
||||
return false;
|
||||
|
||||
var selectionRange = CatchHitObjectUtils.GetPositionRange(SelectedItems);
|
||||
|
||||
bool changed = false;
|
||||
|
||||
EditorBeatmap.PerformOnSelection(h =>
|
||||
{
|
||||
if (h is CatchHitObject catchObject)
|
||||
changed |= handleFlip(selectionRange, catchObject);
|
||||
changed |= handleFlip(selectionRange, catchObject, flipOverOrigin);
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -116,7 +125,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return Math.Clamp(deltaX, lowerBound, upperBound);
|
||||
}
|
||||
|
||||
private bool handleFlip(PositionRange selectionRange, CatchHitObject hitObject)
|
||||
private bool handleFlip(PositionRange selectionRange, CatchHitObject hitObject, bool flipOverOrigin)
|
||||
{
|
||||
switch (hitObject)
|
||||
{
|
||||
@@ -124,7 +133,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return false;
|
||||
|
||||
case JuiceStream juiceStream:
|
||||
juiceStream.OriginalX = selectionRange.GetFlippedPosition(juiceStream.OriginalX);
|
||||
juiceStream.OriginalX = getFlippedPosition(juiceStream.OriginalX);
|
||||
|
||||
foreach (var point in juiceStream.Path.ControlPoints)
|
||||
point.Position *= new Vector2(-1, 1);
|
||||
@@ -133,9 +142,11 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return true;
|
||||
|
||||
default:
|
||||
hitObject.OriginalX = selectionRange.GetFlippedPosition(hitObject.OriginalX);
|
||||
hitObject.OriginalX = getFlippedPosition(hitObject.OriginalX);
|
||||
return true;
|
||||
}
|
||||
|
||||
float getFlippedPosition(float original) => flipOverOrigin ? CatchPlayfield.WIDTH - original : selectionRange.GetFlippedPosition(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+614
-307
File diff suppressed because it is too large
Load Diff
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 369,
|
||||
"Objects": [{
|
||||
"StartTime": 369,
|
||||
"Position": 0,
|
||||
"HyperDash": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 450,
|
||||
"Objects": [{
|
||||
"StartTime": 450,
|
||||
"Position": 512,
|
||||
"HyperDash": false
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
StackLeniency: 0.7
|
||||
Mode: 2
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:6
|
||||
CircleSize:4
|
||||
OverallDifficulty:9.6
|
||||
ApproachRate:9.6
|
||||
SliderMultiplier:1.9
|
||||
SliderTickRate:1
|
||||
|
||||
[TimingPoints]
|
||||
2169,266.666666666667,4,2,1,70,1,0
|
||||
|
||||
|
||||
[HitObjects]
|
||||
0,192,369,1,0,0:0:0:0:
|
||||
512,192,450,1,0,0:0:0:0:
|
||||
+72
-36
@@ -3,147 +3,183 @@
|
||||
"StartTime": 369,
|
||||
"Objects": [{
|
||||
"StartTime": 369,
|
||||
"Position": 177
|
||||
"Position": 177,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 450,
|
||||
"Position": 216.539276
|
||||
"Position": 216.539276,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 532,
|
||||
"Position": 256.5667
|
||||
"Position": 256.5667,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 614,
|
||||
"Position": 296.594116
|
||||
"Position": 296.594116,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 696,
|
||||
"Position": 336.621521
|
||||
"Position": 336.621521,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 778,
|
||||
"Position": 376.99762
|
||||
"Position": 376.99762,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 860,
|
||||
"Position": 337.318878
|
||||
"Position": 337.318878,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 942,
|
||||
"Position": 297.291443
|
||||
"Position": 297.291443,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1024,
|
||||
"Position": 257.264038
|
||||
"Position": 257.264038,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1106,
|
||||
"Position": 217.2366
|
||||
"Position": 217.2366,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1188,
|
||||
"Position": 177
|
||||
"Position": 177,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1270,
|
||||
"Position": 216.818192
|
||||
"Position": 216.818192,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1352,
|
||||
"Position": 256.8456
|
||||
"Position": 256.8456,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1434,
|
||||
"Position": 296.873047
|
||||
"Position": 296.873047,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1516,
|
||||
"Position": 336.900452
|
||||
"Position": 336.900452,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1598,
|
||||
"Position": 376.99762
|
||||
"Position": 376.99762,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1680,
|
||||
"Position": 337.039948
|
||||
"Position": 337.039948,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1762,
|
||||
"Position": 297.0125
|
||||
"Position": 297.0125,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1844,
|
||||
"Position": 256.9851
|
||||
"Position": 256.9851,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1926,
|
||||
"Position": 216.957672
|
||||
"Position": 216.957672,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2008,
|
||||
"Position": 177
|
||||
"Position": 177,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2090,
|
||||
"Position": 217.097137
|
||||
"Position": 217.097137,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2172,
|
||||
"Position": 257.124573
|
||||
"Position": 257.124573,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2254,
|
||||
"Position": 297.152
|
||||
"Position": 297.152,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2336,
|
||||
"Position": 337.179443
|
||||
"Position": 337.179443,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2418,
|
||||
"Position": 376.99762
|
||||
"Position": 376.99762,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2500,
|
||||
"Position": 336.760956
|
||||
"Position": 336.760956,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2582,
|
||||
"Position": 296.733643
|
||||
"Position": 296.733643,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2664,
|
||||
"Position": 256.7062
|
||||
"Position": 256.7062,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2746,
|
||||
"Position": 216.678772
|
||||
"Position": 216.678772,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2828,
|
||||
"Position": 177
|
||||
"Position": 177,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2909,
|
||||
"Position": 216.887909
|
||||
"Position": 216.887909,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2991,
|
||||
"Position": 256.915344
|
||||
"Position": 256.915344,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 3073,
|
||||
"Position": 296.942749
|
||||
"Position": 296.942749,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 3155,
|
||||
"Position": 336.970184
|
||||
"Position": 336.970184,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 3237,
|
||||
"Position": 376.99762
|
||||
"Position": 376.99762,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
+34
-17
@@ -3,71 +3,88 @@
|
||||
"StartTime": 369,
|
||||
"Objects": [{
|
||||
"StartTime": 369,
|
||||
"Position": 65
|
||||
"Position": 65,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 450,
|
||||
"Position": 482
|
||||
"Position": 482,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 532,
|
||||
"Position": 164
|
||||
"Position": 164,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 614,
|
||||
"Position": 315
|
||||
"Position": 315,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 696,
|
||||
"Position": 145
|
||||
"Position": 145,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 778,
|
||||
"Position": 159
|
||||
"Position": 159,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 860,
|
||||
"Position": 310
|
||||
"Position": 310,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 942,
|
||||
"Position": 441
|
||||
"Position": 441,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1024,
|
||||
"Position": 428
|
||||
"Position": 428,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1106,
|
||||
"Position": 243
|
||||
"Position": 243,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1188,
|
||||
"Position": 422
|
||||
"Position": 422,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1270,
|
||||
"Position": 481
|
||||
"Position": 481,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1352,
|
||||
"Position": 104
|
||||
"Position": 104,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1434,
|
||||
"Position": 473
|
||||
"Position": 473,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1516,
|
||||
"Position": 135
|
||||
"Position": 135,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1598,
|
||||
"Position": 360
|
||||
"Position": 360,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 1680,
|
||||
"Position": 123
|
||||
"Position": 123,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
+66
-33
@@ -3,231 +3,264 @@
|
||||
"StartTime": 369,
|
||||
"Objects": [{
|
||||
"StartTime": 369,
|
||||
"Position": 258
|
||||
"Position": 258,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 450,
|
||||
"Objects": [{
|
||||
"StartTime": 450,
|
||||
"Position": 254
|
||||
"Position": 254,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 532,
|
||||
"Objects": [{
|
||||
"StartTime": 532,
|
||||
"Position": 241
|
||||
"Position": 241,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 614,
|
||||
"Objects": [{
|
||||
"StartTime": 614,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 696,
|
||||
"Objects": [{
|
||||
"StartTime": 696,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 778,
|
||||
"Objects": [{
|
||||
"StartTime": 778,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 860,
|
||||
"Objects": [{
|
||||
"StartTime": 860,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 942,
|
||||
"Objects": [{
|
||||
"StartTime": 942,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1024,
|
||||
"Objects": [{
|
||||
"StartTime": 1024,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1106,
|
||||
"Objects": [{
|
||||
"StartTime": 1106,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1188,
|
||||
"Objects": [{
|
||||
"StartTime": 1188,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1270,
|
||||
"Objects": [{
|
||||
"StartTime": 1270,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1352,
|
||||
"Objects": [{
|
||||
"StartTime": 1352,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1434,
|
||||
"Objects": [{
|
||||
"StartTime": 1434,
|
||||
"Position": 258
|
||||
"Position": 258,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1516,
|
||||
"Objects": [{
|
||||
"StartTime": 1516,
|
||||
"Position": 253
|
||||
"Position": 253,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1598,
|
||||
"Objects": [{
|
||||
"StartTime": 1598,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1680,
|
||||
"Objects": [{
|
||||
"StartTime": 1680,
|
||||
"Position": 260
|
||||
"Position": 260,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1762,
|
||||
"Objects": [{
|
||||
"StartTime": 1762,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1844,
|
||||
"Objects": [{
|
||||
"StartTime": 1844,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 1926,
|
||||
"Objects": [{
|
||||
"StartTime": 1926,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2008,
|
||||
"Objects": [{
|
||||
"StartTime": 2008,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2090,
|
||||
"Objects": [{
|
||||
"StartTime": 2090,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2172,
|
||||
"Objects": [{
|
||||
"StartTime": 2172,
|
||||
"Position": 243
|
||||
"Position": 243,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2254,
|
||||
"Objects": [{
|
||||
"StartTime": 2254,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2336,
|
||||
"Objects": [{
|
||||
"StartTime": 2336,
|
||||
"Position": 278
|
||||
"Position": 278,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2418,
|
||||
"Objects": [{
|
||||
"StartTime": 2418,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2500,
|
||||
"Objects": [{
|
||||
"StartTime": 2500,
|
||||
"Position": 258
|
||||
"Position": 258,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2582,
|
||||
"Objects": [{
|
||||
"StartTime": 2582,
|
||||
"Position": 256
|
||||
"Position": 256,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2664,
|
||||
"Objects": [{
|
||||
"StartTime": 2664,
|
||||
"Position": 242
|
||||
"Position": 242,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2746,
|
||||
"Objects": [{
|
||||
"StartTime": 2746,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2828,
|
||||
"Objects": [{
|
||||
"StartTime": 2828,
|
||||
"Position": 238
|
||||
"Position": 238,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2909,
|
||||
"Objects": [{
|
||||
"StartTime": 2909,
|
||||
"Position": 271
|
||||
"Position": 271,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2991,
|
||||
"Objects": [{
|
||||
"StartTime": 2991,
|
||||
"Position": 254
|
||||
"Position": 254,
|
||||
"HyperDash": false
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
+4
-2
@@ -3,14 +3,16 @@
|
||||
"StartTime": 3368,
|
||||
"Objects": [{
|
||||
"StartTime": 3368,
|
||||
"Position": 374
|
||||
"Position": 374,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 3501,
|
||||
"Objects": [{
|
||||
"StartTime": 3501,
|
||||
"Position": 446
|
||||
"Position": 446,
|
||||
"HyperDash": false
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1 +1,71 @@
|
||||
{"Mappings":[{"StartTime":19184.0,"Objects":[{"StartTime":19184.0,"Position":320.0},{"StartTime":19263.0,"Position":311.730255},{"StartTime":19343.0,"Position":324.6205},{"StartTime":19423.0,"Position":343.0907},{"StartTime":19503.0,"Position":372.2917},{"StartTime":19582.0,"Position":385.194733},{"StartTime":19662.0,"Position":379.0426},{"StartTime":19742.0,"Position":385.1066},{"StartTime":19822.0,"Position":391.624664},{"StartTime":19919.0,"Position":386.27832},{"StartTime":20016.0,"Position":380.117035},{"StartTime":20113.0,"Position":381.664154},{"StartTime":20247.0,"Position":370.872864}]}]}
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 19184,
|
||||
"Objects": [{
|
||||
"StartTime": 19184,
|
||||
"Position": 320,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19263,
|
||||
"Position": 311.730255,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19343,
|
||||
"Position": 324.6205,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19423,
|
||||
"Position": 343.0907,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19503,
|
||||
"Position": 372.2917,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19582,
|
||||
"Position": 385.194733,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19662,
|
||||
"Position": 379.0426,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19742,
|
||||
"Position": 385.1066,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19822,
|
||||
"Position": 391.624664,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19919,
|
||||
"Position": 386.27832,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 20016,
|
||||
"Position": 380.117035,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 20113,
|
||||
"Position": 381.664154,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 20247,
|
||||
"Position": 370.872864,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
+20
-10
@@ -3,18 +3,21 @@
|
||||
"StartTime": 2589,
|
||||
"Objects": [{
|
||||
"StartTime": 2589,
|
||||
"Position": 256
|
||||
"Position": 256,
|
||||
"HyperDash": false
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 2915,
|
||||
"Objects": [{
|
||||
"StartTime": 2915,
|
||||
"Position": 65
|
||||
"Position": 65,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 2916,
|
||||
"Position": 482
|
||||
"Position": 482,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -22,11 +25,13 @@
|
||||
"StartTime": 3078,
|
||||
"Objects": [{
|
||||
"StartTime": 3078,
|
||||
"Position": 164
|
||||
"Position": 164,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 3079,
|
||||
"Position": 315
|
||||
"Position": 315,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -34,11 +39,13 @@
|
||||
"StartTime": 3241,
|
||||
"Objects": [{
|
||||
"StartTime": 3241,
|
||||
"Position": 145
|
||||
"Position": 145,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 3242,
|
||||
"Position": 159
|
||||
"Position": 159,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -46,11 +53,13 @@
|
||||
"StartTime": 3404,
|
||||
"Objects": [{
|
||||
"StartTime": 3404,
|
||||
"Position": 310
|
||||
"Position": 310,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 3405,
|
||||
"Position": 441
|
||||
"Position": 441,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -58,7 +67,8 @@
|
||||
"StartTime": 5197,
|
||||
"Objects": [{
|
||||
"StartTime": 5197,
|
||||
"Position": 256
|
||||
"Position": 256,
|
||||
"HyperDash": false
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
+34
-17
@@ -3,71 +3,88 @@
|
||||
"StartTime": 18500,
|
||||
"Objects": [{
|
||||
"StartTime": 18500,
|
||||
"Position": 65
|
||||
"Position": 65,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18559,
|
||||
"Position": 482
|
||||
"Position": 482,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18618,
|
||||
"Position": 164
|
||||
"Position": 164,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18678,
|
||||
"Position": 315
|
||||
"Position": 315,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18737,
|
||||
"Position": 145
|
||||
"Position": 145,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18796,
|
||||
"Position": 159
|
||||
"Position": 159,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18856,
|
||||
"Position": 310
|
||||
"Position": 310,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18915,
|
||||
"Position": 441
|
||||
"Position": 441,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 18975,
|
||||
"Position": 428
|
||||
"Position": 428,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19034,
|
||||
"Position": 243
|
||||
"Position": 243,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19093,
|
||||
"Position": 422
|
||||
"Position": 422,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19153,
|
||||
"Position": 481
|
||||
"Position": 481,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19212,
|
||||
"Position": 104
|
||||
"Position": 104,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19271,
|
||||
"Position": 473
|
||||
"Position": 473,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19331,
|
||||
"Position": 135
|
||||
"Position": 135,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19390,
|
||||
"Position": 360
|
||||
"Position": 360,
|
||||
"HyperDash": false
|
||||
},
|
||||
{
|
||||
"StartTime": 19450,
|
||||
"Position": 123
|
||||
"Position": 123,
|
||||
"HyperDash": false
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
@@ -90,9 +90,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
.ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
|
||||
.FadeOut(duration * 2);
|
||||
|
||||
const float angle_variangle = 15; // should be less than 45
|
||||
directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 4);
|
||||
directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 5);
|
||||
const float angle_variance = 15; // should be less than 45
|
||||
directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variance, angle_variance, randomSeed, 4);
|
||||
directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variance, angle_variance, randomSeed, 5);
|
||||
|
||||
this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out);
|
||||
}
|
||||
|
||||
@@ -210,6 +210,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
catchResult.CatcherAnimationState = CurrentState;
|
||||
catchResult.CatcherHyperDash = HyperDashing;
|
||||
|
||||
// Ignore JuiceStreams and BananaShowers
|
||||
if (!(drawableObject is DrawablePalpableCatchHitObject palpableObject)) return;
|
||||
|
||||
var hitObject = palpableObject.HitObject;
|
||||
@@ -244,6 +245,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
CurrentState = hitObject.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle;
|
||||
else if (!(hitObject is Banana))
|
||||
CurrentState = CatcherAnimationState.Fail;
|
||||
|
||||
if (palpableObject.HitObject.LastInCombo)
|
||||
{
|
||||
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
||||
Explode();
|
||||
else
|
||||
Drop();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||
|
||||
@@ -6,11 +6,9 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
@@ -72,18 +70,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||
{
|
||||
Catcher.OnNewResult(hitObject, result);
|
||||
|
||||
if (!result.Type.IsScorable())
|
||||
return;
|
||||
|
||||
if (hitObject.HitObject.LastInCombo)
|
||||
{
|
||||
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
||||
Catcher.Explode();
|
||||
else
|
||||
Catcher.Drop();
|
||||
}
|
||||
|
||||
comboDisplay.OnNewResult(hitObject, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using osu.Framework.Android;
|
||||
using osu.Game.Tests;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Android
|
||||
{
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
|
||||
[Activity(ConfigurationChanges = DEFAULT_CONFIG_CHANGES, Exported = true, LaunchMode = DEFAULT_LAUNCH_MODE, MainLauncher = true)]
|
||||
public class MainActivity : AndroidGameActivity
|
||||
{
|
||||
protected override Framework.Game CreateGame() => new OsuTestBrowser();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.iOS;
|
||||
using UIKit;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.iOS
|
||||
@@ -9,7 +10,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,7 @@
|
||||
</array>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/AppIcon.appiconset</string>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
@@ -24,9 +25,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetConfigCache configCache)
|
||||
private void load()
|
||||
{
|
||||
var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
||||
var config = (ManiaRulesetConfigManager)RulesetConfigs.GetConfigFor(Ruleset.Value.CreateInstance()).AsNonNull();
|
||||
config.BindWith(ManiaRulesetSetting.ScrollDirection, direction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Screens.Edit;
|
||||
@@ -55,13 +56,13 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
[Test]
|
||||
public void TestDefaultSkin()
|
||||
{
|
||||
AddStep("set default skin", () => skins.CurrentSkinInfo.Value = SkinInfo.Default);
|
||||
AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkin.CreateInfo().ToLiveUnmanaged());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLegacySkin()
|
||||
{
|
||||
AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.Info);
|
||||
AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(10000)]
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
public void TestClockRateAdjusted(double expected, string name)
|
||||
=> Test(expected, name, new ManiaModDoubleTime());
|
||||
|
||||
protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(new ManiaRuleset(), beatmap);
|
||||
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new ManiaDifficultyCalculator(new ManiaRuleset().RulesetInfo, beatmap);
|
||||
|
||||
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||
}
|
||||
|
||||
@@ -4,11 +4,14 @@ Version: 2.5
|
||||
[Mania]
|
||||
Keys: 4
|
||||
ColumnLineWidth: 3,1,3,1,1
|
||||
Hit0: mania/hit0
|
||||
Hit50: mania/hit50
|
||||
Hit100: mania/hit100
|
||||
Hit200: mania/hit200
|
||||
Hit300: mania/hit300
|
||||
Hit300g: mania/hit300g
|
||||
// some skins found in the wild had configuration keys where the @2x suffix was included in the values.
|
||||
// the expected compatibility behaviour is that the presence of the @2x suffix shouldn't change anything
|
||||
// if @2x assets are present.
|
||||
Hit0: mania/hit0@2x
|
||||
Hit50: mania/hit50@2x
|
||||
Hit100: mania/hit100@2x
|
||||
Hit200: mania/hit200@2x
|
||||
Hit300: mania/hit300@2x
|
||||
Hit300g: mania/hit300g@2x
|
||||
StageLeft: mania/stage-left
|
||||
StageRight: mania/stage-right
|
||||
@@ -5,8 +5,10 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Mania.Skinning.Legacy;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@@ -23,15 +25,24 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
if (hitWindows.IsHitResultAllowed(result))
|
||||
{
|
||||
AddStep("Show " + result.GetDescription(), () => SetContents(_ =>
|
||||
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
|
||||
{
|
||||
Type = result
|
||||
}, null)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}));
|
||||
AddStep("Show " + result.GetDescription(), () =>
|
||||
{
|
||||
SetContents(_ =>
|
||||
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
|
||||
{
|
||||
Type = result
|
||||
}, null)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
// for test purposes, undo the Y adjustment related to the `ScorePosition` legacy positioning config value
|
||||
// (see `LegacyManiaJudgementPiece.load()`).
|
||||
// this prevents the judgements showing somewhere below or above the bounding box of the judgement.
|
||||
foreach (var legacyPiece in this.ChildrenOfType<LegacyManiaJudgementPiece>())
|
||||
legacyPiece.Y = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,13 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
|
||||
public TestSceneHitExplosion()
|
||||
{
|
||||
int runcount = 0;
|
||||
int runCount = 0;
|
||||
|
||||
AddRepeatStep("explode", () =>
|
||||
{
|
||||
runcount++;
|
||||
runCount++;
|
||||
|
||||
if (runcount % 15 > 12)
|
||||
if (runCount % 15 > 12)
|
||||
return;
|
||||
|
||||
int poolIndex = 0;
|
||||
@@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
c.Add(hitExplosionPools[poolIndex].Get(e =>
|
||||
{
|
||||
e.Apply(new JudgementResult(new HitObject(), runcount % 6 == 0 ? new HoldNoteTickJudgement() : new ManiaJudgement()));
|
||||
e.Apply(new JudgementResult(new HitObject(), runCount % 6 == 0 ? new HoldNoteTickJudgement() : new ManiaJudgement()));
|
||||
|
||||
e.Anchor = Anchor.Centre;
|
||||
e.Origin = Anchor.Centre;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
@@ -14,6 +13,7 @@ using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
@@ -24,9 +24,6 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
[TestFixture]
|
||||
public class TestSceneTimingBasedNoteColouring : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private RulesetConfigCache configCache { get; set; }
|
||||
|
||||
private Bindable<bool> configTimingBasedNoteColouring;
|
||||
|
||||
private ManualClock clock;
|
||||
@@ -48,7 +45,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
});
|
||||
AddStep("retrieve config bindable", () =>
|
||||
{
|
||||
var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
||||
var config = (ManiaRulesetConfigManager)RulesetConfigs.GetConfigFor(Ruleset.Value.CreateInstance()).AsNonNull();
|
||||
configTimingBasedNoteColouring = config.GetBindable<bool>(ManiaRulesetSetting.TimingBasedNoteColouring);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
public override IEnumerable<BeatmapStatistic> GetStatistics()
|
||||
{
|
||||
int notes = HitObjects.Count(s => s is Note);
|
||||
int holdnotes = HitObjects.Count(s => s is HoldNote);
|
||||
int holdNotes = HitObjects.Count(s => s is HoldNote);
|
||||
|
||||
return new[]
|
||||
{
|
||||
@@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
{
|
||||
Name = @"Hold Note Count",
|
||||
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders),
|
||||
Content = holdnotes.ToString(),
|
||||
Content = holdNotes.ToString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
{
|
||||
public class ManiaDifficultyAttributes : DifficultyAttributes
|
||||
{
|
||||
[JsonProperty("great_hit_window")]
|
||||
public double GreatHitWindow { get; set; }
|
||||
|
||||
[JsonProperty("score_multiplier")]
|
||||
public double ScoreMultiplier { get; set; }
|
||||
|
||||
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||
{
|
||||
foreach (var v in base.ToDatabaseAttributes())
|
||||
yield return v;
|
||||
|
||||
// Todo: osu!mania doesn't output MaxCombo attribute for some reason.
|
||||
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
||||
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||
yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier);
|
||||
}
|
||||
|
||||
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
|
||||
{
|
||||
base.FromDatabaseAttributes(values);
|
||||
|
||||
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
||||
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||
ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Skills;
|
||||
@@ -28,17 +29,17 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
private readonly bool isForCurrentRuleset;
|
||||
private readonly double originalOverallDifficulty;
|
||||
|
||||
public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
public ManiaDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo);
|
||||
originalOverallDifficulty = beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty;
|
||||
isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.MatchesOnlineID(ruleset);
|
||||
originalOverallDifficulty = beatmap.BeatmapInfo.Difficulty.OverallDifficulty;
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
if (beatmap.HitObjects.Count == 0)
|
||||
return new ManiaDifficultyAttributes { Mods = mods, Skills = skills };
|
||||
return new ManiaDifficultyAttributes { Mods = mods };
|
||||
|
||||
HitWindows hitWindows = new ManiaHitWindows();
|
||||
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
|
||||
@@ -50,7 +51,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
GreatHitWindow = Math.Ceiling(getHitWindow300(mods) / clockRate),
|
||||
ScoreMultiplier = getScoreMultiplier(mods),
|
||||
MaxCombo = beatmap.HitObjects.Sum(h => h is HoldNote ? 2 : 1),
|
||||
Skills = skills
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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.Game.Rulesets.Difficulty;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
{
|
||||
public class ManiaPerformanceAttributes : PerformanceAttributes
|
||||
{
|
||||
[JsonProperty("difficulty")]
|
||||
public double Difficulty { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty("scaled_score")]
|
||||
public double ScaledScore { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
{
|
||||
}
|
||||
|
||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||
public override PerformanceAttributes Calculate()
|
||||
{
|
||||
mods = Score.Mods;
|
||||
scaledScore = Score.TotalScore;
|
||||
@@ -61,48 +61,46 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
if (mods.Any(m => m is ModEasy))
|
||||
multiplier *= 0.5;
|
||||
|
||||
double strainValue = computeStrainValue();
|
||||
double accValue = computeAccuracyValue(strainValue);
|
||||
double difficultyValue = computeDifficultyValue();
|
||||
double accValue = computeAccuracyValue(difficultyValue);
|
||||
double totalValue =
|
||||
Math.Pow(
|
||||
Math.Pow(strainValue, 1.1) +
|
||||
Math.Pow(difficultyValue, 1.1) +
|
||||
Math.Pow(accValue, 1.1), 1.0 / 1.1
|
||||
) * multiplier;
|
||||
|
||||
if (categoryDifficulty != null)
|
||||
return new ManiaPerformanceAttributes
|
||||
{
|
||||
categoryDifficulty["Strain"] = strainValue;
|
||||
categoryDifficulty["Accuracy"] = accValue;
|
||||
}
|
||||
|
||||
return totalValue;
|
||||
Difficulty = difficultyValue,
|
||||
Accuracy = accValue,
|
||||
ScaledScore = scaledScore,
|
||||
Total = totalValue
|
||||
};
|
||||
}
|
||||
|
||||
private double computeStrainValue()
|
||||
private double computeDifficultyValue()
|
||||
{
|
||||
// Obtain strain difficulty
|
||||
double strainValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
|
||||
double difficultyValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
|
||||
|
||||
// Longer maps are worth more
|
||||
strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
||||
difficultyValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
||||
|
||||
if (scaledScore <= 500000)
|
||||
strainValue = 0;
|
||||
difficultyValue = 0;
|
||||
else if (scaledScore <= 600000)
|
||||
strainValue *= (scaledScore - 500000) / 100000 * 0.3;
|
||||
difficultyValue *= (scaledScore - 500000) / 100000 * 0.3;
|
||||
else if (scaledScore <= 700000)
|
||||
strainValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
|
||||
difficultyValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
|
||||
else if (scaledScore <= 800000)
|
||||
strainValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
|
||||
difficultyValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
|
||||
else if (scaledScore <= 900000)
|
||||
strainValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
|
||||
difficultyValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
|
||||
else
|
||||
strainValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
|
||||
difficultyValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
|
||||
|
||||
return strainValue;
|
||||
return difficultyValue;
|
||||
}
|
||||
|
||||
private double computeAccuracyValue(double strainValue)
|
||||
private double computeAccuracyValue(double difficultyValue)
|
||||
{
|
||||
if (Attributes.GreatHitWindow <= 0)
|
||||
return 0;
|
||||
@@ -110,12 +108,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
// Lots of arbitrary values from testing.
|
||||
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||
double accuracyValue = Math.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667)
|
||||
* strainValue
|
||||
* difficultyValue
|
||||
* Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
|
||||
|
||||
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||
// accuracyValue *= Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
||||
|
||||
return accuracyValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
@@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
@@ -46,12 +45,6 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
[Resolved]
|
||||
private EditorBeatmap beatmap { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IScrollingInfo scrollingInfo { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private Bindable<WorkingBeatmap> working { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user