mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 17:17:24 +08:00
Merge branch 'master' into abstract-blueprint-handling
This commit is contained in:
commit
5b009c21bb
46
.github/dependabot.yml
vendored
Normal file
46
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: nuget
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: monthly
|
||||||
|
time: "17:00"
|
||||||
|
open-pull-requests-limit: 99
|
||||||
|
ignore:
|
||||||
|
- dependency-name: Microsoft.EntityFrameworkCore.Design
|
||||||
|
versions:
|
||||||
|
- "> 2.2.6"
|
||||||
|
- dependency-name: Microsoft.EntityFrameworkCore.Sqlite
|
||||||
|
versions:
|
||||||
|
- "> 2.2.6"
|
||||||
|
- dependency-name: Microsoft.EntityFrameworkCore.Sqlite.Core
|
||||||
|
versions:
|
||||||
|
- "> 2.2.6"
|
||||||
|
- dependency-name: Microsoft.Extensions.DependencyInjection
|
||||||
|
versions:
|
||||||
|
- ">= 5.a, < 6"
|
||||||
|
- dependency-name: NUnit3TestAdapter
|
||||||
|
versions:
|
||||||
|
- ">= 3.16.a, < 3.17"
|
||||||
|
- dependency-name: Microsoft.NET.Test.Sdk
|
||||||
|
versions:
|
||||||
|
- 16.9.1
|
||||||
|
- dependency-name: Microsoft.Extensions.DependencyInjection
|
||||||
|
versions:
|
||||||
|
- 3.1.11
|
||||||
|
- 3.1.12
|
||||||
|
- dependency-name: Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson
|
||||||
|
versions:
|
||||||
|
- 3.1.11
|
||||||
|
- dependency-name: Microsoft.NETCore.Targets
|
||||||
|
versions:
|
||||||
|
- 5.0.0
|
||||||
|
- dependency-name: Microsoft.AspNetCore.SignalR.Protocols.MessagePack
|
||||||
|
versions:
|
||||||
|
- 5.0.2
|
||||||
|
- dependency-name: NUnit
|
||||||
|
versions:
|
||||||
|
- 3.13.1
|
||||||
|
- dependency-name: Microsoft.AspNetCore.SignalR.Client
|
||||||
|
versions:
|
||||||
|
- 3.1.11
|
@ -11,7 +11,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.424.1" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.427.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -9,6 +9,7 @@ using System.Reflection;
|
|||||||
using System.Runtime.Versioning;
|
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.Overlays;
|
using osu.Desktop.Overlays;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game;
|
using osu.Game;
|
||||||
@ -113,6 +114,8 @@ namespace osu.Desktop
|
|||||||
|
|
||||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||||
LoadComponentAsync(new GameplayWinKeyBlocker(), Add);
|
LoadComponentAsync(new GameplayWinKeyBlocker(), Add);
|
||||||
|
|
||||||
|
LoadComponentAsync(new ElevatedPrivilegesChecker(), Add);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
|
protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
|
||||||
|
83
osu.Desktop/Security/ElevatedPrivilegesChecker.cs
Normal file
83
osu.Desktop/Security/ElevatedPrivilegesChecker.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.Security.Principal;
|
||||||
|
using osu.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
|
||||||
|
namespace osu.Desktop.Security
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the game is running with elevated privileges (as admin in Windows, root in Unix) and displays a warning notification if so.
|
||||||
|
/// </summary>
|
||||||
|
public class ElevatedPrivilegesChecker : Component
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private NotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
|
private bool elevated;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
elevated = checkElevated();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
if (elevated)
|
||||||
|
notifications.Post(new ElevatedPrivilegesNotification());
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkElevated()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (RuntimeInfo.OS)
|
||||||
|
{
|
||||||
|
case RuntimeInfo.Platform.Windows:
|
||||||
|
if (!OperatingSystem.IsWindows()) return false;
|
||||||
|
|
||||||
|
var windowsIdentity = WindowsIdentity.GetCurrent();
|
||||||
|
var windowsPrincipal = new WindowsPrincipal(windowsIdentity);
|
||||||
|
|
||||||
|
return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
|
|
||||||
|
case RuntimeInfo.Platform.macOS:
|
||||||
|
case RuntimeInfo.Platform.Linux:
|
||||||
|
return Mono.Unix.Native.Syscall.geteuid() == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ElevatedPrivilegesNotification : SimpleNotification
|
||||||
|
{
|
||||||
|
public override bool IsImportant => true;
|
||||||
|
|
||||||
|
public ElevatedPrivilegesNotification()
|
||||||
|
{
|
||||||
|
Text = $"Running osu! as {(RuntimeInfo.IsUnix ? "root" : "administrator")} does not improve performance, may break integrations and poses a security risk. Please run the game as a normal user.";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, NotificationOverlay notificationOverlay)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.ShieldAlt;
|
||||||
|
IconBackgound.Colour = colours.YellowDark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||||
<PackageReference Include="System.IO.Packaging" Version="5.0.0" />
|
<PackageReference Include="System.IO.Packaging" Version="5.0.0" />
|
||||||
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.5" />
|
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
|
||||||
<PackageReference Include="nunit" Version="3.13.1" />
|
<PackageReference Include="nunit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
94
osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs
Normal file
94
osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// 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.Testing;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Gameplay
|
||||||
|
{
|
||||||
|
[HeadlessTest]
|
||||||
|
public class TestSceneDrawableHitObject : OsuTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestEntryLifetime()
|
||||||
|
{
|
||||||
|
TestDrawableHitObject dho = null;
|
||||||
|
var initialHitObject = new HitObject
|
||||||
|
{
|
||||||
|
StartTime = 1000
|
||||||
|
};
|
||||||
|
var entry = new TestLifetimeEntry(new HitObject
|
||||||
|
{
|
||||||
|
StartTime = 2000
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("Create DHO", () => Child = dho = new TestDrawableHitObject(initialHitObject));
|
||||||
|
|
||||||
|
AddAssert("Correct initial lifetime", () => dho.LifetimeStart == initialHitObject.StartTime - TestDrawableHitObject.INITIAL_LIFETIME_OFFSET);
|
||||||
|
|
||||||
|
AddStep("Apply entry", () => dho.Apply(entry));
|
||||||
|
|
||||||
|
AddAssert("Correct initial lifetime", () => dho.LifetimeStart == entry.HitObject.StartTime - TestLifetimeEntry.INITIAL_LIFETIME_OFFSET);
|
||||||
|
|
||||||
|
AddStep("Set lifetime", () => dho.LifetimeEnd = 3000);
|
||||||
|
AddAssert("Entry lifetime is updated", () => entry.LifetimeEnd == 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeepAlive()
|
||||||
|
{
|
||||||
|
TestDrawableHitObject dho = null;
|
||||||
|
TestLifetimeEntry entry = null;
|
||||||
|
AddStep("Create DHO", () =>
|
||||||
|
{
|
||||||
|
dho = new TestDrawableHitObject(null);
|
||||||
|
dho.Apply(entry = new TestLifetimeEntry(new HitObject())
|
||||||
|
{
|
||||||
|
LifetimeStart = 0,
|
||||||
|
LifetimeEnd = 1000,
|
||||||
|
});
|
||||||
|
Child = dho;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("KeepAlive = true", () => entry.KeepAlive = true);
|
||||||
|
AddAssert("Lifetime is overriden", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == double.MaxValue);
|
||||||
|
|
||||||
|
AddStep("Set LifetimeStart", () => dho.LifetimeStart = 500);
|
||||||
|
AddStep("KeepAlive = false", () => entry.KeepAlive = false);
|
||||||
|
AddAssert("Lifetime is correct", () => entry.LifetimeStart == 500 && entry.LifetimeEnd == 1000);
|
||||||
|
|
||||||
|
AddStep("Set LifetimeStart while KeepAlive", () =>
|
||||||
|
{
|
||||||
|
entry.KeepAlive = true;
|
||||||
|
dho.LifetimeStart = double.MinValue;
|
||||||
|
entry.KeepAlive = false;
|
||||||
|
});
|
||||||
|
AddAssert("Lifetime is changed", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawableHitObject : DrawableHitObject
|
||||||
|
{
|
||||||
|
public const double INITIAL_LIFETIME_OFFSET = 100;
|
||||||
|
protected override double InitialLifetimeOffset => INITIAL_LIFETIME_OFFSET;
|
||||||
|
|
||||||
|
public TestDrawableHitObject(HitObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestLifetimeEntry : HitObjectLifetimeEntry
|
||||||
|
{
|
||||||
|
public const double INITIAL_LIFETIME_OFFSET = 200;
|
||||||
|
protected override double InitialLifetimeOffset => INITIAL_LIFETIME_OFFSET;
|
||||||
|
|
||||||
|
public TestLifetimeEntry(HitObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Overlays.Settings;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Mods
|
namespace osu.Game.Tests.Mods
|
||||||
{
|
{
|
||||||
@ -26,6 +29,16 @@ namespace osu.Game.Tests.Mods
|
|||||||
Assert.That(orderedSettings[3].Item2.Name, Is.EqualTo(nameof(ClassWithSettings.UnorderedSetting)));
|
Assert.That(orderedSettings[3].Item2.Name, Is.EqualTo(nameof(ClassWithSettings.UnorderedSetting)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCustomControl()
|
||||||
|
{
|
||||||
|
var objectWithCustomSettingControl = new ClassWithCustomSettingControl();
|
||||||
|
var settings = objectWithCustomSettingControl.CreateSettingsControls().ToArray();
|
||||||
|
|
||||||
|
Assert.That(settings, Has.Length.EqualTo(1));
|
||||||
|
Assert.That(settings[0], Is.TypeOf<CustomSettingsControl>());
|
||||||
|
}
|
||||||
|
|
||||||
private class ClassWithSettings
|
private class ClassWithSettings
|
||||||
{
|
{
|
||||||
[SettingSource("Unordered setting", "Should be last")]
|
[SettingSource("Unordered setting", "Should be last")]
|
||||||
@ -40,5 +53,21 @@ namespace osu.Game.Tests.Mods
|
|||||||
[SettingSource("Third setting", "Yet another description", 3)]
|
[SettingSource("Third setting", "Yet another description", 3)]
|
||||||
public BindableInt ThirdSetting { get; set; } = new BindableInt();
|
public BindableInt ThirdSetting { get; set; } = new BindableInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ClassWithCustomSettingControl
|
||||||
|
{
|
||||||
|
[SettingSource("Custom setting", "Should be a custom control", SettingControlType = typeof(CustomSettingsControl))]
|
||||||
|
public BindableInt UnorderedSetting { get; set; } = new BindableInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CustomSettingsControl : SettingsItem<int>
|
||||||
|
{
|
||||||
|
protected override Drawable CreateControl() => new CustomControl();
|
||||||
|
|
||||||
|
private class CustomControl : Drawable, IHasCurrentValue<int>
|
||||||
|
{
|
||||||
|
public Bindable<int> Current { get; set; } = new Bindable<int>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -51,7 +50,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
};
|
};
|
||||||
scoreProcessor.ApplyResult(judgementResult);
|
scoreProcessor.ApplyResult(judgementResult);
|
||||||
|
|
||||||
Assert.IsTrue(Precision.AlmostEquals(expectedScore, scoreProcessor.TotalScore.Value));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(expectedScore).Within(0.5d));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -84,8 +83,8 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, HitResult.SmallTickHit, 925_000)] // (3 * 10) / (4 * 10) * 300_000 + 700_000 (max combo 0)
|
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, HitResult.SmallTickHit, 925_000)] // (3 * 10) / (4 * 10) * 300_000 + 700_000 (max combo 0)
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] // (3 * 0) / (4 * 30) * 300_000 + (0 / 4) * 700_000
|
[TestCase(ScoringMode.Standardised, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] // (3 * 0) / (4 * 30) * 300_000 + (0 / 4) * 700_000
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 575_000)] // (3 * 30) / (4 * 30) * 300_000 + (0 / 4) * 700_000
|
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 575_000)] // (3 * 30) / (4 * 30) * 300_000 + (0 / 4) * 700_000
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 700_030)] // 0 * 300_000 + 700_000 (max combo 0) + 3 * 10 (bonus points)
|
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 10 (bonus points)
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 700_150)] // 0 * 300_000 + 700_000 (max combo 0) + 3 * 50 (bonus points)
|
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 50 (bonus points)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)] // (0 * 4 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)] // (0 * 4 * 300) * (1 + 0 / 25)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 156)] // (((3 * 50) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 156)] // (((3 * 50) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 312)] // (((3 * 100) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 312)] // (((3 * 100) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
||||||
@ -96,8 +95,9 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 225)] // (((3 * 10) / (4 * 10)) * 1 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 225)] // (((3 * 10) / (4 * 10)) * 1 * 300) * (1 + 0 / 25)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] // (0 * 4 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] // (0 * 4 * 300) * (1 + 0 / 25)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 936)] // (((3 * 50) / (4 * 50)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 936)] // (((3 * 50) / (4 * 50)) * 4 * 300) * (1 + 1 / 25)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 30)] // (0 * 1 * 300) * (1 + 0 / 25) + 3 * 10 (bonus points)
|
// TODO: The following two cases don't match expectations currently (a single hit is registered in acc portion when it shouldn't be). See https://github.com/ppy/osu/issues/12604.
|
||||||
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 150)] // (0 * 1 * 300) * (1 + 0 / 25) * 3 * 50 (bonus points)
|
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 330)] // (1 * 1 * 300) * (1 + 0 / 25) + 3 * 10 (bonus points)
|
||||||
|
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 450)] // (1 * 1 * 300) * (1 + 0 / 25) + 3 * 50 (bonus points)
|
||||||
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
|
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
|
||||||
{
|
{
|
||||||
var minResult = new TestJudgement(hitResult).MinResult;
|
var minResult = new TestJudgement(hitResult).MinResult;
|
||||||
@ -118,7 +118,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
scoreProcessor.ApplyResult(judgementResult);
|
scoreProcessor.ApplyResult(judgementResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.IsTrue(Precision.AlmostEquals(expectedScore, scoreProcessor.TotalScore.Value, 0.5));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(expectedScore).Within(0.5d));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
@ -158,7 +158,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
};
|
};
|
||||||
scoreProcessor.ApplyResult(lastJudgementResult);
|
scoreProcessor.ApplyResult(lastJudgementResult);
|
||||||
|
|
||||||
Assert.IsTrue(Precision.AlmostEquals(expectedScore, scoreProcessor.TotalScore.Value, 0.5));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(expectedScore).Within(0.5d));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -169,7 +169,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
scoreProcessor.Mode.Value = scoringMode;
|
scoreProcessor.Mode.Value = scoringMode;
|
||||||
scoreProcessor.ApplyBeatmap(new TestBeatmap(new RulesetInfo()));
|
scoreProcessor.ApplyBeatmap(new TestBeatmap(new RulesetInfo()));
|
||||||
|
|
||||||
Assert.IsTrue(Precision.AlmostEquals(0, scoreProcessor.TotalScore.Value));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(HitResult.IgnoreHit, HitResult.IgnoreMiss)]
|
[TestCase(HitResult.IgnoreHit, HitResult.IgnoreMiss)]
|
||||||
@ -287,6 +287,23 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
Assert.AreEqual(expectedReturnValue, hitResult.IsScorable());
|
Assert.AreEqual(expectedReturnValue, hitResult.IsScorable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(HitResult.Perfect, 1_000_000)]
|
||||||
|
[TestCase(HitResult.SmallTickHit, 1_000_000)]
|
||||||
|
[TestCase(HitResult.LargeTickHit, 1_000_000)]
|
||||||
|
[TestCase(HitResult.SmallBonus, 1_000_000 + Judgement.SMALL_BONUS_SCORE)]
|
||||||
|
[TestCase(HitResult.LargeBonus, 1_000_000 + Judgement.LARGE_BONUS_SCORE)]
|
||||||
|
public void TestGetScoreWithExternalStatistics(HitResult result, int expectedScore)
|
||||||
|
{
|
||||||
|
var statistic = new Dictionary<HitResult, int> { { result, 1 } };
|
||||||
|
|
||||||
|
scoreProcessor.ApplyBeatmap(new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = { new TestHitObject(result) }
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(scoreProcessor.GetImmediateScore(ScoringMode.Standardised, result.AffectsCombo() ? 1 : 0, statistic), Is.EqualTo(expectedScore).Within(0.5d));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestJudgement : Judgement
|
private class TestJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override HitResult MaxResult { get; }
|
public override HitResult MaxResult { get; }
|
||||||
|
@ -43,7 +43,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
createButtonWithBeatmap(createSoleily());
|
createButtonWithBeatmap(createSoleily());
|
||||||
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
|
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
|
||||||
AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()));
|
AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()));
|
||||||
|
|
||||||
AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
|
AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
|
||||||
|
AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
|
||||||
|
|
||||||
createButtonWithBeatmap(createSoleily());
|
createButtonWithBeatmap(createSoleily());
|
||||||
AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
|
AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
|
||||||
ensureSoleilyRemoved();
|
ensureSoleilyRemoved();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
// 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;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
@ -31,7 +34,15 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
public int? OrderPosition { get; }
|
public int? OrderPosition { get; }
|
||||||
|
|
||||||
public SettingSourceAttribute(string label, string description = null)
|
/// <summary>
|
||||||
|
/// The type of the settings control which handles this setting source.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Must be a type deriving <see cref="SettingsItem{T}"/> with a public parameterless constructor.
|
||||||
|
/// </remarks>
|
||||||
|
public Type? SettingControlType { get; set; }
|
||||||
|
|
||||||
|
public SettingSourceAttribute(string? label, string? description = null)
|
||||||
{
|
{
|
||||||
Label = label ?? string.Empty;
|
Label = label ?? string.Empty;
|
||||||
Description = description ?? string.Empty;
|
Description = description ?? string.Empty;
|
||||||
@ -67,6 +78,22 @@ namespace osu.Game.Configuration
|
|||||||
{
|
{
|
||||||
object value = property.GetValue(obj);
|
object value = property.GetValue(obj);
|
||||||
|
|
||||||
|
if (attr.SettingControlType != null)
|
||||||
|
{
|
||||||
|
var controlType = attr.SettingControlType;
|
||||||
|
if (controlType.EnumerateBaseTypes().All(t => !t.IsGenericType || t.GetGenericTypeDefinition() != typeof(SettingsItem<>)))
|
||||||
|
throw new InvalidOperationException($"{nameof(SettingSourceAttribute)} had an unsupported custom control type ({controlType.ReadableName()})");
|
||||||
|
|
||||||
|
var control = (Drawable)Activator.CreateInstance(controlType);
|
||||||
|
controlType.GetProperty(nameof(SettingsItem<object>.LabelText))?.SetValue(control, attr.Label);
|
||||||
|
controlType.GetProperty(nameof(SettingsItem<object>.TooltipText))?.SetValue(control, attr.Description);
|
||||||
|
controlType.GetProperty(nameof(SettingsItem<object>.Current))?.SetValue(control, value);
|
||||||
|
|
||||||
|
yield return control;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case BindableNumber<float> bNumber:
|
case BindableNumber<float> bNumber:
|
||||||
|
@ -156,6 +156,8 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
bool isLowPriorityImport = tasks.Length > low_priority_import_batch_size;
|
bool isLowPriorityImport = tasks.Length > low_priority_import_batch_size;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
await Task.WhenAll(tasks.Select(async task =>
|
await Task.WhenAll(tasks.Select(async task =>
|
||||||
{
|
{
|
||||||
notification.CancellationToken.ThrowIfCancellationRequested();
|
notification.CancellationToken.ThrowIfCancellationRequested();
|
||||||
@ -183,6 +185,15 @@ namespace osu.Game.Database
|
|||||||
Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database);
|
Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database);
|
||||||
}
|
}
|
||||||
})).ConfigureAwait(false);
|
})).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
if (imported.Count == 0)
|
||||||
|
{
|
||||||
|
notification.State = ProgressNotificationState.Cancelled;
|
||||||
|
return imported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (imported.Count == 0)
|
if (imported.Count == 0)
|
||||||
{
|
{
|
||||||
@ -422,16 +433,26 @@ namespace osu.Game.Database
|
|||||||
if (retrievedItem == null)
|
if (retrievedItem == null)
|
||||||
throw new ArgumentException("Specified model could not be found", nameof(item));
|
throw new ArgumentException("Specified model could not be found", nameof(item));
|
||||||
|
|
||||||
using (var archive = ZipArchive.Create())
|
|
||||||
{
|
|
||||||
foreach (var file in retrievedItem.Files)
|
|
||||||
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
|
|
||||||
|
|
||||||
using (var outputStream = exportStorage.GetStream($"{getValidFilename(item.ToString())}{HandledExtensions.First()}", FileAccess.Write, FileMode.Create))
|
using (var outputStream = exportStorage.GetStream($"{getValidFilename(item.ToString())}{HandledExtensions.First()}", FileAccess.Write, FileMode.Create))
|
||||||
archive.SaveTo(outputStream);
|
ExportModelTo(retrievedItem, outputStream);
|
||||||
|
|
||||||
exportStorage.OpenInNativeExplorer();
|
exportStorage.OpenInNativeExplorer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exports an item to the given output stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The item to export.</param>
|
||||||
|
/// <param name="outputStream">The output stream to export to.</param>
|
||||||
|
protected virtual void ExportModelTo(TModel model, Stream outputStream)
|
||||||
|
{
|
||||||
|
using (var archive = ZipArchive.Create())
|
||||||
|
{
|
||||||
|
foreach (var file in model.Files)
|
||||||
|
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
|
||||||
|
|
||||||
|
archive.SaveTo(outputStream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -11,16 +11,17 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Performance;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Pooling;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Objects.Pooling;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Drawables
|
namespace osu.Game.Rulesets.Objects.Drawables
|
||||||
@ -429,9 +430,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
base.ClearTransformsAfter(double.MinValue, true);
|
base.ClearTransformsAfter(double.MinValue, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reapplies the current <see cref="ArmedState"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected void RefreshStateTransforms() => updateState(State.Value, true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply (generally fade-in) transforms leading into the <see cref="HitObject"/> start time.
|
/// Apply (generally fade-in) transforms leading into the <see cref="HitObject"/> start time.
|
||||||
/// The local drawable hierarchy is recursively delayed to <see cref="HitObjectLifetimeEntry.LifetimeStart"/> for convenience.
|
/// The local drawable hierarchy is recursively delayed to <see cref="LifetimeEntry.LifetimeStart"/> for convenience.
|
||||||
///
|
///
|
||||||
/// By default this will fade in the object from zero with no duration.
|
/// By default this will fade in the object from zero with no duration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -613,7 +619,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This is only used as an optimisation to delay the initial update of this <see cref="DrawableHitObject"/> and may be tuned more aggressively if required.
|
/// This is only used as an optimisation to delay the initial update of this <see cref="DrawableHitObject"/> and may be tuned more aggressively if required.
|
||||||
/// It is indirectly used to decide the automatic transform offset provided to <see cref="UpdateInitialTransforms"/>.
|
/// It is indirectly used to decide the automatic transform offset provided to <see cref="UpdateInitialTransforms"/>.
|
||||||
/// A more accurate <see cref="HitObjectLifetimeEntry.LifetimeStart"/> should be set for further optimisation (in <see cref="LoadComplete"/>, for example).
|
/// A more accurate <see cref="LifetimeEntry.LifetimeStart"/> should be set for further optimisation (in <see cref="LoadComplete"/>, for example).
|
||||||
/// <para>
|
/// <para>
|
||||||
/// Only has an effect if this <see cref="DrawableHitObject"/> is not being pooled.
|
/// Only has an effect if this <see cref="DrawableHitObject"/> is not being pooled.
|
||||||
/// For pooled <see cref="DrawableHitObject"/>s, use <see cref="HitObjectLifetimeEntry.InitialLifetimeOffset"/> instead.
|
/// For pooled <see cref="DrawableHitObject"/>s, use <see cref="HitObjectLifetimeEntry.InitialLifetimeOffset"/> instead.
|
||||||
|
@ -38,40 +38,23 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
startTimeBindable.BindValueChanged(onStartTimeChanged, true);
|
startTimeBindable.BindValueChanged(onStartTimeChanged, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The lifetime start, as set by the hitobject.
|
// The lifetime, as set by the hitobject.
|
||||||
private double realLifetimeStart = double.MinValue;
|
private double realLifetimeStart = double.MinValue;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The time at which the <see cref="HitObject"/> should become alive.
|
|
||||||
/// </summary>
|
|
||||||
public new double LifetimeStart
|
|
||||||
{
|
|
||||||
get => realLifetimeStart;
|
|
||||||
set => setLifetime(realLifetimeStart = value, LifetimeEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The lifetime end, as set by the hitobject.
|
|
||||||
private double realLifetimeEnd = double.MaxValue;
|
private double realLifetimeEnd = double.MaxValue;
|
||||||
|
|
||||||
/// <summary>
|
// This method is called even if `start == LifetimeStart` when `KeepAlive` is true (necessary to update `realLifetimeStart`).
|
||||||
/// The time at which the <see cref="HitObject"/> should become dead.
|
protected override void SetLifetimeStart(double start)
|
||||||
/// </summary>
|
|
||||||
public new double LifetimeEnd
|
|
||||||
{
|
{
|
||||||
get => realLifetimeEnd;
|
realLifetimeStart = start;
|
||||||
set => setLifetime(LifetimeStart, realLifetimeEnd = value);
|
if (!keepAlive)
|
||||||
|
base.SetLifetimeStart(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setLifetime(double start, double end)
|
protected override void SetLifetimeEnd(double end)
|
||||||
{
|
{
|
||||||
if (keepAlive)
|
realLifetimeEnd = end;
|
||||||
{
|
if (!keepAlive)
|
||||||
start = double.MinValue;
|
base.SetLifetimeEnd(end);
|
||||||
end = double.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.LifetimeStart = start;
|
|
||||||
base.LifetimeEnd = end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool keepAlive;
|
private bool keepAlive;
|
||||||
@ -87,7 +70,10 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
keepAlive = value;
|
keepAlive = value;
|
||||||
setLifetime(realLifetimeStart, realLifetimeEnd);
|
if (keepAlive)
|
||||||
|
SetLifetime(double.MinValue, double.MaxValue);
|
||||||
|
else
|
||||||
|
SetLifetime(realLifetimeStart, realLifetimeEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,12 +84,12 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This is only used as an optimisation to delay the initial update of the <see cref="HitObject"/> and may be tuned more aggressively if required.
|
/// This is only used as an optimisation to delay the initial update of the <see cref="HitObject"/> and may be tuned more aggressively if required.
|
||||||
/// It is indirectly used to decide the automatic transform offset provided to <see cref="DrawableHitObject.UpdateInitialTransforms"/>.
|
/// It is indirectly used to decide the automatic transform offset provided to <see cref="DrawableHitObject.UpdateInitialTransforms"/>.
|
||||||
/// A more accurate <see cref="LifetimeStart"/> should be set for further optimisation (in <see cref="DrawableHitObject.LoadComplete"/>, for example).
|
/// A more accurate <see cref="LifetimeEntry.LifetimeStart"/> should be set for further optimisation (in <see cref="DrawableHitObject.LoadComplete"/>, for example).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected virtual double InitialLifetimeOffset => 10000;
|
protected virtual double InitialLifetimeOffset => 10000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets <see cref="LifetimeStart"/> according to the change in start time of the <see cref="HitObject"/>.
|
/// Resets <see cref="LifetimeEntry.LifetimeStart"/> according to the change in start time of the <see cref="HitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void onStartTimeChanged(ValueChangedEvent<double> startTime) => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset;
|
private void onStartTimeChanged(ValueChangedEvent<double> startTime) => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value;
|
computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetScore(mode, maxAchievableCombo, calculateAccuracyRatio(computedBaseScore), calculateComboRatio(maxCombo), scoreResultCounts);
|
return GetScore(mode, maxAchievableCombo, calculateAccuracyRatio(computedBaseScore), calculateComboRatio(maxCombo), statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -266,7 +266,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
if (preferRolling && rollingMaxBaseScore != 0)
|
if (preferRolling && rollingMaxBaseScore != 0)
|
||||||
return baseScore / rollingMaxBaseScore;
|
return baseScore / rollingMaxBaseScore;
|
||||||
|
|
||||||
return maxBaseScore > 0 ? baseScore / maxBaseScore : 0;
|
return maxBaseScore > 0 ? baseScore / maxBaseScore : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateComboRatio(int maxCombo) => maxAchievableCombo > 0 ? (double)maxCombo / maxAchievableCombo : 1;
|
private double calculateComboRatio(int maxCombo) => maxAchievableCombo > 0 ? (double)maxCombo / maxAchievableCombo : 1;
|
||||||
|
@ -95,7 +95,7 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
|
|
||||||
foreach (var f in score.Replay.Frames.OfType<IConvertibleReplayFrame>().Select(f => f.ToLegacy(beatmap)))
|
foreach (var f in score.Replay.Frames.OfType<IConvertibleReplayFrame>().Select(f => f.ToLegacy(beatmap)))
|
||||||
{
|
{
|
||||||
replayData.Append(FormattableString.Invariant($"{f.Time - lastF.Time}|{f.MouseX ?? 0}|{f.MouseY ?? 0}|{(int)f.ButtonState},"));
|
replayData.Append(FormattableString.Invariant($"{(int)Math.Round(f.Time - lastF.Time)}|{f.MouseX ?? 0}|{f.MouseY ?? 0}|{(int)f.ButtonState},"));
|
||||||
lastF = f;
|
lastF = f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,16 @@ namespace osu.Game.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ExportModelTo(ScoreInfo model, Stream outputStream)
|
||||||
|
{
|
||||||
|
var file = model.Files.SingleOrDefault();
|
||||||
|
if (file == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using (var inputStream = Files.Storage.GetStream(file.FileInfo.StoragePath))
|
||||||
|
inputStream.CopyTo(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<string> GetStableImportPaths(Storage storage)
|
protected override IEnumerable<string> GetStableImportPaths(Storage storage)
|
||||||
=> storage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
|
=> storage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
|
||||||
.Select(path => storage.GetFullPath(path));
|
.Select(path => storage.GetFullPath(path));
|
||||||
|
@ -19,21 +19,21 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="DiffPlex" Version="1.7.0" />
|
<PackageReference Include="DiffPlex" Version="1.7.0" />
|
||||||
<PackageReference Include="Humanizer" Version="2.8.26" />
|
<PackageReference Include="Humanizer" Version="2.9.9" />
|
||||||
<PackageReference Include="MessagePack" Version="2.2.85" />
|
<PackageReference Include="MessagePack" Version="2.2.85" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
|
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.424.1" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.427.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.2.0" />
|
<PackageReference Include="Sentry" Version="3.3.4" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.1" />
|
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.424.1" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.427.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
@ -89,13 +89,13 @@
|
|||||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<PackageReference Include="DiffPlex" Version="1.6.3" />
|
<PackageReference Include="DiffPlex" Version="1.6.3" />
|
||||||
<PackageReference Include="Humanizer" Version="2.8.26" />
|
<PackageReference Include="Humanizer" Version="2.9.9" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.424.1" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.427.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.1" />
|
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2021.115.0" ExcludeAssets="all" />
|
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2021.115.0" ExcludeAssets="all" />
|
||||||
|
Loading…
Reference in New Issue
Block a user