mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 21:52:55 +08:00
Merge branch 'master' into master
This commit is contained in:
commit
a84fd2e20c
1
.idea/.idea.osu.Android/.idea/.name
Normal file
1
.idea/.idea.osu.Android/.idea/.name
Normal file
@ -0,0 +1 @@
|
|||||||
|
osu.Android
|
8
.idea/.idea.osu.Android/.idea/indexLayout.xml
Normal file
8
.idea/.idea.osu.Android/.idea/indexLayout.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/.idea.osu.Android/.idea/misc.xml
Normal file
6
.idea/.idea.osu.Android/.idea/misc.xml
Normal file
@ -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>
|
6
.idea/.idea.osu.Android/.idea/projectSettingsUpdater.xml
Normal file
6
.idea/.idea.osu.Android/.idea/projectSettingsUpdater.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RiderProjectSettingsUpdater">
|
||||||
|
<option name="vcsConfiguration" value="2" />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/.idea.osu.Android/.idea/vcs.xml
Normal file
6
.idea/.idea.osu.Android/.idea/vcs.xml
Normal file
@ -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>
|
6
.idea/.idea.osu/.idea/misc.xml
Normal file
6
.idea/.idea.osu/.idea/misc.xml
Normal file
@ -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>
|
@ -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,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="RiderProjectSettingsUpdater">
|
<component name="RiderProjectSettingsUpdater">
|
||||||
<option name="vcsConfiguration" value="1" />
|
<option name="vcsConfiguration" value="2" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -13,3 +13,5 @@ M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.H
|
|||||||
M:Realms.IRealmCollection`1.SubscribeForNotifications`1(Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IRealmCollection<T>,NotificationCallbackDelegate<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.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: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.
|
||||||
|
@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi
|
|||||||
|
|
||||||
**Latest build:**
|
**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.
|
- 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.
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
|
|||||||
public class TestSceneOsuGame : OsuTestScene
|
public class TestSceneOsuGame : OsuTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
|
||||||
{
|
{
|
||||||
host.Run(new OsuTestBrowser());
|
host.Run(new OsuTestBrowser());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
public class TestSceneOsuGame : OsuTestScene
|
public class TestSceneOsuGame : OsuTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
|
||||||
{
|
{
|
||||||
host.Run(new OsuTestBrowser());
|
host.Run(new OsuTestBrowser());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
|
|||||||
public class TestSceneOsuGame : OsuTestScene
|
public class TestSceneOsuGame : OsuTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
|
||||||
{
|
{
|
||||||
host.Run(new OsuTestBrowser());
|
host.Run(new OsuTestBrowser());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
public class TestSceneOsuGame : OsuTestScene
|
public class TestSceneOsuGame : OsuTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
|
||||||
{
|
{
|
||||||
host.Run(new OsuTestBrowser());
|
host.Run(new OsuTestBrowser());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Pippidon.UI
|
|||||||
private PippidonCharacter pippidon;
|
private PippidonCharacter pippidon;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load()
|
||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -51,11 +51,11 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1215.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1227.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.128.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- 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.7.1" />
|
<PackageReference Include="Realm" Version="10.8.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -10,14 +10,11 @@ using System.Runtime.Versioning;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using osu.Desktop.Security;
|
using osu.Desktop.Security;
|
||||||
using osu.Desktop.Overlays;
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game;
|
using osu.Game;
|
||||||
using osu.Desktop.Updater;
|
using osu.Desktop.Updater;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Screens;
|
|
||||||
using osu.Game.Screens.Menu;
|
|
||||||
using osu.Game.Updater;
|
using osu.Game.Updater;
|
||||||
using osu.Desktop.Windows;
|
using osu.Desktop.Windows;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
@ -27,13 +24,9 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
internal class OsuGameDesktop : OsuGame
|
internal class OsuGameDesktop : OsuGame
|
||||||
{
|
{
|
||||||
private readonly bool noVersionOverlay;
|
|
||||||
private VersionManager versionManager;
|
|
||||||
|
|
||||||
public OsuGameDesktop(string[] args = null)
|
public OsuGameDesktop(string[] args = null)
|
||||||
: base(args)
|
: base(args)
|
||||||
{
|
{
|
||||||
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override StableStorage GetStorageForStableInstall()
|
public override StableStorage GetStorageForStableInstall()
|
||||||
@ -114,9 +107,6 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
if (!noVersionOverlay)
|
|
||||||
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
|
|
||||||
|
|
||||||
LoadComponentAsync(new DiscordRichPresence(), Add);
|
LoadComponentAsync(new DiscordRichPresence(), Add);
|
||||||
|
|
||||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||||
@ -125,23 +115,6 @@ namespace osu.Desktop
|
|||||||
LoadComponentAsync(new ElevatedPrivilegesChecker(), Add);
|
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)
|
public override void SetHost(GameHost host)
|
||||||
{
|
{
|
||||||
base.SetHost(host);
|
base.SetHost(host);
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Desktop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(gameName, true))
|
using (DesktopGameHost host = Host.GetSuitableDesktopHost(gameName, new HostOptions { BindIPC = true }))
|
||||||
{
|
{
|
||||||
host.ExceptionThrown += handleException;
|
host.ExceptionThrown += handleException;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Desktop.Security
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, NotificationOverlay notificationOverlay)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.ShieldAlt;
|
Icon = FontAwesome.Solid.ShieldAlt;
|
||||||
IconBackground.Colour = colours.YellowDark;
|
IconBackground.Colour = colours.YellowDark;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// ReSharper disable IdentifierTypo
|
||||||
|
|
||||||
namespace osu.Desktop.Windows
|
namespace osu.Desktop.Windows
|
||||||
{
|
{
|
||||||
internal class WindowsKey
|
internal class WindowsKey
|
||||||
|
141
osu.Game.Benchmarks/BenchmarkRealmReads.cs
Normal file
141
osu.Game.Benchmarks/BenchmarkRealmReads.cs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
|
namespace osu.Game.Benchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkRealmReads : BenchmarkTest
|
||||||
|
{
|
||||||
|
private TemporaryNativeStorage storage;
|
||||||
|
private RealmAccess realm;
|
||||||
|
private UpdateThread updateThread;
|
||||||
|
|
||||||
|
[Params(1, 100, 1000)]
|
||||||
|
public int ReadsPerFetch { get; set; }
|
||||||
|
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
storage = new TemporaryNativeStorage("realm-benchmark");
|
||||||
|
storage.DeleteDirectory(string.Empty);
|
||||||
|
|
||||||
|
realm = new RealmAccess(storage, "client");
|
||||||
|
|
||||||
|
realm.Run(r =>
|
||||||
|
{
|
||||||
|
realm.Write(c => c.Add(TestResources.CreateTestBeatmapSetInfo(rulesets: new[] { new OsuRuleset().RulesetInfo })));
|
||||||
|
});
|
||||||
|
|
||||||
|
updateThread = new UpdateThread(() => { }, null);
|
||||||
|
updateThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkDirectPropertyRead()
|
||||||
|
{
|
||||||
|
realm.Run(r =>
|
||||||
|
{
|
||||||
|
var beatmapSet = r.All<BeatmapSetInfo>().First();
|
||||||
|
|
||||||
|
for (int i = 0; i < ReadsPerFetch; i++)
|
||||||
|
{
|
||||||
|
string _ = beatmapSet.Beatmaps.First().Hash;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkDirectPropertyReadUpdateThread()
|
||||||
|
{
|
||||||
|
var done = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
updateThread.Scheduler.Add(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var beatmapSet = realm.Realm.All<BeatmapSetInfo>().First();
|
||||||
|
|
||||||
|
for (int i = 0; i < ReadsPerFetch; i++)
|
||||||
|
{
|
||||||
|
string _ = beatmapSet.Beatmaps.First().Hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
done.Set();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
done.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkRealmLivePropertyRead()
|
||||||
|
{
|
||||||
|
realm.Run(r =>
|
||||||
|
{
|
||||||
|
var beatmapSet = r.All<BeatmapSetInfo>().First().ToLive(realm);
|
||||||
|
|
||||||
|
for (int i = 0; i < ReadsPerFetch; i++)
|
||||||
|
{
|
||||||
|
string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkRealmLivePropertyReadUpdateThread()
|
||||||
|
{
|
||||||
|
var done = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
updateThread.Scheduler.Add(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var beatmapSet = realm.Realm.All<BeatmapSetInfo>().First().ToLive(realm);
|
||||||
|
|
||||||
|
for (int i = 0; i < ReadsPerFetch; i++)
|
||||||
|
{
|
||||||
|
string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
done.Set();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
done.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkDetachedPropertyRead()
|
||||||
|
{
|
||||||
|
realm.Run(r =>
|
||||||
|
{
|
||||||
|
var beatmapSet = r.All<BeatmapSetInfo>().First().Detach();
|
||||||
|
|
||||||
|
for (int i = 0; i < ReadsPerFetch; i++)
|
||||||
|
{
|
||||||
|
string _ = beatmapSet.Beatmaps.First().Hash;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[GlobalCleanup]
|
||||||
|
public void Cleanup()
|
||||||
|
{
|
||||||
|
realm?.Dispose();
|
||||||
|
storage?.Dispose();
|
||||||
|
updateThread?.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Timeout(10000)]
|
|
||||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||||
|
@ -29,7 +29,13 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
|
|||||||
|
|
||||||
protected CatchSelectionBlueprintTestScene()
|
protected CatchSelectionBlueprintTestScene()
|
||||||
{
|
{
|
||||||
EditorBeatmap = new EditorBeatmap(new CatchBeatmap()) { Difficulty = { CircleSize = 0 } };
|
EditorBeatmap = new EditorBeatmap(new CatchBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new CatchRuleset().RulesetInfo,
|
||||||
|
}
|
||||||
|
}) { Difficulty = { CircleSize = 0 } };
|
||||||
EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint
|
EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint
|
||||||
{
|
{
|
||||||
BeatLength = 100
|
BeatLength = 100
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
|
Difficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
|
||||||
Ruleset = ruleset
|
Ruleset = ruleset
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
|
Difficulty = new BeatmapDifficulty { CircleSize = 6 },
|
||||||
Ruleset = ruleset
|
Ruleset = ruleset
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
|
Difficulty = new BeatmapDifficulty { CircleSize = 6 },
|
||||||
Ruleset = ruleset
|
Ruleset = ruleset
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -35,12 +35,12 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
HitObjects = new List<HitObject> { new Fruit() },
|
HitObjects = new List<HitObject> { new Fruit() },
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
Difficulty = new BeatmapDifficulty(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
Artist = @"Unknown",
|
Artist = @"Unknown",
|
||||||
Title = @"You're breathtaking",
|
Title = @"You're breathtaking",
|
||||||
AuthorString = @"Everyone",
|
Author = { Username = @"Everyone" },
|
||||||
},
|
},
|
||||||
Ruleset = new CatchRuleset().RulesetInfo
|
Ruleset = new CatchRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
Ruleset = ruleset,
|
Ruleset = ruleset,
|
||||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.6f }
|
Difficulty = new BeatmapDifficulty { CircleSize = 3.6f }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 },
|
Difficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 },
|
||||||
Ruleset = ruleset
|
Ruleset = ruleset
|
||||||
},
|
},
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -15,9 +16,26 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
private const float default_flashlight_size = 350;
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
|
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||||
|
{
|
||||||
|
MinValue = 0.5f,
|
||||||
|
MaxValue = 1.5f,
|
||||||
|
Default = 1f,
|
||||||
|
Value = 1f,
|
||||||
|
Precision = 0.1f
|
||||||
|
};
|
||||||
|
|
||||||
public override Flashlight CreateFlashlight() => new CatchFlashlight(playfield);
|
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||||
|
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||||
|
{
|
||||||
|
Default = true,
|
||||||
|
Value = true
|
||||||
|
};
|
||||||
|
|
||||||
|
public override float DefaultFlashlightSize => 350;
|
||||||
|
|
||||||
|
protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield);
|
||||||
|
|
||||||
private CatchPlayfield playfield;
|
private CatchPlayfield playfield;
|
||||||
|
|
||||||
@ -31,10 +49,11 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
private readonly CatchPlayfield playfield;
|
private readonly CatchPlayfield playfield;
|
||||||
|
|
||||||
public CatchFlashlight(CatchPlayfield playfield)
|
public CatchFlashlight(CatchModFlashlight modFlashlight, CatchPlayfield playfield)
|
||||||
|
: base(modFlashlight)
|
||||||
{
|
{
|
||||||
this.playfield = playfield;
|
this.playfield = playfield;
|
||||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
FlashlightSize = new Vector2(0, GetSizeFor(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -44,19 +63,9 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
FlashlightPosition = playfield.CatcherArea.ToSpaceOfOtherDrawable(playfield.Catcher.DrawPosition, this);
|
FlashlightPosition = playfield.CatcherArea.ToSpaceOfOtherDrawable(playfield.Catcher.DrawPosition, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getSizeFor(int combo)
|
|
||||||
{
|
|
||||||
if (combo > 200)
|
|
||||||
return default_flashlight_size * 0.8f;
|
|
||||||
else if (combo > 100)
|
|
||||||
return default_flashlight_size * 0.9f;
|
|
||||||
else
|
|
||||||
return default_flashlight_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||||
{
|
{
|
||||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string FragmentShader => "CircularFlashlight";
|
protected override string FragmentShader => "CircularFlashlight";
|
||||||
|
@ -29,7 +29,13 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
|
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
|
||||||
|
|
||||||
[Cached(typeof(EditorBeatmap))]
|
[Cached(typeof(EditorBeatmap))]
|
||||||
private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition()));
|
private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition())
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new ManiaRuleset().RulesetInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private readonly ManiaBeatSnapGrid beatSnapGrid;
|
private readonly ManiaBeatSnapGrid beatSnapGrid;
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
{
|
{
|
||||||
AddStep("setup compose screen", () =>
|
AddStep("setup compose screen", () =>
|
||||||
{
|
{
|
||||||
var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }))
|
var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })
|
||||||
{
|
{
|
||||||
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
|
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
|
||||||
};
|
});
|
||||||
|
|
||||||
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
||||||
|
|
||||||
|
@ -203,10 +203,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }))
|
EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })
|
||||||
{
|
{
|
||||||
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }
|
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }
|
||||||
},
|
}),
|
||||||
Composer = new ManiaHitObjectComposer(new ManiaRuleset())
|
Composer = new ManiaHitObjectComposer(new ManiaRuleset())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Timeout(10000)]
|
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
@ -4,11 +4,14 @@ Version: 2.5
|
|||||||
[Mania]
|
[Mania]
|
||||||
Keys: 4
|
Keys: 4
|
||||||
ColumnLineWidth: 3,1,3,1,1
|
ColumnLineWidth: 3,1,3,1,1
|
||||||
Hit0: mania/hit0
|
// some skins found in the wild had configuration keys where the @2x suffix was included in the values.
|
||||||
Hit50: mania/hit50
|
// the expected compatibility behaviour is that the presence of the @2x suffix shouldn't change anything
|
||||||
Hit100: mania/hit100
|
// if @2x assets are present.
|
||||||
Hit200: mania/hit200
|
Hit0: mania/hit0@2x
|
||||||
Hit300: mania/hit300
|
Hit50: mania/hit50@2x
|
||||||
Hit300g: mania/hit300g
|
Hit100: mania/hit100@2x
|
||||||
|
Hit200: mania/hit200@2x
|
||||||
|
Hit300: mania/hit300@2x
|
||||||
|
Hit300g: mania/hit300g@2x
|
||||||
StageLeft: mania/stage-left
|
StageLeft: mania/stage-left
|
||||||
StageRight: mania/stage-right
|
StageRight: mania/stage-right
|
@ -5,8 +5,10 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning.Legacy;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -23,7 +25,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
if (hitWindows.IsHitResultAllowed(result))
|
if (hitWindows.IsHitResultAllowed(result))
|
||||||
{
|
{
|
||||||
AddStep("Show " + result.GetDescription(), () => SetContents(_ =>
|
AddStep("Show " + result.GetDescription(), () =>
|
||||||
|
{
|
||||||
|
SetContents(_ =>
|
||||||
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
|
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
|
||||||
{
|
{
|
||||||
Type = result
|
Type = result
|
||||||
@ -31,7 +35,14 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = 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;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
},
|
},
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
Difficulty = new BeatmapDifficulty
|
||||||
{
|
{
|
||||||
SliderTickRate = 4,
|
SliderTickRate = 4,
|
||||||
OverallDifficulty = 10,
|
OverallDifficulty = 10,
|
||||||
@ -306,7 +306,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
},
|
},
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = tick_rate },
|
Difficulty = new BeatmapDifficulty { SliderTickRate = tick_rate },
|
||||||
Ruleset = new ManiaRuleset().RulesetInfo
|
Ruleset = new ManiaRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -383,7 +383,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
},
|
},
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 4 },
|
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 },
|
||||||
Ruleset = new ManiaRuleset().RulesetInfo
|
Ruleset = new ManiaRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
public static int GetColumnCountForNonConvert(BeatmapInfo beatmapInfo)
|
public static int GetColumnCountForNonConvert(BeatmapInfo beatmapInfo)
|
||||||
{
|
{
|
||||||
double roundedCircleSize = Math.Round(beatmapInfo.BaseDifficulty.CircleSize);
|
double roundedCircleSize = Math.Round(beatmapInfo.Difficulty.CircleSize);
|
||||||
return (int)Math.Max(1, roundedCircleSize);
|
return (int)Math.Max(1, roundedCircleSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||||
@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public bool Matches(BeatmapInfo beatmapInfo)
|
public bool Matches(BeatmapInfo beatmapInfo)
|
||||||
{
|
{
|
||||||
return !keys.HasFilter || (beatmapInfo.RulesetID == new ManiaRuleset().LegacyID && keys.IsInRange(ManiaBeatmapConverter.GetColumnCountForNonConvert(beatmapInfo)));
|
return !keys.HasFilter || (beatmapInfo.Ruleset.OnlineID == new ManiaRuleset().LegacyID && keys.IsInRange(ManiaBeatmapConverter.GetColumnCountForNonConvert(beatmapInfo)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value)
|
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value)
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
|
||||||
|
|
||||||
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new DrainingHealthProcessor(drainStartTime, 0.5);
|
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new ManiaHealthProcessor(drainStartTime, 0.5);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -16,17 +17,35 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
||||||
|
|
||||||
private const float default_flashlight_size = 180;
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
|
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||||
|
{
|
||||||
|
MinValue = 0.5f,
|
||||||
|
MaxValue = 3f,
|
||||||
|
Default = 1f,
|
||||||
|
Value = 1f,
|
||||||
|
Precision = 0.1f
|
||||||
|
};
|
||||||
|
|
||||||
public override Flashlight CreateFlashlight() => new ManiaFlashlight();
|
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||||
|
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||||
|
{
|
||||||
|
Default = false,
|
||||||
|
Value = false
|
||||||
|
};
|
||||||
|
|
||||||
|
public override float DefaultFlashlightSize => 50;
|
||||||
|
|
||||||
|
protected override Flashlight CreateFlashlight() => new ManiaFlashlight(this);
|
||||||
|
|
||||||
private class ManiaFlashlight : Flashlight
|
private class ManiaFlashlight : Flashlight
|
||||||
{
|
{
|
||||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
||||||
|
|
||||||
public ManiaFlashlight()
|
public ManiaFlashlight(ManiaModFlashlight modFlashlight)
|
||||||
|
: base(modFlashlight)
|
||||||
{
|
{
|
||||||
FlashlightSize = new Vector2(0, default_flashlight_size);
|
FlashlightSize = new Vector2(DrawWidth, GetSizeFor(0));
|
||||||
|
|
||||||
AddLayout(flashlightProperties);
|
AddLayout(flashlightProperties);
|
||||||
}
|
}
|
||||||
@ -46,6 +65,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
|
|
||||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||||
{
|
{
|
||||||
|
this.TransformTo(nameof(FlashlightSize), new Vector2(DrawWidth, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string FragmentShader => "RectangularFlashlight";
|
protected override string FragmentShader => "RectangularFlashlight";
|
||||||
|
23
osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
Normal file
23
osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 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.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Scoring
|
||||||
|
{
|
||||||
|
public class ManiaHealthProcessor : DrainingHealthProcessor
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ManiaHealthProcessor(double drainStartTime, double drainLenience = 0)
|
||||||
|
: base(drainStartTime, drainLenience)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override HitResult GetSimulatedHitResult(Judgement judgement)
|
||||||
|
{
|
||||||
|
// Users are not expected to attain perfect judgements for all notes due to the tighter hit window.
|
||||||
|
return judgement.MaxResult == HitResult.Perfect ? HitResult.Great : judgement.MaxResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
var beatmap = new Beatmap<HitObject>
|
var beatmap = new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = hitObjects,
|
HitObjects = hitObjects,
|
||||||
BeatmapInfo = new BeatmapInfo { BaseDifficulty = new BeatmapDifficulty(beatmapDifficulty) }
|
BeatmapInfo = new BeatmapInfo { Difficulty = new BeatmapDifficulty(beatmapDifficulty) }
|
||||||
};
|
};
|
||||||
|
|
||||||
return new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
return new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
@ -40,7 +40,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
|
|
||||||
public TestSceneOsuDistanceSnapGrid()
|
public TestSceneOsuDistanceSnapGrid()
|
||||||
{
|
{
|
||||||
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
225
osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs
Normal file
225
osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Edit;
|
||||||
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||||
|
{
|
||||||
|
public class TestSceneSliderSnapping : EditorTestScene
|
||||||
|
{
|
||||||
|
private const double beat_length = 1000;
|
||||||
|
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||||
|
{
|
||||||
|
var controlPointInfo = new ControlPointInfo();
|
||||||
|
controlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
|
||||||
|
return new TestBeatmap(ruleset, false)
|
||||||
|
{
|
||||||
|
ControlPointInfo = controlPointInfo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Slider slider;
|
||||||
|
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
base.SetUpSteps();
|
||||||
|
|
||||||
|
AddStep("add unsnapped slider", () => EditorBeatmap.Add(slider = new Slider
|
||||||
|
{
|
||||||
|
StartTime = 0,
|
||||||
|
Position = OsuPlayfield.BASE_SIZE / 5,
|
||||||
|
Path = new SliderPath
|
||||||
|
{
|
||||||
|
ControlPoints =
|
||||||
|
{
|
||||||
|
new PathControlPoint(Vector2.Zero),
|
||||||
|
new PathControlPoint(OsuPlayfield.BASE_SIZE * 2 / 5),
|
||||||
|
new PathControlPoint(OsuPlayfield.BASE_SIZE * 3 / 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
AddStep("set beat divisor to 1/1", () =>
|
||||||
|
{
|
||||||
|
var beatDivisor = (BindableBeatDivisor)Editor.Dependencies.Get(typeof(BindableBeatDivisor));
|
||||||
|
beatDivisor.Value = 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMovingUnsnappedSliderNodesSnaps()
|
||||||
|
{
|
||||||
|
PathControlPointPiece sliderEnd = null;
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("select slider end", () =>
|
||||||
|
{
|
||||||
|
sliderEnd = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints.Last());
|
||||||
|
InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre);
|
||||||
|
});
|
||||||
|
AddStep("move slider end", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre - new Vector2(0, 20));
|
||||||
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
|
});
|
||||||
|
assertSliderSnapped(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddingControlPointToUnsnappedSliderNodesSnaps()
|
||||||
|
{
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("move mouse to new point location", () =>
|
||||||
|
{
|
||||||
|
var firstPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[0]);
|
||||||
|
var secondPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]);
|
||||||
|
InputManager.MoveMouseTo((firstPiece.ScreenSpaceDrawQuad.Centre + secondPiece.ScreenSpaceDrawQuad.Centre) / 2);
|
||||||
|
});
|
||||||
|
AddStep("move slider end", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
|
});
|
||||||
|
assertSliderSnapped(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRemovingControlPointFromUnsnappedSliderNodesSnaps()
|
||||||
|
{
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("move mouse to second control point", () =>
|
||||||
|
{
|
||||||
|
var secondPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]);
|
||||||
|
InputManager.MoveMouseTo(secondPiece);
|
||||||
|
});
|
||||||
|
AddStep("quick delete", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.ShiftLeft);
|
||||||
|
InputManager.PressButton(MouseButton.Right);
|
||||||
|
InputManager.ReleaseKey(Key.ShiftLeft);
|
||||||
|
});
|
||||||
|
assertSliderSnapped(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResizingUnsnappedSliderSnaps()
|
||||||
|
{
|
||||||
|
SelectionBoxScaleHandle handle = null;
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("move mouse to scale handle", () =>
|
||||||
|
{
|
||||||
|
handle = this.ChildrenOfType<SelectionBoxScaleHandle>().First();
|
||||||
|
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
||||||
|
});
|
||||||
|
AddStep("scale slider", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre + new Vector2(20, 20));
|
||||||
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
|
});
|
||||||
|
assertSliderSnapped(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRotatingUnsnappedSliderDoesNotSnap()
|
||||||
|
{
|
||||||
|
SelectionBoxRotationHandle handle = null;
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("move mouse to rotate handle", () =>
|
||||||
|
{
|
||||||
|
handle = this.ChildrenOfType<SelectionBoxRotationHandle>().First();
|
||||||
|
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
||||||
|
});
|
||||||
|
AddStep("scale slider", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre + new Vector2(0, 20));
|
||||||
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
|
});
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFlippingSliderDoesNotSnap()
|
||||||
|
{
|
||||||
|
OsuSelectionHandler selectionHandler = null;
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("flip slider horizontally", () =>
|
||||||
|
{
|
||||||
|
selectionHandler = this.ChildrenOfType<OsuSelectionHandler>().Single();
|
||||||
|
selectionHandler.OnPressed(new KeyBindingPressEvent<GlobalAction>(InputManager.CurrentState, GlobalAction.EditorFlipHorizontally));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("flip slider vertically", () =>
|
||||||
|
{
|
||||||
|
selectionHandler = this.ChildrenOfType<OsuSelectionHandler>().Single();
|
||||||
|
selectionHandler.OnPressed(new KeyBindingPressEvent<GlobalAction>(InputManager.CurrentState, GlobalAction.EditorFlipVertically));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestReversingSliderDoesNotSnap()
|
||||||
|
{
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
|
||||||
|
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
AddStep("reverse slider", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
|
InputManager.Key(Key.G);
|
||||||
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertSliderSnapped(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSliderSnapped(bool snapped)
|
||||||
|
=> AddAssert($"slider is {(snapped ? "" : "not ")}snapped", () =>
|
||||||
|
{
|
||||||
|
double durationInBeatLengths = slider.Duration / beat_length;
|
||||||
|
double fractionalPart = durationInBeatLengths - (int)durationInBeatLengths;
|
||||||
|
return Precision.AlmostEquals(fractionalPart, 0) == snapped;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
|
using osu.Game.Screens.Edit.Timing;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||||
|
{
|
||||||
|
public class TestSceneSliderVelocityAdjust : OsuGameTestScene
|
||||||
|
{
|
||||||
|
private Screens.Edit.Editor editor => Game.ScreenStack.CurrentScreen as Screens.Edit.Editor;
|
||||||
|
|
||||||
|
private EditorBeatmap editorBeatmap => editor.ChildrenOfType<EditorBeatmap>().FirstOrDefault();
|
||||||
|
|
||||||
|
private EditorClock editorClock => editor.ChildrenOfType<EditorClock>().FirstOrDefault();
|
||||||
|
|
||||||
|
private Slider slider => editorBeatmap.HitObjects.OfType<Slider>().FirstOrDefault();
|
||||||
|
|
||||||
|
private TimelineHitObjectBlueprint blueprint => editor.ChildrenOfType<TimelineHitObjectBlueprint>().FirstOrDefault();
|
||||||
|
|
||||||
|
private DifficultyPointPiece difficultyPointPiece => blueprint.ChildrenOfType<DifficultyPointPiece>().First();
|
||||||
|
|
||||||
|
private IndeterminateSliderWithTextBoxInput<double> velocityTextBox => Game.ChildrenOfType<DifficultyPointPiece.DifficultyEditPopover>().First().ChildrenOfType<IndeterminateSliderWithTextBoxInput<double>>().First();
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
||||||
|
|
||||||
|
private bool editorComponentsReady => editor.ChildrenOfType<HitObjectComposer>().FirstOrDefault()?.IsLoaded == true
|
||||||
|
&& editor.ChildrenOfType<TimelineArea>().FirstOrDefault()?.IsLoaded == true
|
||||||
|
&& editor?.ChildrenOfType<Playfield>().FirstOrDefault()?.IsLoaded == true;
|
||||||
|
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void TestVelocityChangeSavesCorrectly(bool adjustVelocity)
|
||||||
|
{
|
||||||
|
double? velocity = null;
|
||||||
|
|
||||||
|
AddStep("enter editor", () => Game.ScreenStack.Push(new EditorLoader()));
|
||||||
|
AddUntilStep("wait for editor load", () => editorComponentsReady);
|
||||||
|
|
||||||
|
AddStep("seek to first control point", () => editorClock.Seek(editorBeatmap.ControlPointInfo.TimingPoints.First().Time));
|
||||||
|
AddStep("enter slider placement mode", () => InputManager.Key(Key.Number3));
|
||||||
|
|
||||||
|
AddStep("move mouse to centre", () => InputManager.MoveMouseTo(editor.ChildrenOfType<Playfield>().First().ScreenSpaceDrawQuad.Centre));
|
||||||
|
AddStep("start placement", () => InputManager.Click(MouseButton.Left));
|
||||||
|
|
||||||
|
AddStep("move mouse to bottom right", () => InputManager.MoveMouseTo(editor.ChildrenOfType<Playfield>().First().ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||||
|
AddStep("end placement", () => InputManager.Click(MouseButton.Right));
|
||||||
|
|
||||||
|
AddStep("exit placement mode", () => InputManager.Key(Key.Number1));
|
||||||
|
|
||||||
|
AddAssert("slider placed", () => slider != null);
|
||||||
|
|
||||||
|
AddStep("select slider", () => editorBeatmap.SelectedHitObjects.Add(slider));
|
||||||
|
|
||||||
|
AddAssert("ensure one slider placed", () => slider != null);
|
||||||
|
|
||||||
|
AddStep("store velocity", () => velocity = slider.Velocity);
|
||||||
|
|
||||||
|
if (adjustVelocity)
|
||||||
|
{
|
||||||
|
AddStep("open velocity adjust panel", () => difficultyPointPiece.TriggerClick());
|
||||||
|
AddStep("change velocity", () => velocityTextBox.Current.Value = 2);
|
||||||
|
|
||||||
|
AddAssert("velocity adjusted", () =>
|
||||||
|
{
|
||||||
|
Debug.Assert(velocity != null);
|
||||||
|
return Precision.AlmostEquals(velocity.Value * 2, slider.Velocity);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("store velocity", () => velocity = slider.Velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddStep("save", () => InputManager.Keys(PlatformAction.Save));
|
||||||
|
AddStep("exit", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
|
AddStep("enter editor (again)", () => Game.ScreenStack.Push(new EditorLoader()));
|
||||||
|
AddUntilStep("wait for editor load", () => editorComponentsReady);
|
||||||
|
|
||||||
|
AddStep("seek to slider", () => editorClock.Seek(slider.StartTime));
|
||||||
|
AddAssert("slider has correct velocity", () => slider.Velocity == velocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
Difficulty = new BeatmapDifficulty
|
||||||
{
|
{
|
||||||
CircleSize = 8
|
CircleSize = 8
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,6 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
|
|
||||||
private bool isBreak() => Player.IsBreakTime.Value;
|
private bool isBreak() => Player.IsBreakTime.Value;
|
||||||
|
|
||||||
private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha);
|
private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha, 0.1f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Timeout(10000)]
|
|
||||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
|
Difficulty = new BeatmapDifficulty { CircleSize = 6 },
|
||||||
Ruleset = ruleset
|
Ruleset = ruleset
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 10 },
|
Difficulty = new BeatmapDifficulty { OverallDifficulty = 10 },
|
||||||
Ruleset = ruleset
|
Ruleset = ruleset
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -358,7 +358,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
},
|
},
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
|
Difficulty = new BeatmapDifficulty { SliderTickRate = 3 },
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
Ruleset = new OsuRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -364,7 +364,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
HitObjects = hitObjects,
|
HitObjects = hitObjects,
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
|
Difficulty = new BeatmapDifficulty { SliderTickRate = 3 },
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
Ruleset = new OsuRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
private int effectiveMissCount;
|
private double effectiveMissCount;
|
||||||
|
|
||||||
public OsuPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
public OsuPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, attributes, score)
|
: base(ruleset, attributes, score)
|
||||||
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
if (mods.Any(m => m is OsuModNoFail))
|
if (mods.Any(m => m is OsuModNoFail))
|
||||||
multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount);
|
multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount);
|
||||||
|
|
||||||
if (mods.Any(m => m is OsuModSpunOut))
|
if (mods.Any(m => m is OsuModSpunOut) && totalHits > 0)
|
||||||
multiplier *= 1.0 - Math.Pow((double)Attributes.SpinnerCount / totalHits, 0.85);
|
multiplier *= 1.0 - Math.Pow((double)Attributes.SpinnerCount / totalHits, 0.85);
|
||||||
|
|
||||||
if (mods.Any(h => h is OsuModRelax))
|
if (mods.Any(h => h is OsuModRelax))
|
||||||
@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||||
if (effectiveMissCount > 0)
|
if (effectiveMissCount > 0)
|
||||||
aimValue *= 0.97 * Math.Pow(1 - Math.Pow((double)effectiveMissCount / totalHits, 0.775), effectiveMissCount);
|
aimValue *= 0.97 * Math.Pow(1 - Math.Pow(effectiveMissCount / totalHits, 0.775), effectiveMissCount);
|
||||||
|
|
||||||
aimValue *= getComboScalingFactor();
|
aimValue *= getComboScalingFactor();
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||||
if (effectiveMissCount > 0)
|
if (effectiveMissCount > 0)
|
||||||
speedValue *= 0.97 * Math.Pow(1 - Math.Pow((double)effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
|
speedValue *= 0.97 * Math.Pow(1 - Math.Pow(effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
|
||||||
|
|
||||||
speedValue *= getComboScalingFactor();
|
speedValue *= getComboScalingFactor();
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||||
if (effectiveMissCount > 0)
|
if (effectiveMissCount > 0)
|
||||||
flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow((double)effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
|
flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow(effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
|
||||||
|
|
||||||
flashlightValue *= getComboScalingFactor();
|
flashlightValue *= getComboScalingFactor();
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return flashlightValue;
|
return flashlightValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int calculateEffectiveMissCount()
|
private double calculateEffectiveMissCount()
|
||||||
{
|
{
|
||||||
// Guess the number of misses + slider breaks from combo
|
// Guess the number of misses + slider breaks from combo
|
||||||
double comboBasedMissCount = 0.0;
|
double comboBasedMissCount = 0.0;
|
||||||
@ -259,7 +259,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
// Clamp miss count since it's derived from combo and can be higher than total hits and that breaks some calculations
|
// Clamp miss count since it's derived from combo and can be higher than total hits and that breaks some calculations
|
||||||
comboBasedMissCount = Math.Min(comboBasedMissCount, totalHits);
|
comboBasedMissCount = Math.Min(comboBasedMissCount, totalHits);
|
||||||
|
|
||||||
return Math.Max(countMiss, (int)Math.Floor(comboBasedMissCount));
|
return Math.Max(countMiss, comboBasedMissCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getComboScalingFactor() => Attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
private double getComboScalingFactor() => Attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
@ -283,6 +283,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snap the path to the current beat divisor before checking length validity.
|
||||||
|
slider.SnapTo(snapProvider);
|
||||||
|
|
||||||
if (!slider.Path.HasValidLength)
|
if (!slider.Path.HasValidLength)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < slider.Path.ControlPoints.Count; i++)
|
for (int i = 0; i < slider.Path.ControlPoints.Count; i++)
|
||||||
@ -290,6 +293,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
|
|
||||||
slider.Position = oldPosition;
|
slider.Position = oldPosition;
|
||||||
slider.StartTime = oldStartTime;
|
slider.StartTime = oldStartTime;
|
||||||
|
// Snap the path length again to undo the invalid length.
|
||||||
|
slider.SnapTo(snapProvider);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
controlPoints.BindTo(HitObject.Path.ControlPoints);
|
controlPoints.BindTo(HitObject.Path.ControlPoints);
|
||||||
|
|
||||||
pathVersion.BindTo(HitObject.Path.Version);
|
pathVersion.BindTo(HitObject.Path.Version);
|
||||||
pathVersion.BindValueChanged(_ => updatePath());
|
pathVersion.BindValueChanged(_ => editorBeatmap?.Update(HitObject));
|
||||||
|
|
||||||
BodyPiece.UpdateFrom(HitObject);
|
BodyPiece.UpdateFrom(HitObject);
|
||||||
}
|
}
|
||||||
@ -208,6 +208,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
// Move the control points from the insertion index onwards to make room for the insertion
|
// Move the control points from the insertion index onwards to make room for the insertion
|
||||||
controlPoints.Insert(insertionIndex, pathControlPoint);
|
controlPoints.Insert(insertionIndex, pathControlPoint);
|
||||||
|
|
||||||
|
HitObject.SnapTo(composer);
|
||||||
|
|
||||||
return pathControlPoint;
|
return pathControlPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +229,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
controlPoints.Remove(c);
|
controlPoints.Remove(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are 0 or 1 remaining control points, the slider is in a degenerate (single point) form and should be deleted
|
// Snap the slider to the current beat divisor before checking length validity.
|
||||||
|
HitObject.SnapTo(composer);
|
||||||
|
|
||||||
|
// If there are 0 or 1 remaining control points, or the slider has an invalid length, it is in a degenerate form and should be deleted
|
||||||
if (controlPoints.Count <= 1 || !HitObject.Path.HasValidLength)
|
if (controlPoints.Count <= 1 || !HitObject.Path.HasValidLength)
|
||||||
{
|
{
|
||||||
placementHandler?.Delete(HitObject);
|
placementHandler?.Delete(HitObject);
|
||||||
@ -242,12 +247,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
HitObject.Position += first;
|
HitObject.Position += first;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePath()
|
|
||||||
{
|
|
||||||
HitObject.Path.ExpectedDistance.Value = composer?.GetSnappedDistanceFromDistance(HitObject, (float)HitObject.Path.CalculatedDistance) ?? (float)HitObject.Path.CalculatedDistance;
|
|
||||||
editorBeatmap?.Update(HitObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void convertToStream()
|
private void convertToStream()
|
||||||
{
|
{
|
||||||
if (editorBeatmap == null || changeHandler == null || beatDivisor == null)
|
if (editorBeatmap == null || changeHandler == null || beatDivisor == null)
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -18,6 +22,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class OsuSelectionHandler : EditorSelectionHandler
|
public class OsuSelectionHandler : EditorSelectionHandler
|
||||||
{
|
{
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private IPositionSnapProvider? positionSnapProvider { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -27,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
/// During a transform, the initial path types of a single selected slider are stored so they
|
/// During a transform, the initial path types of a single selected slider are stored so they
|
||||||
/// can be maintained throughout the operation.
|
/// can be maintained throughout the operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<PathType?> referencePathTypes;
|
private List<PathType?>? referencePathTypes;
|
||||||
|
|
||||||
protected override void OnSelectionChanged()
|
protected override void OnSelectionChanged()
|
||||||
{
|
{
|
||||||
@ -197,6 +204,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
for (int i = 0; i < slider.Path.ControlPoints.Count; ++i)
|
for (int i = 0; i < slider.Path.ControlPoints.Count; ++i)
|
||||||
slider.Path.ControlPoints[i].Type = referencePathTypes[i];
|
slider.Path.ControlPoints[i].Type = referencePathTypes[i];
|
||||||
|
|
||||||
|
// Snap the slider's length to the current beat divisor
|
||||||
|
// to calculate the final resulting duration / bounding box before the final checks.
|
||||||
|
slider.SnapTo(positionSnapProvider);
|
||||||
|
|
||||||
//if sliderhead or sliderend end up outside playfield, revert scaling.
|
//if sliderhead or sliderend end up outside playfield, revert scaling.
|
||||||
Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider });
|
Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider });
|
||||||
(bool xInBounds, bool yInBounds) = isQuadInBounds(scaledQuad);
|
(bool xInBounds, bool yInBounds) = isQuadInBounds(scaledQuad);
|
||||||
@ -206,6 +217,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
foreach (var point in slider.Path.ControlPoints)
|
foreach (var point in slider.Path.ControlPoints)
|
||||||
point.Position = oldControlPoints.Dequeue();
|
point.Position = oldControlPoints.Dequeue();
|
||||||
|
|
||||||
|
// Snap the slider's length again to undo the potentially-invalid length applied by the previous snap.
|
||||||
|
slider.SnapTo(positionSnapProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scaleHitObjects(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale)
|
private void scaleHitObjects(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale)
|
||||||
|
@ -12,7 +12,6 @@ using osu.Game.Rulesets.Mods;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
@ -21,27 +20,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
private const float default_flashlight_size = 180;
|
|
||||||
|
|
||||||
private const double default_follow_delay = 120;
|
private const double default_follow_delay = 120;
|
||||||
|
|
||||||
private OsuFlashlight flashlight;
|
|
||||||
|
|
||||||
public override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight();
|
|
||||||
|
|
||||||
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
|
||||||
{
|
|
||||||
if (drawable is DrawableSlider s)
|
|
||||||
s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
|
||||||
{
|
|
||||||
base.ApplyToDrawableRuleset(drawableRuleset);
|
|
||||||
|
|
||||||
flashlight.FollowDelay = FollowDelay.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[SettingSource("Follow delay", "Milliseconds until the flashlight reaches the cursor")]
|
[SettingSource("Follow delay", "Milliseconds until the flashlight reaches the cursor")]
|
||||||
public BindableNumber<double> FollowDelay { get; } = new BindableDouble(default_follow_delay)
|
public BindableNumber<double> FollowDelay { get; } = new BindableDouble(default_follow_delay)
|
||||||
{
|
{
|
||||||
@ -50,13 +30,45 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
Precision = default_follow_delay,
|
Precision = default_follow_delay,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
|
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||||
|
{
|
||||||
|
MinValue = 0.5f,
|
||||||
|
MaxValue = 2f,
|
||||||
|
Default = 1f,
|
||||||
|
Value = 1f,
|
||||||
|
Precision = 0.1f
|
||||||
|
};
|
||||||
|
|
||||||
|
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||||
|
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||||
|
{
|
||||||
|
Default = true,
|
||||||
|
Value = true
|
||||||
|
};
|
||||||
|
|
||||||
|
public override float DefaultFlashlightSize => 180;
|
||||||
|
|
||||||
|
private OsuFlashlight flashlight;
|
||||||
|
|
||||||
|
protected override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight(this);
|
||||||
|
|
||||||
|
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
||||||
|
{
|
||||||
|
if (drawable is DrawableSlider s)
|
||||||
|
s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
|
||||||
|
}
|
||||||
|
|
||||||
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
||||||
{
|
{
|
||||||
public double FollowDelay { private get; set; }
|
private readonly double followDelay;
|
||||||
|
|
||||||
public OsuFlashlight()
|
public OsuFlashlight(OsuModFlashlight modFlashlight)
|
||||||
|
: base(modFlashlight)
|
||||||
{
|
{
|
||||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
followDelay = modFlashlight.FollowDelay.Value;
|
||||||
|
|
||||||
|
FlashlightSize = new Vector2(0, GetSizeFor(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSliderTrackingChange(ValueChangedEvent<bool> e)
|
public void OnSliderTrackingChange(ValueChangedEvent<bool> e)
|
||||||
@ -71,24 +83,14 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
var destination = e.MousePosition;
|
var destination = e.MousePosition;
|
||||||
|
|
||||||
FlashlightPosition = Interpolation.ValueAt(
|
FlashlightPosition = Interpolation.ValueAt(
|
||||||
Math.Min(Math.Abs(Clock.ElapsedFrameTime), FollowDelay), position, destination, 0, FollowDelay, Easing.Out);
|
Math.Min(Math.Abs(Clock.ElapsedFrameTime), followDelay), position, destination, 0, followDelay, Easing.Out);
|
||||||
|
|
||||||
return base.OnMouseMove(e);
|
return base.OnMouseMove(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getSizeFor(int combo)
|
|
||||||
{
|
|
||||||
if (combo > 200)
|
|
||||||
return default_flashlight_size * 0.8f;
|
|
||||||
else if (combo > 100)
|
|
||||||
return default_flashlight_size * 0.9f;
|
|
||||||
else
|
|
||||||
return default_flashlight_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||||
{
|
{
|
||||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string FragmentShader => "CircularFlashlight";
|
protected override string FragmentShader => "CircularFlashlight";
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
@ -65,8 +65,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
double startTime = StartTime + (float)(i + 1) / totalSpins * Duration;
|
double startTime = StartTime + (float)(i + 1) / totalSpins * Duration;
|
||||||
|
|
||||||
AddNested(i < SpinsRequired
|
AddNested(i < SpinsRequired
|
||||||
? new SpinnerTick { StartTime = startTime }
|
? new SpinnerTick { StartTime = startTime, Position = Position }
|
||||||
: new SpinnerBonusTick { StartTime = startTime });
|
: new SpinnerBonusTick { StartTime = startTime, Position = Position });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,15 +3,13 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Default
|
namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||||
{
|
{
|
||||||
public class SpinnerBackgroundLayer : SpinnerFill
|
public class SpinnerBackgroundLayer : SpinnerFill
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, DrawableHitObject drawableHitObject)
|
private void load()
|
||||||
{
|
{
|
||||||
Disc.Alpha = 0;
|
Disc.Alpha = 0;
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
private GameplayState gameplayState { get; set; }
|
private GameplayState gameplayState { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin, OsuColour colours)
|
private void load(ISkinSource skin)
|
||||||
{
|
{
|
||||||
var texture = skin.GetTexture("star2");
|
var texture = skin.GetTexture("star2");
|
||||||
var starBreakAdditive = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255);
|
var starBreakAdditive = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255);
|
||||||
|
@ -12,6 +12,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
CursorExpand,
|
CursorExpand,
|
||||||
CursorRotate,
|
CursorRotate,
|
||||||
HitCircleOverlayAboveNumber,
|
HitCircleOverlayAboveNumber,
|
||||||
|
|
||||||
|
// ReSharper disable once IdentifierTypo
|
||||||
HitCircleOverlayAboveNumer, // Some old skins will have this typo
|
HitCircleOverlayAboveNumer, // Some old skins will have this typo
|
||||||
SpinnerFrequencyModulate,
|
SpinnerFrequencyModulate,
|
||||||
SpinnerNoBlink
|
SpinnerNoBlink
|
||||||
|
@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
pointGrid.Content = points;
|
pointGrid.Content = points;
|
||||||
|
|
||||||
if (score.HitEvents == null || score.HitEvents.Count == 0)
|
if (score.HitEvents.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Todo: This should probably not be done like this.
|
// Todo: This should probably not be done like this.
|
||||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig)
|
private void load(OsuRulesetConfigManager rulesetConfig)
|
||||||
{
|
{
|
||||||
rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);
|
rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,12 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
Difficulty = new BeatmapDifficulty(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
Artist = @"Unknown",
|
Artist = @"Unknown",
|
||||||
Title = @"Sample Beatmap",
|
Title = @"Sample Beatmap",
|
||||||
AuthorString = @"peppy",
|
Author = { Username = @"peppy" },
|
||||||
},
|
},
|
||||||
Ruleset = new TaikoRuleset().RulesetInfo
|
Ruleset = new TaikoRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
// 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.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
|
||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
|
||||||
using osu.Game.Screens.Edit;
|
|
||||||
using osu.Game.Screens.Edit.Setup;
|
|
||||||
using osu.Game.Screens.Menu;
|
|
||||||
using osu.Game.Screens.Select;
|
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Tests.Editor
|
|
||||||
{
|
|
||||||
public class TestSceneEditorSaving : OsuGameTestScene
|
|
||||||
{
|
|
||||||
private Screens.Edit.Editor editor => Game.ChildrenOfType<Screens.Edit.Editor>().FirstOrDefault();
|
|
||||||
|
|
||||||
private EditorBeatmap editorBeatmap => (EditorBeatmap)editor.Dependencies.Get(typeof(EditorBeatmap));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests the general expected flow of creating a new beatmap, saving it, then loading it back from song select.
|
|
||||||
/// Emphasis is placed on <see cref="BeatmapDifficulty.SliderMultiplier"/>, since taiko has special handling for it to keep compatibility with stable.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestNewBeatmapSaveThenLoad()
|
|
||||||
{
|
|
||||||
AddStep("set default beatmap", () => Game.Beatmap.SetDefault());
|
|
||||||
AddStep("set taiko ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
|
|
||||||
|
|
||||||
PushAndConfirm(() => new EditorLoader());
|
|
||||||
|
|
||||||
AddUntilStep("wait for editor load", () => editor?.IsLoaded == true);
|
|
||||||
|
|
||||||
AddUntilStep("wait for metadata screen load", () => editor.ChildrenOfType<MetadataSection>().FirstOrDefault()?.IsLoaded == true);
|
|
||||||
|
|
||||||
// We intentionally switch away from the metadata screen, else there is a feedback loop with the textbox handling which causes metadata changes below to get overwritten.
|
|
||||||
|
|
||||||
AddStep("Enter compose mode", () => InputManager.Key(Key.F1));
|
|
||||||
AddUntilStep("Wait for compose mode load", () => editor.ChildrenOfType<HitObjectComposer>().FirstOrDefault()?.IsLoaded == true);
|
|
||||||
|
|
||||||
AddStep("Set slider multiplier", () => editorBeatmap.Difficulty.SliderMultiplier = 2);
|
|
||||||
AddStep("Set artist and title", () =>
|
|
||||||
{
|
|
||||||
editorBeatmap.BeatmapInfo.Metadata.Artist = "artist";
|
|
||||||
editorBeatmap.BeatmapInfo.Metadata.Title = "title";
|
|
||||||
});
|
|
||||||
AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName = "difficulty");
|
|
||||||
|
|
||||||
checkMutations();
|
|
||||||
|
|
||||||
AddStep("Save", () => InputManager.Keys(PlatformAction.Save));
|
|
||||||
|
|
||||||
checkMutations();
|
|
||||||
|
|
||||||
AddStep("Exit", () => InputManager.Key(Key.Escape));
|
|
||||||
|
|
||||||
AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
|
||||||
|
|
||||||
PushAndConfirm(() => new PlaySongSelect());
|
|
||||||
|
|
||||||
AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault);
|
|
||||||
AddStep("Open options", () => InputManager.Key(Key.F3));
|
|
||||||
AddStep("Enter editor", () => InputManager.Key(Key.Number5));
|
|
||||||
|
|
||||||
AddUntilStep("Wait for editor load", () => editor != null);
|
|
||||||
|
|
||||||
checkMutations();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkMutations()
|
|
||||||
{
|
|
||||||
AddAssert("Beatmap has correct slider multiplier", () =>
|
|
||||||
{
|
|
||||||
// we can only assert value correctness on TaikoMultiplierAppliedDifficulty, because that is the final difficulty converted taiko beatmaps use.
|
|
||||||
// therefore, ensure that we have that difficulty type by calling .CopyFrom(), which is a no-op if the type is already correct.
|
|
||||||
var taikoDifficulty = new TaikoBeatmapConverter.TaikoMultiplierAppliedDifficulty();
|
|
||||||
taikoDifficulty.CopyFrom(editorBeatmap.Difficulty);
|
|
||||||
return Precision.AlmostEquals(taikoDifficulty.SliderMultiplier, 2);
|
|
||||||
});
|
|
||||||
AddAssert("Beatmap has correct metadata", () => editorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && editorBeatmap.BeatmapInfo.Metadata.Title == "title");
|
|
||||||
AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +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 NUnit.Framework;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests.Editor
|
||||||
|
{
|
||||||
|
public class TestSceneTaikoEditorSaving : EditorSavingTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateRuleset() => new TaikoRuleset();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTaikoSliderMultiplier()
|
||||||
|
{
|
||||||
|
AddStep("Set slider multiplier", () => EditorBeatmap.Difficulty.SliderMultiplier = 2);
|
||||||
|
|
||||||
|
SaveEditor();
|
||||||
|
|
||||||
|
AddAssert("Beatmap has correct slider multiplier", assertTaikoSliderMulitplier);
|
||||||
|
|
||||||
|
ReloadEditorToSameBeatmap();
|
||||||
|
|
||||||
|
AddAssert("Beatmap still has correct slider multiplier", assertTaikoSliderMulitplier);
|
||||||
|
|
||||||
|
bool assertTaikoSliderMulitplier()
|
||||||
|
{
|
||||||
|
// we can only assert value correctness on TaikoMultiplierAppliedDifficulty, because that is the final difficulty converted taiko beatmaps use.
|
||||||
|
// therefore, ensure that we have that difficulty type by calling .CopyFrom(), which is a no-op if the type is already correct.
|
||||||
|
var taikoDifficulty = new TaikoBeatmapConverter.TaikoMultiplierAppliedDifficulty();
|
||||||
|
taikoDifficulty.CopyFrom(EditorBeatmap.Difficulty);
|
||||||
|
return Precision.AlmostEquals(taikoDifficulty.SliderMultiplier, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -40,10 +40,10 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor
|
|||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
EditorBeatmap = new EditorBeatmap(new TaikoBeatmap())
|
EditorBeatmap = new EditorBeatmap(new TaikoBeatmap
|
||||||
{
|
{
|
||||||
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }
|
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }
|
||||||
},
|
}),
|
||||||
new TaikoHitObjectComposer(new TaikoRuleset())
|
new TaikoHitObjectComposer(new TaikoRuleset())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -158,12 +158,12 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
{
|
{
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
Difficulty = new BeatmapDifficulty(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
Artist = "Unknown",
|
Artist = "Unknown",
|
||||||
Title = "Sample Beatmap",
|
Title = "Sample Beatmap",
|
||||||
AuthorString = "Craftplacer",
|
Author = { Username = "Craftplacer" },
|
||||||
},
|
},
|
||||||
Ruleset = new TaikoRuleset().RulesetInfo
|
Ruleset = new TaikoRuleset().RulesetInfo
|
||||||
},
|
},
|
||||||
|
@ -12,7 +12,6 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Taiko.Tests
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Timeout(10000)]
|
|
||||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||||
|
36
osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs
Normal file
36
osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneDrumRollJudgements : TestSceneTaikoPlayer
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestStrongDrumRollFullyJudgedOnKilled()
|
||||||
|
{
|
||||||
|
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||||
|
AddAssert("all judgements are misses", () => Player.Results.All(r => r.Type == r.Judgement.MinResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool Autoplay => false;
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap<TaikoHitObject>
|
||||||
|
{
|
||||||
|
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new DrumRoll
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Duration = 1000,
|
||||||
|
IsStrong = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken);
|
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken);
|
||||||
|
|
||||||
if (original.BeatmapInfo.RulesetID == 3)
|
if (original.BeatmapInfo.Ruleset.OnlineID == 3)
|
||||||
{
|
{
|
||||||
// Post processing step to transform mania hit objects with the same start time into strong hits
|
// Post processing step to transform mania hit objects with the same start time into strong hits
|
||||||
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
|
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
|
||||||
@ -191,6 +191,9 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
protected override Beatmap<TaikoHitObject> CreateBeatmap() => new TaikoBeatmap();
|
protected override Beatmap<TaikoHitObject> CreateBeatmap() => new TaikoBeatmap();
|
||||||
|
|
||||||
|
// Important to note that this is subclassing a realm object.
|
||||||
|
// Realm doesn't allow this, but for now this can work since we aren't (in theory?) persisting this to the database.
|
||||||
|
// It is only used during beatmap conversion and processing.
|
||||||
internal class TaikoMultiplierAppliedDifficulty : BeatmapDifficulty
|
internal class TaikoMultiplierAppliedDifficulty : BeatmapDifficulty
|
||||||
{
|
{
|
||||||
public TaikoMultiplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty)
|
public TaikoMultiplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty)
|
||||||
@ -205,6 +208,8 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
#region Overrides of BeatmapDifficulty
|
#region Overrides of BeatmapDifficulty
|
||||||
|
|
||||||
|
public override BeatmapDifficulty Clone() => new TaikoMultiplierAppliedDifficulty(this);
|
||||||
|
|
||||||
public override void CopyTo(BeatmapDifficulty other)
|
public override void CopyTo(BeatmapDifficulty other)
|
||||||
{
|
{
|
||||||
base.CopyTo(other);
|
base.CopyTo(other);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
@ -16,9 +17,26 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
private const float default_flashlight_size = 250;
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
|
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||||
|
{
|
||||||
|
MinValue = 0.5f,
|
||||||
|
MaxValue = 1.5f,
|
||||||
|
Default = 1f,
|
||||||
|
Value = 1f,
|
||||||
|
Precision = 0.1f
|
||||||
|
};
|
||||||
|
|
||||||
public override Flashlight CreateFlashlight() => new TaikoFlashlight(playfield);
|
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||||
|
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||||
|
{
|
||||||
|
Default = true,
|
||||||
|
Value = true
|
||||||
|
};
|
||||||
|
|
||||||
|
public override float DefaultFlashlightSize => 250;
|
||||||
|
|
||||||
|
protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield);
|
||||||
|
|
||||||
private TaikoPlayfield playfield;
|
private TaikoPlayfield playfield;
|
||||||
|
|
||||||
@ -33,7 +51,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
||||||
private readonly TaikoPlayfield taikoPlayfield;
|
private readonly TaikoPlayfield taikoPlayfield;
|
||||||
|
|
||||||
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
|
public TaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield)
|
||||||
|
: base(modFlashlight)
|
||||||
{
|
{
|
||||||
this.taikoPlayfield = taikoPlayfield;
|
this.taikoPlayfield = taikoPlayfield;
|
||||||
FlashlightSize = getSizeFor(0);
|
FlashlightSize = getSizeFor(0);
|
||||||
@ -43,15 +62,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
|
|
||||||
private Vector2 getSizeFor(int combo)
|
private Vector2 getSizeFor(int combo)
|
||||||
{
|
{
|
||||||
float size = default_flashlight_size;
|
|
||||||
|
|
||||||
if (combo > 200)
|
|
||||||
size *= 0.8f;
|
|
||||||
else if (combo > 100)
|
|
||||||
size *= 0.9f;
|
|
||||||
|
|
||||||
// Preserve flashlight size through the playfield's aspect adjustment.
|
// Preserve flashlight size through the playfield's aspect adjustment.
|
||||||
return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
return new Vector2(0, GetSizeFor(combo) * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||||
|
@ -197,6 +197,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnKilled()
|
||||||
|
{
|
||||||
|
base.OnKilled();
|
||||||
|
|
||||||
|
if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged)
|
||||||
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
|
}
|
||||||
|
|
||||||
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -52,6 +53,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnKilled()
|
||||||
|
{
|
||||||
|
base.OnKilled();
|
||||||
|
|
||||||
|
if (Time.Current > HitObject.GetEndTime() && !Judged)
|
||||||
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateHitStateTransforms(ArmedState state)
|
protected override void UpdateHitStateTransforms(ArmedState state)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
@ -92,6 +101,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnKilled()
|
||||||
|
{
|
||||||
|
base.OnKilled();
|
||||||
|
|
||||||
|
if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged)
|
||||||
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
|
}
|
||||||
|
|
||||||
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
AccentColour = Hit.COLOUR_CENTRE;
|
AccentColour = Hit.COLOUR_CENTRE;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
|
|||||||
if (!effectPoint.KiaiMode)
|
if (!effectPoint.KiaiMode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (beatIndex % (int)timingPoint.TimeSignature != 0)
|
if (beatIndex % timingPoint.TimeSignature.Numerator != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double duration = timingPoint.BeatLength * 2;
|
double duration = timingPoint.BeatLength * 2;
|
||||||
|
@ -5,7 +5,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
AccentColour = Hit.COLOUR_RIM;
|
AccentColour = Hit.COLOUR_RIM;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -39,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(TextureStore textures, GameplayState gameplayState)
|
private void load(GameplayState gameplayState)
|
||||||
{
|
{
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
||||||
Assert.AreEqual(164471, metadata.PreviewTime);
|
Assert.AreEqual(164471, metadata.PreviewTime);
|
||||||
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
||||||
Assert.IsTrue(beatmapInfo.RulesetID == 0);
|
Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0);
|
||||||
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
||||||
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
||||||
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
||||||
@ -117,7 +117,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(string.Empty, metadata.Source);
|
Assert.AreEqual(string.Empty, metadata.Source);
|
||||||
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
|
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
|
||||||
Assert.AreEqual(557821, beatmapInfo.OnlineID);
|
Assert.AreEqual(557821, beatmapInfo.OnlineID);
|
||||||
Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineID);
|
Assert.AreEqual(241526, beatmapInfo.BeatmapSet?.OnlineID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,17 +178,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
var timingPoint = controlPoints.TimingPointAt(0);
|
var timingPoint = controlPoints.TimingPointAt(0);
|
||||||
Assert.AreEqual(956, timingPoint.Time);
|
Assert.AreEqual(956, timingPoint.Time);
|
||||||
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
|
||||||
timingPoint = controlPoints.TimingPointAt(48428);
|
timingPoint = controlPoints.TimingPointAt(48428);
|
||||||
Assert.AreEqual(956, timingPoint.Time);
|
Assert.AreEqual(956, timingPoint.Time);
|
||||||
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
|
||||||
timingPoint = controlPoints.TimingPointAt(119637);
|
timingPoint = controlPoints.TimingPointAt(119637);
|
||||||
Assert.AreEqual(119637, timingPoint.Time);
|
Assert.AreEqual(119637, timingPoint.Time);
|
||||||
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
|
||||||
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
||||||
Assert.AreEqual(0, difficultyPoint.Time);
|
Assert.AreEqual(0, difficultyPoint.Time);
|
||||||
@ -794,5 +794,74 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.That(path.Distance, Is.EqualTo(1));
|
Assert.That(path.Distance, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLegacyDefaultsPreserved()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
using (var stream = new LineBufferedReader(memoryStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(decoded.BeatmapInfo.AudioLeadIn, Is.EqualTo(0));
|
||||||
|
Assert.That(decoded.BeatmapInfo.StackLeniency, Is.EqualTo(0.7f));
|
||||||
|
Assert.That(decoded.BeatmapInfo.SpecialStyle, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.LetterboxInBreaks, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.WidescreenStoryboard, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.EpilepsyWarning, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.SamplesMatchPlaybackRate, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.Countdown, Is.EqualTo(CountdownType.Normal));
|
||||||
|
Assert.That(decoded.BeatmapInfo.CountdownOffset, Is.EqualTo(0));
|
||||||
|
Assert.That(decoded.BeatmapInfo.Metadata.PreviewTime, Is.EqualTo(-1));
|
||||||
|
Assert.That(decoded.BeatmapInfo.Ruleset.OnlineID, Is.EqualTo(0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUndefinedApproachRateInheritsOverallDifficulty()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("undefined-approach-rate.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
Assert.That(decoded.Difficulty.ApproachRate, Is.EqualTo(1));
|
||||||
|
Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestApproachRateDefinedBeforeOverallDifficulty()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("approach-rate-before-overall-difficulty.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
Assert.That(decoded.Difficulty.ApproachRate, Is.EqualTo(9));
|
||||||
|
Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestApproachRateDefinedAfterOverallDifficulty()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("approach-rate-after-overall-difficulty.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
Assert.That(decoded.Difficulty.ApproachRate, Is.EqualTo(9));
|
||||||
|
Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
|
|
||||||
private IBeatmap convert(IBeatmap beatmap)
|
private IBeatmap convert(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
switch (beatmap.BeatmapInfo.RulesetID)
|
switch (beatmap.BeatmapInfo.Ruleset.OnlineID)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
|
beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Replays;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
@ -51,6 +52,11 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
|
|
||||||
Assert.AreEqual(829_931, score.ScoreInfo.TotalScore);
|
Assert.AreEqual(829_931, score.ScoreInfo.TotalScore);
|
||||||
Assert.AreEqual(3, score.ScoreInfo.MaxCombo);
|
Assert.AreEqual(3, score.ScoreInfo.MaxCombo);
|
||||||
|
|
||||||
|
Assert.IsTrue(score.ScoreInfo.Mods.Any(m => m is ManiaModClassic));
|
||||||
|
Assert.IsTrue(score.ScoreInfo.APIMods.Any(m => m.Acronym == "CL"));
|
||||||
|
Assert.IsTrue(score.ScoreInfo.ModsJson.Contains("CL"));
|
||||||
|
|
||||||
Assert.IsTrue(Precision.AlmostEquals(0.8889, score.ScoreInfo.Accuracy, 0.0001));
|
Assert.IsTrue(Precision.AlmostEquals(0.8889, score.ScoreInfo.Accuracy, 0.0001));
|
||||||
Assert.AreEqual(ScoreRank.B, score.ScoreInfo.Rank);
|
Assert.AreEqual(ScoreRank.B, score.ScoreInfo.Rank);
|
||||||
|
|
||||||
@ -95,7 +101,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.That(decodedAfterEncode, Is.Not.Null);
|
Assert.That(decodedAfterEncode, Is.Not.Null);
|
||||||
|
|
||||||
Assert.That(decodedAfterEncode.ScoreInfo.User.Username, Is.EqualTo(scoreInfo.User.Username));
|
Assert.That(decodedAfterEncode.ScoreInfo.User.Username, Is.EqualTo(scoreInfo.User.Username));
|
||||||
Assert.That(decodedAfterEncode.ScoreInfo.BeatmapInfoID, Is.EqualTo(scoreInfo.BeatmapInfoID));
|
|
||||||
Assert.That(decodedAfterEncode.ScoreInfo.Ruleset, Is.EqualTo(scoreInfo.Ruleset));
|
Assert.That(decodedAfterEncode.ScoreInfo.Ruleset, Is.EqualTo(scoreInfo.Ruleset));
|
||||||
Assert.That(decodedAfterEncode.ScoreInfo.TotalScore, Is.EqualTo(scoreInfo.TotalScore));
|
Assert.That(decodedAfterEncode.ScoreInfo.TotalScore, Is.EqualTo(scoreInfo.TotalScore));
|
||||||
Assert.That(decodedAfterEncode.ScoreInfo.MaxCombo, Is.EqualTo(scoreInfo.MaxCombo));
|
Assert.That(decodedAfterEncode.ScoreInfo.MaxCombo, Is.EqualTo(scoreInfo.MaxCombo));
|
||||||
@ -129,7 +134,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
MD5Hash = md5Hash,
|
MD5Hash = md5Hash,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
BaseDifficulty = new BeatmapDifficulty()
|
Difficulty = new BeatmapDifficulty()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
var beatmap = decodeAsJson(normal);
|
var beatmap = decodeAsJson(normal);
|
||||||
var meta = beatmap.BeatmapInfo.Metadata;
|
var meta = beatmap.BeatmapInfo.Metadata;
|
||||||
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
|
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID);
|
||||||
Assert.AreEqual("Soleily", meta.Artist);
|
Assert.AreEqual("Soleily", meta.Artist);
|
||||||
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
||||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||||
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
||||||
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
||||||
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
|
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
|
||||||
Assert.IsTrue(beatmapInfo.RulesetID == 0);
|
Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0);
|
||||||
Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks);
|
Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks);
|
||||||
Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard);
|
Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard);
|
||||||
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
||||||
|
85
osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
Normal file
85
osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// 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.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Tests.Database;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Beatmaps.IO
|
||||||
|
{
|
||||||
|
public static class BeatmapImportHelper
|
||||||
|
{
|
||||||
|
public static async Task<BeatmapSetInfo> LoadQuickOszIntoOsu(OsuGameBase osu)
|
||||||
|
{
|
||||||
|
string temp = TestResources.GetQuickTestBeatmapForImport();
|
||||||
|
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var importedSet = await manager.Import(new ImportTask(temp)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Debug.Assert(importedSet != null);
|
||||||
|
|
||||||
|
ensureLoaded(osu);
|
||||||
|
|
||||||
|
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||||
|
|
||||||
|
return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
||||||
|
{
|
||||||
|
string temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||||
|
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var importedSet = await manager.Import(new ImportTask(temp)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Debug.Assert(importedSet != null);
|
||||||
|
|
||||||
|
ensureLoaded(osu);
|
||||||
|
|
||||||
|
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||||
|
|
||||||
|
return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
||||||
|
{
|
||||||
|
var realm = osu.Dependencies.Get<RealmAccess>();
|
||||||
|
|
||||||
|
realm.Run(r => BeatmapImporterTests.EnsureLoaded(r, timeout));
|
||||||
|
|
||||||
|
// TODO: add back some extra checks outside of the realm ones?
|
||||||
|
// var set = queryBeatmapSets().First();
|
||||||
|
// foreach (BeatmapInfo b in set.Beatmaps)
|
||||||
|
// Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
|
||||||
|
// Assert.IsTrue(set.Beatmaps.Count > 0);
|
||||||
|
// var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
||||||
|
// Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||||
|
// beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
|
||||||
|
// Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||||
|
// beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
|
||||||
|
// Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||||
|
// beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
||||||
|
// Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
|
||||||
|
{
|
||||||
|
Task task = Task.Run(() =>
|
||||||
|
{
|
||||||
|
while (!result()) Thread.Sleep(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var meta = beatmap.Metadata;
|
var meta = beatmap.Metadata;
|
||||||
|
|
||||||
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
|
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID);
|
||||||
Assert.AreEqual("Soleily", meta.Artist);
|
Assert.AreEqual("Soleily", meta.Artist);
|
||||||
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
||||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||||
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -23,6 +24,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
public const double BASE_STARS = 5.55;
|
public const double BASE_STARS = 5.55;
|
||||||
|
|
||||||
|
private static readonly Guid guid = Guid.NewGuid();
|
||||||
|
|
||||||
private BeatmapSetInfo importedSet;
|
private BeatmapSetInfo importedSet;
|
||||||
|
|
||||||
private TestBeatmapDifficultyCache difficultyCache;
|
private TestBeatmapDifficultyCache difficultyCache;
|
||||||
@ -32,7 +35,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase osu)
|
private void load(OsuGameBase osu)
|
||||||
{
|
{
|
||||||
importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).Result;
|
importedSet = BeatmapImportHelper.LoadQuickOszIntoOsu(osu).GetResultSafely();
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -97,8 +100,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestKeyEqualsWithDifferentModInstances()
|
public void TestKeyEqualsWithDifferentModInstances()
|
||||||
{
|
{
|
||||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
|
||||||
Assert.That(key1, Is.EqualTo(key2));
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||||
@ -107,8 +110,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestKeyEqualsWithDifferentModOrder()
|
public void TestKeyEqualsWithDifferentModOrder()
|
||||||
{
|
{
|
||||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
||||||
|
|
||||||
Assert.That(key1, Is.EqualTo(key2));
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||||
@ -117,8 +120,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestKeyDoesntEqualWithDifferentModSettings()
|
public void TestKeyDoesntEqualWithDifferentModSettings()
|
||||||
{
|
{
|
||||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
|
||||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
|
||||||
|
|
||||||
Assert.That(key1, Is.Not.EqualTo(key2));
|
Assert.That(key1, Is.Not.EqualTo(key2));
|
||||||
Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode()));
|
Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode()));
|
||||||
@ -127,8 +130,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestKeyEqualWithMatchingModSettings()
|
public void TestKeyEqualWithMatchingModSettings()
|
||||||
{
|
{
|
||||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||||
|
|
||||||
Assert.That(key1, Is.EqualTo(key2));
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
@ -30,7 +31,13 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
AddStep("add beatmap", () =>
|
AddStep("add beatmap", () =>
|
||||||
{
|
{
|
||||||
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
});
|
||||||
editorBeatmap.HitObjectAdded += h => addedObject = h;
|
editorBeatmap.HitObjectAdded += h => addedObject = h;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,7 +56,14 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
EditorBeatmap editorBeatmap = null;
|
EditorBeatmap editorBeatmap = null;
|
||||||
AddStep("add beatmap", () =>
|
AddStep("add beatmap", () =>
|
||||||
{
|
{
|
||||||
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } });
|
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
HitObjects = { hitCircle }
|
||||||
|
});
|
||||||
editorBeatmap.HitObjectRemoved += h => removedObject = h;
|
editorBeatmap.HitObjectRemoved += h => removedObject = h;
|
||||||
});
|
});
|
||||||
AddStep("remove hitobject", () => editorBeatmap.Remove(editorBeatmap.HitObjects.First()));
|
AddStep("remove hitobject", () => editorBeatmap.Remove(editorBeatmap.HitObjects.First()));
|
||||||
@ -71,7 +85,14 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
EditorBeatmap editorBeatmap;
|
EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } });
|
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
HitObjects = { hitCircle }
|
||||||
|
});
|
||||||
editorBeatmap.HitObjectUpdated += h => changedObject = h;
|
editorBeatmap.HitObjectUpdated += h => changedObject = h;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -91,7 +112,13 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
AddStep("add beatmap", () =>
|
AddStep("add beatmap", () =>
|
||||||
{
|
{
|
||||||
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
});
|
||||||
editorBeatmap.HitObjectUpdated += h => changedObject = h;
|
editorBeatmap.HitObjectUpdated += h => changedObject = h;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -111,7 +138,14 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
public void TestRemovedHitObjectStartTimeChangeEvent()
|
public void TestRemovedHitObjectStartTimeChangeEvent()
|
||||||
{
|
{
|
||||||
var hitCircle = new HitCircle();
|
var hitCircle = new HitCircle();
|
||||||
var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } });
|
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
HitObjects = { hitCircle }
|
||||||
|
});
|
||||||
|
|
||||||
HitObject changedObject = null;
|
HitObject changedObject = null;
|
||||||
editorBeatmap.HitObjectUpdated += h => changedObject = h;
|
editorBeatmap.HitObjectUpdated += h => changedObject = h;
|
||||||
@ -131,6 +165,10 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
{
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle(),
|
new HitCircle(),
|
||||||
@ -156,6 +194,10 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
{
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle(),
|
new HitCircle(),
|
||||||
@ -185,7 +227,13 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
updatedObjects.Clear();
|
updatedObjects.Clear();
|
||||||
|
|
||||||
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
@ -220,7 +268,13 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
updatedObjects.Clear();
|
updatedObjects.Clear();
|
||||||
|
|
||||||
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
},
|
||||||
|
});
|
||||||
editorBeatmap.Add(new HitCircle());
|
editorBeatmap.Add(new HitCircle());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Models;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps
|
namespace osu.Game.Tests.Beatmaps
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
Artist = "artist",
|
Artist = "artist",
|
||||||
Title = "title",
|
Title = "title",
|
||||||
Author = new APIUser { Username = "creator" }
|
Author = new RealmUser { Username = "creator" }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
{
|
{
|
||||||
Artist = "artist",
|
Artist = "artist",
|
||||||
Title = "title",
|
Title = "title",
|
||||||
Author = new APIUser { Username = "creator" }
|
Author = new RealmUser { Username = "creator" }
|
||||||
},
|
},
|
||||||
DifficultyName = "difficulty"
|
DifficultyName = "difficulty"
|
||||||
};
|
};
|
||||||
|
@ -9,6 +9,21 @@ namespace osu.Game.Tests.Chat
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class MessageFormatterTests
|
public class MessageFormatterTests
|
||||||
{
|
{
|
||||||
|
private string originalWebsiteRootUrl;
|
||||||
|
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public void OneTimeSetUp()
|
||||||
|
{
|
||||||
|
originalWebsiteRootUrl = MessageFormatter.WebsiteRootUrl;
|
||||||
|
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeTearDown]
|
||||||
|
public void OneTimeTearDown()
|
||||||
|
{
|
||||||
|
MessageFormatter.WebsiteRootUrl = originalWebsiteRootUrl;
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBareLink()
|
public void TestBareLink()
|
||||||
{
|
{
|
||||||
@ -32,8 +47,6 @@ namespace osu.Game.Tests.Chat
|
|||||||
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/discussions/123", "https://dev.ppy.sh/beatmapsets/discussions/123")]
|
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/discussions/123", "https://dev.ppy.sh/beatmapsets/discussions/123")]
|
||||||
public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link)
|
public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link)
|
||||||
{
|
{
|
||||||
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
|
|
||||||
|
|
||||||
Message result = MessageFormatter.FormatMessage(new Message { Content = link });
|
Message result = MessageFormatter.FormatMessage(new Message { Content = link });
|
||||||
|
|
||||||
Assert.AreEqual(result.Content, result.DisplayContent);
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
@ -47,7 +60,10 @@ namespace osu.Game.Tests.Chat
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestMultipleComplexLinks()
|
public void TestMultipleComplexLinks()
|
||||||
{
|
{
|
||||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a http://test.io/link#fragment. (see https://twitter.com). Also, This string should not be altered. http://example.com/" });
|
Message result = MessageFormatter.FormatMessage(new Message
|
||||||
|
{
|
||||||
|
Content = "This is a http://test.io/link#fragment. (see https://twitter.com). Also, This string should not be altered. http://example.com/"
|
||||||
|
});
|
||||||
|
|
||||||
Assert.AreEqual(result.Content, result.DisplayContent);
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
Assert.AreEqual(3, result.Links.Count);
|
Assert.AreEqual(3, result.Links.Count);
|
||||||
@ -104,7 +120,7 @@ namespace osu.Game.Tests.Chat
|
|||||||
|
|
||||||
Assert.AreEqual("This is a Wiki Link.", result.DisplayContent);
|
Assert.AreEqual("This is a Wiki Link.", result.DisplayContent);
|
||||||
Assert.AreEqual(1, result.Links.Count);
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||||
Assert.AreEqual(10, result.Links[0].Index);
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
Assert.AreEqual(9, result.Links[0].Length);
|
Assert.AreEqual(9, result.Links[0].Length);
|
||||||
}
|
}
|
||||||
@ -117,15 +133,15 @@ namespace osu.Game.Tests.Chat
|
|||||||
Assert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent);
|
Assert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent);
|
||||||
Assert.AreEqual(3, result.Links.Count);
|
Assert.AreEqual(3, result.Links.Count);
|
||||||
|
|
||||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||||
Assert.AreEqual(10, result.Links[0].Index);
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
Assert.AreEqual(9, result.Links[0].Length);
|
Assert.AreEqual(9, result.Links[0].Length);
|
||||||
|
|
||||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki:Link", result.Links[1].Url);
|
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki:Link", result.Links[1].Url);
|
||||||
Assert.AreEqual(20, result.Links[1].Index);
|
Assert.AreEqual(20, result.Links[1].Index);
|
||||||
Assert.AreEqual(9, result.Links[1].Length);
|
Assert.AreEqual(9, result.Links[1].Length);
|
||||||
|
|
||||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki.Link", result.Links[2].Url);
|
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki.Link", result.Links[2].Url);
|
||||||
Assert.AreEqual(29, result.Links[2].Index);
|
Assert.AreEqual(29, result.Links[2].Index);
|
||||||
Assert.AreEqual(9, result.Links[2].Length);
|
Assert.AreEqual(9, result.Links[2].Length);
|
||||||
}
|
}
|
||||||
@ -445,12 +461,15 @@ namespace osu.Game.Tests.Chat
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLinkComplex()
|
public void TestLinkComplex()
|
||||||
{
|
{
|
||||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [http://www.simple-test.com simple test] with some [traps] and [[wiki links]]. Don't forget to visit https://osu.ppy.sh (now!)[http://google.com]\uD83D\uDE12" });
|
Message result = MessageFormatter.FormatMessage(new Message
|
||||||
|
{
|
||||||
|
Content = "This is a [http://www.simple-test.com simple test] with some [traps] and [[wiki links]]. Don't forget to visit https://osu.ppy.sh (now!)[http://google.com]\uD83D\uDE12"
|
||||||
|
});
|
||||||
|
|
||||||
Assert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now!\0\0\0", result.DisplayContent);
|
Assert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now!\0\0\0", result.DisplayContent);
|
||||||
Assert.AreEqual(5, result.Links.Count);
|
Assert.AreEqual(5, result.Links.Count);
|
||||||
|
|
||||||
Link f = result.Links.Find(l => l.Url == "https://osu.ppy.sh/wiki/wiki links");
|
Link f = result.Links.Find(l => l.Url == "https://dev.ppy.sh/wiki/wiki links");
|
||||||
Assert.That(f, Is.Not.Null);
|
Assert.That(f, Is.Not.Null);
|
||||||
Assert.AreEqual(44, f.Index);
|
Assert.AreEqual(44, f.Index);
|
||||||
Assert.AreEqual(10, f.Length);
|
Assert.AreEqual(10, f.Length);
|
||||||
@ -514,8 +533,6 @@ namespace osu.Game.Tests.Chat
|
|||||||
[TestCase("https://dev.ppy.sh/home/changelog/lazer/2021.1012", "lazer/2021.1012")]
|
[TestCase("https://dev.ppy.sh/home/changelog/lazer/2021.1012", "lazer/2021.1012")]
|
||||||
public void TestChangelogLinks(string link, string expectedArg)
|
public void TestChangelogLinks(string link, string expectedArg)
|
||||||
{
|
{
|
||||||
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
|
|
||||||
|
|
||||||
LinkDetails result = MessageFormatter.GetLinkDetails(link);
|
LinkDetails result = MessageFormatter.GetLinkDetails(link);
|
||||||
|
|
||||||
Assert.AreEqual(LinkAction.OpenChangelog, result.Action);
|
Assert.AreEqual(LinkAction.OpenChangelog, result.Action);
|
||||||
|
@ -6,6 +6,7 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
@ -154,7 +155,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Name matches the automatically chosen name from `CleanRunHeadlessGameHost` above, so we end up using the same storage location.
|
// Name matches the automatically chosen name from `CleanRunHeadlessGameHost` above, so we end up using the same storage location.
|
||||||
using (HeadlessGameHost host = new TestRunHeadlessGameHost(firstRunName))
|
using (HeadlessGameHost host = new TestRunHeadlessGameHost(firstRunName, null))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -179,7 +180,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
// intentionally spin this up on a separate task to avoid disposal deadlocks.
|
// intentionally spin this up on a separate task to avoid disposal deadlocks.
|
||||||
// see https://github.com/EventStore/EventStore/issues/1179
|
// see https://github.com/EventStore/EventStore/issues/1179
|
||||||
await Task.Run(() => osu.CollectionManager.Import(stream).Wait());
|
await Task.Factory.StartNew(() => osu.CollectionManager.Import(stream).WaitSafely(), TaskCreationOptions.LongRunning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ using osu.Game.Extensions;
|
|||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Stores;
|
using osu.Game.Stores;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
using Realms;
|
using Realms;
|
||||||
@ -34,56 +35,157 @@ namespace osu.Game.Tests.Database
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BeatmapImporterTests : RealmTest
|
public class BeatmapImporterTests : RealmTest
|
||||||
{
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestDetachBeatmapSet()
|
||||||
|
{
|
||||||
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
|
{
|
||||||
|
using (var importer = new BeatmapModelManager(realm, storage))
|
||||||
|
using (new RulesetStore(realm, storage))
|
||||||
|
{
|
||||||
|
Live<BeatmapSetInfo>? beatmapSet;
|
||||||
|
|
||||||
|
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
|
||||||
|
beatmapSet = await importer.Import(reader);
|
||||||
|
|
||||||
|
Assert.NotNull(beatmapSet);
|
||||||
|
Debug.Assert(beatmapSet != null);
|
||||||
|
|
||||||
|
BeatmapSetInfo? detachedBeatmapSet = null;
|
||||||
|
|
||||||
|
beatmapSet.PerformRead(live =>
|
||||||
|
{
|
||||||
|
detachedBeatmapSet = live.Detach();
|
||||||
|
|
||||||
|
// files are omitted
|
||||||
|
Assert.AreEqual(0, detachedBeatmapSet.Files.Count);
|
||||||
|
|
||||||
|
Assert.AreEqual(live.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count);
|
||||||
|
Assert.AreEqual(live.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count());
|
||||||
|
Assert.AreEqual(live.Metadata, detachedBeatmapSet.Metadata);
|
||||||
|
});
|
||||||
|
|
||||||
|
Debug.Assert(detachedBeatmapSet != null);
|
||||||
|
|
||||||
|
// Check detached instances can all be accessed without throwing.
|
||||||
|
Assert.AreEqual(0, detachedBeatmapSet.Files.Count);
|
||||||
|
Assert.NotNull(detachedBeatmapSet.Beatmaps.Count);
|
||||||
|
Assert.NotZero(detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count());
|
||||||
|
Assert.NotNull(detachedBeatmapSet.Metadata);
|
||||||
|
|
||||||
|
// Check cyclic reference to beatmap set
|
||||||
|
Assert.AreEqual(detachedBeatmapSet, detachedBeatmapSet.Beatmaps.First().BeatmapSet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUpdateDetachedBeatmapSet()
|
||||||
|
{
|
||||||
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
|
{
|
||||||
|
using (var importer = new BeatmapModelManager(realm, storage))
|
||||||
|
using (new RulesetStore(realm, storage))
|
||||||
|
{
|
||||||
|
Live<BeatmapSetInfo>? beatmapSet;
|
||||||
|
|
||||||
|
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
|
||||||
|
beatmapSet = await importer.Import(reader);
|
||||||
|
|
||||||
|
Assert.NotNull(beatmapSet);
|
||||||
|
Debug.Assert(beatmapSet != null);
|
||||||
|
|
||||||
|
// Detach at the BeatmapInfo point, similar to what GetWorkingBeatmap does.
|
||||||
|
BeatmapInfo? detachedBeatmap = null;
|
||||||
|
|
||||||
|
beatmapSet.PerformRead(s => detachedBeatmap = s.Beatmaps.First().Detach());
|
||||||
|
|
||||||
|
BeatmapSetInfo? detachedBeatmapSet = detachedBeatmap?.BeatmapSet;
|
||||||
|
|
||||||
|
Debug.Assert(detachedBeatmapSet != null);
|
||||||
|
|
||||||
|
var newUser = new RealmUser { Username = "peppy", OnlineID = 2 };
|
||||||
|
|
||||||
|
detachedBeatmapSet.Beatmaps.First().Metadata.Artist = "New Artist";
|
||||||
|
detachedBeatmapSet.Beatmaps.First().Metadata.Author = newUser;
|
||||||
|
|
||||||
|
Assert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked);
|
||||||
|
detachedBeatmapSet.Status = BeatmapOnlineStatus.Ranked;
|
||||||
|
|
||||||
|
beatmapSet.PerformWrite(s =>
|
||||||
|
{
|
||||||
|
detachedBeatmapSet.CopyChangesToRealm(s);
|
||||||
|
});
|
||||||
|
|
||||||
|
beatmapSet.PerformRead(s =>
|
||||||
|
{
|
||||||
|
// Check above changes explicitly.
|
||||||
|
Assert.AreEqual(BeatmapOnlineStatus.Ranked, s.Status);
|
||||||
|
Assert.AreEqual("New Artist", s.Beatmaps.First().Metadata.Artist);
|
||||||
|
Assert.AreEqual(newUser, s.Beatmaps.First().Metadata.Author);
|
||||||
|
Assert.NotZero(s.Files.Count);
|
||||||
|
|
||||||
|
// Check nothing was lost in the copy operation.
|
||||||
|
Assert.AreEqual(s.Files.Count, detachedBeatmapSet.Files.Count);
|
||||||
|
Assert.AreEqual(s.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count());
|
||||||
|
Assert.AreEqual(s.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count);
|
||||||
|
Assert.AreEqual(s.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count());
|
||||||
|
Assert.AreEqual(s.Metadata, detachedBeatmapSet.Metadata);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportBeatmapThenCleanup()
|
public void TestImportBeatmapThenCleanup()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using (var importer = new BeatmapImporter(realmFactory, storage))
|
using (var importer = new BeatmapModelManager(realm, storage))
|
||||||
using (new RealmRulesetStore(realmFactory, storage))
|
using (new RulesetStore(realm, storage))
|
||||||
{
|
{
|
||||||
ILive<RealmBeatmapSet>? imported;
|
Live<BeatmapSetInfo>? imported;
|
||||||
|
|
||||||
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
|
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
|
||||||
imported = await importer.Import(reader);
|
imported = await importer.Import(reader);
|
||||||
|
|
||||||
Assert.AreEqual(1, realmFactory.Context.All<RealmBeatmapSet>().Count());
|
Assert.AreEqual(1, realm.Realm.All<BeatmapSetInfo>().Count());
|
||||||
|
|
||||||
Assert.NotNull(imported);
|
Assert.NotNull(imported);
|
||||||
Debug.Assert(imported != null);
|
Debug.Assert(imported != null);
|
||||||
|
|
||||||
imported.PerformWrite(s => s.DeletePending = true);
|
imported.PerformWrite(s => s.DeletePending = true);
|
||||||
|
|
||||||
Assert.AreEqual(1, realmFactory.Context.All<RealmBeatmapSet>().Count(s => s.DeletePending));
|
Assert.AreEqual(1, realm.Realm.All<BeatmapSetInfo>().Count(s => s.DeletePending));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.Log("Running with no work to purge pending deletions");
|
Logger.Log("Running with no work to purge pending deletions");
|
||||||
|
|
||||||
RunTestWithRealm((realmFactory, _) => { Assert.AreEqual(0, realmFactory.Context.All<RealmBeatmapSet>().Count()); });
|
RunTestWithRealm((realm, _) => { Assert.AreEqual(0, realm.Realm.All<BeatmapSetInfo>().Count()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportWhenClosed()
|
public void TestImportWhenClosed()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
await LoadOszIntoStore(importer, realmFactory.Context);
|
await LoadOszIntoStore(importer, realm.Realm);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAccessFileAfterImport()
|
public void TestAccessFileAfterImport()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
var beatmap = imported.Beatmaps.First();
|
var beatmap = imported.Beatmaps.First();
|
||||||
var file = beatmap.File;
|
var file = beatmap.File;
|
||||||
@ -96,33 +198,33 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenDelete()
|
public void TestImportThenDelete()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
deleteBeatmapSet(imported, realmFactory.Context);
|
deleteBeatmapSet(imported, realm.Realm);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenDeleteFromStream()
|
public void TestImportThenDeleteFromStream()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? tempPath = TestResources.GetTestBeatmapForImport();
|
string? tempPath = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
ILive<RealmBeatmapSet>? importedSet;
|
Live<BeatmapSetInfo>? importedSet;
|
||||||
|
|
||||||
using (var stream = File.OpenRead(tempPath))
|
using (var stream = File.OpenRead(tempPath))
|
||||||
{
|
{
|
||||||
importedSet = await importer.Import(new ImportTask(stream, Path.GetFileName(tempPath)));
|
importedSet = await importer.Import(new ImportTask(stream, Path.GetFileName(tempPath)));
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.NotNull(importedSet);
|
Assert.NotNull(importedSet);
|
||||||
@ -131,39 +233,39 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing");
|
Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing");
|
||||||
File.Delete(tempPath);
|
File.Delete(tempPath);
|
||||||
|
|
||||||
var imported = realmFactory.Context.All<RealmBeatmapSet>().First(beatmapSet => beatmapSet.ID == importedSet.ID);
|
var imported = realm.Realm.All<BeatmapSetInfo>().First(beatmapSet => beatmapSet.ID == importedSet.ID);
|
||||||
|
|
||||||
deleteBeatmapSet(imported, realmFactory.Context);
|
deleteBeatmapSet(imported, realm.Realm);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenImport()
|
public void TestImportThenImport()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
|
var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||||
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
||||||
|
|
||||||
checkBeatmapSetCount(realmFactory.Context, 1);
|
checkBeatmapSetCount(realm.Realm, 1);
|
||||||
checkSingleReferencedFileCount(realmFactory.Context, 18);
|
checkSingleReferencedFileCount(realm.Realm, 18);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenImportWithReZip()
|
public void TestImportThenImportWithReZip()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -172,7 +274,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
string hashBefore = hashFile(temp);
|
string hashBefore = hashFile(temp);
|
||||||
|
|
||||||
@ -190,7 +292,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
|
|
||||||
Assert.NotNull(importedSecondTime);
|
Assert.NotNull(importedSecondTime);
|
||||||
Debug.Assert(importedSecondTime != null);
|
Debug.Assert(importedSecondTime != null);
|
||||||
@ -209,10 +311,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenImportWithChangedHashedFile()
|
public void TestImportThenImportWithChangedHashedFile()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -221,9 +323,9 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
await createScoreForBeatmap(realmFactory.Context, imported.Beatmaps.First());
|
await createScoreForBeatmap(realm.Realm, imported.Beatmaps.First());
|
||||||
|
|
||||||
using (var zip = ZipArchive.Open(temp))
|
using (var zip = ZipArchive.Open(temp))
|
||||||
zip.WriteToDirectory(extractedFolder);
|
zip.WriteToDirectory(extractedFolder);
|
||||||
@ -241,7 +343,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
|
|
||||||
// check the newly "imported" beatmap is not the original.
|
// check the newly "imported" beatmap is not the original.
|
||||||
Assert.NotNull(importedSecondTime);
|
Assert.NotNull(importedSecondTime);
|
||||||
@ -261,10 +363,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Ignore("intentionally broken by import optimisations")]
|
[Ignore("intentionally broken by import optimisations")]
|
||||||
public void TestImportThenImportWithChangedFile()
|
public void TestImportThenImportWithChangedFile()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -273,7 +375,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
using (var zip = ZipArchive.Open(temp))
|
using (var zip = ZipArchive.Open(temp))
|
||||||
zip.WriteToDirectory(extractedFolder);
|
zip.WriteToDirectory(extractedFolder);
|
||||||
@ -290,7 +392,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
|
|
||||||
Assert.NotNull(importedSecondTime);
|
Assert.NotNull(importedSecondTime);
|
||||||
Debug.Assert(importedSecondTime != null);
|
Debug.Assert(importedSecondTime != null);
|
||||||
@ -309,10 +411,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenImportWithDifferentFilename()
|
public void TestImportThenImportWithDifferentFilename()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -321,7 +423,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
using (var zip = ZipArchive.Open(temp))
|
using (var zip = ZipArchive.Open(temp))
|
||||||
zip.WriteToDirectory(extractedFolder);
|
zip.WriteToDirectory(extractedFolder);
|
||||||
@ -338,7 +440,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
|
|
||||||
Assert.NotNull(importedSecondTime);
|
Assert.NotNull(importedSecondTime);
|
||||||
Debug.Assert(importedSecondTime != null);
|
Debug.Assert(importedSecondTime != null);
|
||||||
@ -358,12 +460,12 @@ namespace osu.Game.Tests.Database
|
|||||||
[Ignore("intentionally broken by import optimisations")]
|
[Ignore("intentionally broken by import optimisations")]
|
||||||
public void TestImportCorruptThenImport()
|
public void TestImportCorruptThenImport()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
var firstFile = imported.Files.First();
|
var firstFile = imported.Files.First();
|
||||||
|
|
||||||
@ -374,7 +476,7 @@ namespace osu.Game.Tests.Database
|
|||||||
using (var stream = storage.GetStream(firstFile.File.GetStoragePath(), FileAccess.Write, FileMode.Create))
|
using (var stream = storage.GetStream(firstFile.File.GetStoragePath(), FileAccess.Write, FileMode.Create))
|
||||||
stream.WriteByte(0);
|
stream.WriteByte(0);
|
||||||
|
|
||||||
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
|
var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
using (var stream = storage.GetStream(firstFile.File.GetStoragePath()))
|
using (var stream = storage.GetStream(firstFile.File.GetStoragePath()))
|
||||||
Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import");
|
Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import");
|
||||||
@ -383,18 +485,18 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||||
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
||||||
|
|
||||||
checkBeatmapSetCount(realmFactory.Context, 1);
|
checkBeatmapSetCount(realm.Realm, 1);
|
||||||
checkSingleReferencedFileCount(realmFactory.Context, 18);
|
checkSingleReferencedFileCount(realm.Realm, 18);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestModelCreationFailureDoesntReturn()
|
public void TestModelCreationFailureDoesntReturn()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var progressNotification = new ImportProgressNotification();
|
var progressNotification = new ImportProgressNotification();
|
||||||
|
|
||||||
@ -408,8 +510,8 @@ namespace osu.Game.Tests.Database
|
|||||||
new ImportTask(zipStream, string.Empty)
|
new ImportTask(zipStream, string.Empty)
|
||||||
);
|
);
|
||||||
|
|
||||||
checkBeatmapSetCount(realmFactory.Context, 0);
|
checkBeatmapSetCount(realm.Realm, 0);
|
||||||
checkBeatmapCount(realmFactory.Context, 0);
|
checkBeatmapCount(realm.Realm, 0);
|
||||||
|
|
||||||
Assert.IsEmpty(imported);
|
Assert.IsEmpty(imported);
|
||||||
Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
|
Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
|
||||||
@ -419,7 +521,7 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestRollbackOnFailure()
|
public void TestRollbackOnFailure()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
int loggedExceptionCount = 0;
|
int loggedExceptionCount = 0;
|
||||||
|
|
||||||
@ -429,16 +531,16 @@ namespace osu.Game.Tests.Database
|
|||||||
Interlocked.Increment(ref loggedExceptionCount);
|
Interlocked.Increment(ref loggedExceptionCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
realmFactory.Context.Write(() => imported.Hash += "-changed");
|
realm.Realm.Write(() => imported.Hash += "-changed");
|
||||||
|
|
||||||
checkBeatmapSetCount(realmFactory.Context, 1);
|
checkBeatmapSetCount(realm.Realm, 1);
|
||||||
checkBeatmapCount(realmFactory.Context, 12);
|
checkBeatmapCount(realm.Realm, 12);
|
||||||
checkSingleReferencedFileCount(realmFactory.Context, 18);
|
checkSingleReferencedFileCount(realm.Realm, 18);
|
||||||
|
|
||||||
string? brokenTempFilename = TestResources.GetTestBeatmapForImport();
|
string? brokenTempFilename = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -463,10 +565,10 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
checkBeatmapSetCount(realmFactory.Context, 1);
|
checkBeatmapSetCount(realm.Realm, 1);
|
||||||
checkBeatmapCount(realmFactory.Context, 12);
|
checkBeatmapCount(realm.Realm, 12);
|
||||||
|
|
||||||
checkSingleReferencedFileCount(realmFactory.Context, 18);
|
checkSingleReferencedFileCount(realm.Realm, 18);
|
||||||
|
|
||||||
Assert.AreEqual(1, loggedExceptionCount);
|
Assert.AreEqual(1, loggedExceptionCount);
|
||||||
|
|
||||||
@ -477,18 +579,18 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenDeleteThenImportOptimisedPath()
|
public void TestImportThenDeleteThenImportOptimisedPath()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
deleteBeatmapSet(imported, realmFactory.Context);
|
deleteBeatmapSet(imported, realm.Realm);
|
||||||
|
|
||||||
Assert.IsTrue(imported.DeletePending);
|
Assert.IsTrue(imported.DeletePending);
|
||||||
|
|
||||||
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
|
var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||||
@ -499,20 +601,52 @@ namespace osu.Game.Tests.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenDeleteThenImportNonOptimisedPath()
|
public void TestImportThenReimportAfterMissingFiles()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new NonOptimisedBeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realmFactory, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realmFactory, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realmFactory.Realm);
|
||||||
|
|
||||||
deleteBeatmapSet(imported, realmFactory.Context);
|
deleteBeatmapSet(imported, realmFactory.Realm);
|
||||||
|
|
||||||
Assert.IsTrue(imported.DeletePending);
|
Assert.IsTrue(imported.DeletePending);
|
||||||
|
|
||||||
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
|
// intentionally nuke all files
|
||||||
|
storage.DeleteDirectory("files");
|
||||||
|
|
||||||
|
Assert.That(imported.Files.All(f => !storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
|
||||||
|
|
||||||
|
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Realm);
|
||||||
|
|
||||||
|
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||||
|
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||||
|
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
||||||
|
Assert.IsFalse(imported.DeletePending);
|
||||||
|
Assert.IsFalse(importedSecondTime.DeletePending);
|
||||||
|
|
||||||
|
// check that the files now exist, even though they were deleted above.
|
||||||
|
Assert.That(importedSecondTime.Files.All(f => storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestImportThenDeleteThenImportNonOptimisedPath()
|
||||||
|
{
|
||||||
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
|
{
|
||||||
|
using var importer = new NonOptimisedBeatmapImporter(realm, storage);
|
||||||
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
|
deleteBeatmapSet(imported, realm.Realm);
|
||||||
|
|
||||||
|
Assert.IsTrue(imported.DeletePending);
|
||||||
|
|
||||||
|
var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||||
@ -525,22 +659,22 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportThenDeleteThenImportWithOnlineIDsMissing()
|
public void TestImportThenDeleteThenImportWithOnlineIDsMissing()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
realmFactory.Context.Write(() =>
|
realm.Realm.Write(() =>
|
||||||
{
|
{
|
||||||
foreach (var b in imported.Beatmaps)
|
foreach (var b in imported.Beatmaps)
|
||||||
b.OnlineID = -1;
|
b.OnlineID = -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
deleteBeatmapSet(imported, realmFactory.Context);
|
deleteBeatmapSet(imported, realm.Realm);
|
||||||
|
|
||||||
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
|
var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
// check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
|
// check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
|
||||||
Assert.IsTrue(imported.ID != importedSecondTime.ID);
|
Assert.IsTrue(imported.ID != importedSecondTime.ID);
|
||||||
@ -551,12 +685,12 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportWithDuplicateBeatmapIDs()
|
public void TestImportWithDuplicateBeatmapIDs()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealm((realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
var metadata = new RealmBeatmapMetadata
|
var metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
Artist = "SomeArtist",
|
Artist = "SomeArtist",
|
||||||
Author =
|
Author =
|
||||||
@ -565,18 +699,18 @@ namespace osu.Game.Tests.Database
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var ruleset = realmFactory.Context.All<RealmRuleset>().First();
|
var ruleset = realm.Realm.All<RulesetInfo>().First();
|
||||||
|
|
||||||
var toImport = new RealmBeatmapSet
|
var toImport = new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineID = 1,
|
OnlineID = 1,
|
||||||
Beatmaps =
|
Beatmaps =
|
||||||
{
|
{
|
||||||
new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata)
|
new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
|
||||||
{
|
{
|
||||||
OnlineID = 2,
|
OnlineID = 2,
|
||||||
},
|
},
|
||||||
new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata)
|
new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
|
||||||
{
|
{
|
||||||
OnlineID = 2,
|
OnlineID = 2,
|
||||||
Status = BeatmapOnlineStatus.Loved,
|
Status = BeatmapOnlineStatus.Loved,
|
||||||
@ -584,7 +718,7 @@ namespace osu.Game.Tests.Database
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var imported = await importer.Import(toImport);
|
var imported = importer.Import(toImport);
|
||||||
|
|
||||||
Assert.NotNull(imported);
|
Assert.NotNull(imported);
|
||||||
Debug.Assert(imported != null);
|
Debug.Assert(imported != null);
|
||||||
@ -597,15 +731,15 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportWhenFileOpen()
|
public void TestImportWhenFileOpen()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
using (File.OpenRead(temp))
|
using (File.OpenRead(temp))
|
||||||
await importer.Import(temp);
|
await importer.Import(temp);
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
File.Delete(temp);
|
File.Delete(temp);
|
||||||
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
|
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
|
||||||
});
|
});
|
||||||
@ -614,10 +748,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportWithDuplicateHashes()
|
public void TestImportWithDuplicateHashes()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -638,7 +772,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
await importer.Import(temp);
|
await importer.Import(temp);
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -650,10 +784,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportNestedStructure()
|
public void TestImportNestedStructure()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -678,7 +812,7 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.NotNull(imported);
|
Assert.NotNull(imported);
|
||||||
Debug.Assert(imported != null);
|
Debug.Assert(imported != null);
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
|
|
||||||
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder");
|
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder");
|
||||||
}
|
}
|
||||||
@ -692,10 +826,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportWithIgnoredDirectoryInArchive()
|
public void TestImportWithIgnoredDirectoryInArchive()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -728,7 +862,7 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.NotNull(imported);
|
Assert.NotNull(imported);
|
||||||
Debug.Assert(imported != null);
|
Debug.Assert(imported != null);
|
||||||
|
|
||||||
ensureLoaded(realmFactory.Context);
|
EnsureLoaded(realm.Realm);
|
||||||
|
|
||||||
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("__MACOSX"))), "Files contain resource fork folder, which should be ignored");
|
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("__MACOSX"))), "Files contain resource fork folder, which should be ignored");
|
||||||
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("actual_data"))), "Files contain common subfolder");
|
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("actual_data"))), "Files contain common subfolder");
|
||||||
@ -743,27 +877,27 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestUpdateBeatmapInfo()
|
public void TestUpdateBeatmapInfo()
|
||||||
{
|
{
|
||||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
{
|
{
|
||||||
using var importer = new BeatmapImporter(realmFactory, storage);
|
using var importer = new BeatmapModelManager(realm, storage);
|
||||||
using var store = new RealmRulesetStore(realmFactory, storage);
|
using var store = new RulesetStore(realm, storage);
|
||||||
|
|
||||||
string? temp = TestResources.GetTestBeatmapForImport();
|
string? temp = TestResources.GetTestBeatmapForImport();
|
||||||
await importer.Import(temp);
|
await importer.Import(temp);
|
||||||
|
|
||||||
// Update via the beatmap, not the beatmap info, to ensure correct linking
|
// Update via the beatmap, not the beatmap info, to ensure correct linking
|
||||||
RealmBeatmapSet setToUpdate = realmFactory.Context.All<RealmBeatmapSet>().First();
|
BeatmapSetInfo setToUpdate = realm.Realm.All<BeatmapSetInfo>().First();
|
||||||
|
|
||||||
var beatmapToUpdate = setToUpdate.Beatmaps.First();
|
var beatmapToUpdate = setToUpdate.Beatmaps.First();
|
||||||
|
|
||||||
realmFactory.Context.Write(() => beatmapToUpdate.DifficultyName = "updated");
|
realm.Realm.Write(() => beatmapToUpdate.DifficultyName = "updated");
|
||||||
|
|
||||||
RealmBeatmap updatedInfo = realmFactory.Context.All<RealmBeatmap>().First(b => b.ID == beatmapToUpdate.ID);
|
BeatmapInfo updatedInfo = realm.Realm.All<BeatmapInfo>().First(b => b.ID == beatmapToUpdate.ID);
|
||||||
Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated"));
|
Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<RealmBeatmapSet?> LoadQuickOszIntoOsu(BeatmapImporter importer, Realm realm)
|
public static async Task<BeatmapSetInfo?> LoadQuickOszIntoOsu(BeatmapImporter importer, Realm realm)
|
||||||
{
|
{
|
||||||
string? temp = TestResources.GetQuickTestBeatmapForImport();
|
string? temp = TestResources.GetQuickTestBeatmapForImport();
|
||||||
|
|
||||||
@ -771,14 +905,14 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
Assert.NotNull(importedSet);
|
Assert.NotNull(importedSet);
|
||||||
|
|
||||||
ensureLoaded(realm);
|
EnsureLoaded(realm);
|
||||||
|
|
||||||
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||||
|
|
||||||
return realm.All<RealmBeatmapSet>().FirstOrDefault(beatmapSet => beatmapSet.ID == importedSet!.ID);
|
return realm.All<BeatmapSetInfo>().FirstOrDefault(beatmapSet => beatmapSet.ID == importedSet!.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<RealmBeatmapSet> LoadOszIntoStore(BeatmapImporter importer, Realm realm, string? path = null, bool virtualTrack = false)
|
public static async Task<BeatmapSetInfo> LoadOszIntoStore(BeatmapImporter importer, Realm realm, string? path = null, bool virtualTrack = false)
|
||||||
{
|
{
|
||||||
string? temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
string? temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||||
|
|
||||||
@ -787,24 +921,24 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.NotNull(importedSet);
|
Assert.NotNull(importedSet);
|
||||||
Debug.Assert(importedSet != null);
|
Debug.Assert(importedSet != null);
|
||||||
|
|
||||||
ensureLoaded(realm);
|
EnsureLoaded(realm);
|
||||||
|
|
||||||
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||||
|
|
||||||
return realm.All<RealmBeatmapSet>().First(beatmapSet => beatmapSet.ID == importedSet.ID);
|
return realm.All<BeatmapSetInfo>().First(beatmapSet => beatmapSet.ID == importedSet.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteBeatmapSet(RealmBeatmapSet imported, Realm realm)
|
private void deleteBeatmapSet(BeatmapSetInfo imported, Realm realm)
|
||||||
{
|
{
|
||||||
realm.Write(() => imported.DeletePending = true);
|
realm.Write(() => imported.DeletePending = true);
|
||||||
|
|
||||||
checkBeatmapSetCount(realm, 0);
|
checkBeatmapSetCount(realm, 0);
|
||||||
checkBeatmapSetCount(realm, 1, true);
|
checkBeatmapSetCount(realm, 1, true);
|
||||||
|
|
||||||
Assert.IsTrue(realm.All<RealmBeatmapSet>().First(_ => true).DeletePending);
|
Assert.IsTrue(realm.All<BeatmapSetInfo>().First(_ => true).DeletePending);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task createScoreForBeatmap(Realm realm, RealmBeatmap beatmap)
|
private static Task createScoreForBeatmap(Realm realm, BeatmapInfo beatmap)
|
||||||
{
|
{
|
||||||
// TODO: reimplement when we have score support in realm.
|
// TODO: reimplement when we have score support in realm.
|
||||||
// return ImportScoreTest.LoadScoreIntoOsu(osu, new ScoreInfo
|
// return ImportScoreTest.LoadScoreIntoOsu(osu, new ScoreInfo
|
||||||
@ -820,8 +954,8 @@ namespace osu.Game.Tests.Database
|
|||||||
private static void checkBeatmapSetCount(Realm realm, int expected, bool includeDeletePending = false)
|
private static void checkBeatmapSetCount(Realm realm, int expected, bool includeDeletePending = false)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(expected, includeDeletePending
|
Assert.AreEqual(expected, includeDeletePending
|
||||||
? realm.All<RealmBeatmapSet>().Count()
|
? realm.All<BeatmapSetInfo>().Count()
|
||||||
: realm.All<RealmBeatmapSet>().Count(s => !s.DeletePending));
|
: realm.All<BeatmapSetInfo>().Count(s => !s.DeletePending));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string hashFile(string filename)
|
private static string hashFile(string filename)
|
||||||
@ -832,7 +966,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
private static void checkBeatmapCount(Realm realm, int expected)
|
private static void checkBeatmapCount(Realm realm, int expected)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(expected, realm.All<RealmBeatmap>().Where(_ => true).ToList().Count);
|
Assert.AreEqual(expected, realm.All<BeatmapInfo>().Where(_ => true).ToList().Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkSingleReferencedFileCount(Realm realm, int expected)
|
private static void checkSingleReferencedFileCount(Realm realm, int expected)
|
||||||
@ -848,26 +982,25 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.AreEqual(expected, singleReferencedCount);
|
Assert.AreEqual(expected, singleReferencedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureLoaded(Realm realm, int timeout = 60000)
|
internal static void EnsureLoaded(Realm realm, int timeout = 60000)
|
||||||
{
|
{
|
||||||
IQueryable<RealmBeatmapSet>? resultSets = null;
|
IQueryable<BeatmapSetInfo>? resultSets = null;
|
||||||
|
|
||||||
waitForOrAssert(() =>
|
waitForOrAssert(() =>
|
||||||
{
|
{
|
||||||
realm.Refresh();
|
realm.Refresh();
|
||||||
return (resultSets = realm.All<RealmBeatmapSet>().Where(s => !s.DeletePending && s.OnlineID == 241526)).Any();
|
return (resultSets = realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending && s.OnlineID == 241526)).Any();
|
||||||
},
|
}, @"BeatmapSet did not import to the database in allocated time.", timeout);
|
||||||
@"BeatmapSet did not import to the database in allocated time.", timeout);
|
|
||||||
|
|
||||||
// ensure we were stored to beatmap database backing...
|
// ensure we were stored to beatmap database backing...
|
||||||
Assert.IsTrue(resultSets?.Count() == 1, $@"Incorrect result count found ({resultSets?.Count()} but should be 1).");
|
Assert.IsTrue(resultSets?.Count() == 1, $@"Incorrect result count found ({resultSets?.Count()} but should be 1).");
|
||||||
|
|
||||||
IEnumerable<RealmBeatmapSet> queryBeatmapSets() => realm.All<RealmBeatmapSet>().Where(s => !s.DeletePending && s.OnlineID == 241526);
|
IEnumerable<BeatmapSetInfo> queryBeatmapSets() => realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending && s.OnlineID == 241526);
|
||||||
|
|
||||||
var set = queryBeatmapSets().First();
|
var set = queryBeatmapSets().First();
|
||||||
|
|
||||||
// ReSharper disable once PossibleUnintendedReferenceComparison
|
// ReSharper disable once PossibleUnintendedReferenceComparison
|
||||||
IEnumerable<RealmBeatmap> queryBeatmaps() => realm.All<RealmBeatmap>().Where(s => s.BeatmapSet != null && s.BeatmapSet == set);
|
IEnumerable<BeatmapInfo> queryBeatmaps() => realm.All<BeatmapInfo>().Where(s => s.BeatmapSet != null && s.BeatmapSet == set);
|
||||||
|
|
||||||
Assert.AreEqual(12, queryBeatmaps().Count(), @"Beatmap count was not correct");
|
Assert.AreEqual(12, queryBeatmaps().Count(), @"Beatmap count was not correct");
|
||||||
Assert.AreEqual(1, queryBeatmapSets().Count(), @"Beatmapset count was not correct");
|
Assert.AreEqual(1, queryBeatmapSets().Count(), @"Beatmapset count was not correct");
|
||||||
@ -880,7 +1013,7 @@ namespace osu.Game.Tests.Database
|
|||||||
countBeatmaps = queryBeatmaps().Count(),
|
countBeatmaps = queryBeatmaps().Count(),
|
||||||
$@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps}).");
|
$@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps}).");
|
||||||
|
|
||||||
foreach (RealmBeatmap b in set.Beatmaps)
|
foreach (BeatmapInfo b in set.Beatmaps)
|
||||||
Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
|
Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
|
||||||
Assert.IsTrue(set.Beatmaps.Count > 0);
|
Assert.IsTrue(set.Beatmaps.Count > 0);
|
||||||
}
|
}
|
||||||
@ -903,8 +1036,8 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
public class NonOptimisedBeatmapImporter : BeatmapImporter
|
public class NonOptimisedBeatmapImporter : BeatmapImporter
|
||||||
{
|
{
|
||||||
public NonOptimisedBeatmapImporter(RealmContextFactory realmFactory, Storage storage)
|
public NonOptimisedBeatmapImporter(RealmAccess realm, Storage storage)
|
||||||
: base(realmFactory, storage)
|
: base(realm, storage)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,10 +19,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportFile()
|
public void TestImportFile()
|
||||||
{
|
{
|
||||||
RunTestWithRealm((realmFactory, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmFactory.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmFactory, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
||||||
|
|
||||||
@ -36,10 +36,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestImportSameFileTwice()
|
public void TestImportSameFileTwice()
|
||||||
{
|
{
|
||||||
RunTestWithRealm((realmFactory, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmFactory.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmFactory, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
||||||
|
|
||||||
@ -53,10 +53,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDontPurgeReferenced()
|
public void TestDontPurgeReferenced()
|
||||||
{
|
{
|
||||||
RunTestWithRealm((realmFactory, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmFactory.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmFactory, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
||||||
|
|
||||||
@ -92,10 +92,10 @@ namespace osu.Game.Tests.Database
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPurgeUnreferenced()
|
public void TestPurgeUnreferenced()
|
||||||
{
|
{
|
||||||
RunTestWithRealm((realmFactory, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmFactory.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmFactory, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user