mirror of
https://github.com/ppy/osu.git
synced 2026-05-17 17:33:02 +08:00
Compare commits
417 Commits
@@ -15,7 +15,7 @@
|
||||
]
|
||||
},
|
||||
"jetbrains.resharper.globaltools": {
|
||||
"version": "2020.2.4",
|
||||
"version": "2020.3.2",
|
||||
"commands": [
|
||||
"jb"
|
||||
]
|
||||
|
||||
+15
-7
@@ -16,9 +16,9 @@
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Code Analysis">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.2" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.2" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Code Analysis">
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodeAnalysis\osu.ruleset</CodeAnalysisRuleSet>
|
||||
@@ -28,9 +28,17 @@
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<!-- DeepEqual is not netstandard-compatible. This is fine since we run tests with .NET Framework anyway.
|
||||
This is required due to https://github.com/NuGet/Home/issues/5740 -->
|
||||
<NoWarn>$(NoWarn);NU1701</NoWarn>
|
||||
<!--
|
||||
NU1701:
|
||||
DeepEqual is not netstandard-compatible. This is fine since we run tests with .NET Framework anyway.
|
||||
This is required due to https://github.com/NuGet/Home/issues/5740
|
||||
|
||||
CA9998:
|
||||
Microsoft.CodeAnalysis.FxCopAnalyzers has been deprecated.
|
||||
The entire package will be able to be removed after migrating to .NET 5,
|
||||
as analysers are shipped as part of the .NET 5 SDK anyway.
|
||||
-->
|
||||
<NoWarn>$(NoWarn);NU1701;CA9998</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Nuget">
|
||||
<IsPackable>false</IsPackable>
|
||||
@@ -40,7 +48,7 @@
|
||||
<RepositoryUrl>https://github.com/ppy/osu</RepositoryUrl>
|
||||
<PackageReleaseNotes>Automated release.</PackageReleaseNotes>
|
||||
<Company>ppy Pty Ltd</Company>
|
||||
<Copyright>Copyright (c) 2020 ppy Pty Ltd</Copyright>
|
||||
<Copyright>Copyright (c) 2021 ppy Pty Ltd</Copyright>
|
||||
<PackageTags>osu game</PackageTags>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2020 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Copyright (c) 2021 ppy Pty Ltd <contact@ppy.sh>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+60
-13
@@ -1,21 +1,68 @@
|
||||
clone_depth: 1
|
||||
version: '{build}'
|
||||
image: Visual Studio 2019
|
||||
dotnet_csproj:
|
||||
patch: true
|
||||
file: 'osu.Game\osu.Game.csproj' # Use wildcard when it's able to exclude Xamarin projects
|
||||
version: $(APPVEYOR_REPO_TAG_NAME)
|
||||
before_build:
|
||||
- ps: dotnet --info # Useful when version mismatch between CI and local
|
||||
- ps: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects
|
||||
test: off
|
||||
skip_non_tags: true
|
||||
configuration: Release
|
||||
build:
|
||||
project: build\Desktop.proj # Skipping Xamarin Release that's slow and covered by fastlane
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
publish_nuget: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- job_name: osu-game
|
||||
- job_name: osu-ruleset
|
||||
job_depends_on: osu-game
|
||||
- job_name: taiko-ruleset
|
||||
job_depends_on: osu-game
|
||||
- job_name: catch-ruleset
|
||||
job_depends_on: osu-game
|
||||
- job_name: mania-ruleset
|
||||
job_depends_on: osu-game
|
||||
|
||||
nuget:
|
||||
project_feed: true
|
||||
|
||||
for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- job_name: osu-game
|
||||
build_script:
|
||||
- cmd: dotnet pack osu.Game\osu.Game.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- job_name: osu-ruleset
|
||||
build_script:
|
||||
- cmd: dotnet remove osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj reference osu.Game\osu.Game.csproj
|
||||
- cmd: dotnet add osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
|
||||
- cmd: dotnet pack osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- job_name: taiko-ruleset
|
||||
build_script:
|
||||
- cmd: dotnet remove osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj reference osu.Game\osu.Game.csproj
|
||||
- cmd: dotnet add osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
|
||||
- cmd: dotnet pack osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- job_name: catch-ruleset
|
||||
build_script:
|
||||
- cmd: dotnet remove osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj reference osu.Game\osu.Game.csproj
|
||||
- cmd: dotnet add osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
|
||||
- cmd: dotnet pack osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- job_name: mania-ruleset
|
||||
build_script:
|
||||
- cmd: dotnet remove osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj reference osu.Game\osu.Game.csproj
|
||||
- cmd: dotnet add osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
|
||||
- cmd: dotnet pack osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
|
||||
|
||||
artifacts:
|
||||
- path: '**\*.nupkg'
|
||||
|
||||
deploy:
|
||||
- provider: Environment
|
||||
name: nuget
|
||||
name: nuget
|
||||
+4
-6
@@ -48,9 +48,8 @@ desc 'Deploy to play store'
|
||||
|
||||
desc 'Compile the project'
|
||||
lane :build do |options|
|
||||
nuget_restore(
|
||||
project_path: 'osu.sln'
|
||||
)
|
||||
nuget_restore(project_path: 'osu.Android/osu.Android.csproj')
|
||||
nuget_restore(project_path: 'osu.Game/osu.Game.csproj')
|
||||
|
||||
souyuz(
|
||||
build_configuration: 'Release',
|
||||
@@ -107,9 +106,8 @@ platform :ios do
|
||||
|
||||
desc 'Compile the project'
|
||||
lane :build do
|
||||
nuget_restore(
|
||||
project_path: 'osu.sln'
|
||||
)
|
||||
nuget_restore(project_path: 'osu.iOS/osu.iOS.csproj')
|
||||
nuget_restore(project_path: 'osu.Game/osu.Game.csproj')
|
||||
|
||||
souyuz(
|
||||
platform: "ios",
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"sdk": {
|
||||
"allowPrerelease": false,
|
||||
"rollForward": "minor",
|
||||
"version": "3.1.100"
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.Build.Traversal": "3.0.2"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1228.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.118.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -12,11 +13,14 @@ using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Views;
|
||||
using osu.Framework.Android;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Android
|
||||
{
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)]
|
||||
[IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream" })]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })]
|
||||
public class OsuGameActivity : AndroidGameActivity
|
||||
{
|
||||
@@ -52,43 +56,59 @@ namespace osu.Android
|
||||
{
|
||||
case Intent.ActionDefault:
|
||||
if (intent.Scheme == ContentResolver.SchemeContent)
|
||||
handleImportFromUri(intent.Data);
|
||||
handleImportFromUris(intent.Data);
|
||||
else if (osu_url_schemes.Contains(intent.Scheme))
|
||||
game.HandleLink(intent.DataString);
|
||||
break;
|
||||
|
||||
case Intent.ActionSend:
|
||||
case Intent.ActionSendMultiple:
|
||||
{
|
||||
var content = intent.ClipData?.GetItemAt(0);
|
||||
if (content != null)
|
||||
handleImportFromUri(content.Uri);
|
||||
var uris = new List<Uri>();
|
||||
for (int i = 0; i < intent.ClipData?.ItemCount; i++)
|
||||
{
|
||||
var content = intent.ClipData?.GetItemAt(i);
|
||||
if (content != null)
|
||||
uris.Add(content.Uri);
|
||||
}
|
||||
handleImportFromUris(uris.ToArray());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleImportFromUri(Uri uri) => Task.Factory.StartNew(async () =>
|
||||
private void handleImportFromUris(params Uri[] uris) => Task.Factory.StartNew(async () =>
|
||||
{
|
||||
// there are more performant overloads of this method, but this one is the most backwards-compatible
|
||||
// (dates back to API 1).
|
||||
var cursor = ContentResolver?.Query(uri, null, null, null, null);
|
||||
var tasks = new List<ImportTask>();
|
||||
|
||||
if (cursor == null)
|
||||
return;
|
||||
await Task.WhenAll(uris.Select(async uri =>
|
||||
{
|
||||
// there are more performant overloads of this method, but this one is the most backwards-compatible
|
||||
// (dates back to API 1).
|
||||
var cursor = ContentResolver?.Query(uri, null, null, null, null);
|
||||
|
||||
cursor.MoveToFirst();
|
||||
if (cursor == null)
|
||||
return;
|
||||
|
||||
var filenameColumn = cursor.GetColumnIndex(OpenableColumns.DisplayName);
|
||||
string filename = cursor.GetString(filenameColumn);
|
||||
cursor.MoveToFirst();
|
||||
|
||||
// SharpCompress requires archive streams to be seekable, which the stream opened by
|
||||
// OpenInputStream() seems to not necessarily be.
|
||||
// copy to an arbitrary-access memory stream to be able to proceed with the import.
|
||||
var copy = new MemoryStream();
|
||||
using (var stream = ContentResolver.OpenInputStream(uri))
|
||||
await stream.CopyToAsync(copy);
|
||||
var filenameColumn = cursor.GetColumnIndex(OpenableColumns.DisplayName);
|
||||
string filename = cursor.GetString(filenameColumn);
|
||||
|
||||
await game.Import(copy, filename);
|
||||
// SharpCompress requires archive streams to be seekable, which the stream opened by
|
||||
// OpenInputStream() seems to not necessarily be.
|
||||
// copy to an arbitrary-access memory stream to be able to proceed with the import.
|
||||
var copy = new MemoryStream();
|
||||
using (var stream = ContentResolver.OpenInputStream(uri))
|
||||
await stream.CopyToAsync(copy);
|
||||
|
||||
lock (tasks)
|
||||
{
|
||||
tasks.Add(new ImportTask(copy, filename));
|
||||
}
|
||||
}));
|
||||
|
||||
await game.Import(tasks.ToArray());
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
@@ -31,13 +32,15 @@ namespace osu.Desktop
|
||||
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
|
||||
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
|
||||
private readonly Bindable<DiscordRichPresenceMode> privacyMode = new Bindable<DiscordRichPresenceMode>();
|
||||
|
||||
private readonly RichPresence presence = new RichPresence
|
||||
{
|
||||
Assets = new Assets { LargeImageKey = "osu_logo_lazer", }
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IAPIProvider provider)
|
||||
private void load(IAPIProvider provider, OsuConfigManager config)
|
||||
{
|
||||
client = new DiscordRpcClient(client_id)
|
||||
{
|
||||
@@ -51,6 +54,8 @@ namespace osu.Desktop
|
||||
|
||||
client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network);
|
||||
|
||||
config.BindWith(OsuSetting.DiscordRichPresence, privacyMode);
|
||||
|
||||
(user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u =>
|
||||
{
|
||||
status.UnbindBindings();
|
||||
@@ -63,6 +68,7 @@ namespace osu.Desktop
|
||||
ruleset.BindValueChanged(_ => updateStatus());
|
||||
status.BindValueChanged(_ => updateStatus());
|
||||
activity.BindValueChanged(_ => updateStatus());
|
||||
privacyMode.BindValueChanged(_ => updateStatus());
|
||||
|
||||
client.Initialize();
|
||||
}
|
||||
@@ -78,7 +84,7 @@ namespace osu.Desktop
|
||||
if (!client.IsInitialized)
|
||||
return;
|
||||
|
||||
if (status.Value is UserStatusOffline)
|
||||
if (status.Value is UserStatusOffline || privacyMode.Value == DiscordRichPresenceMode.Off)
|
||||
{
|
||||
client.ClearPresence();
|
||||
return;
|
||||
@@ -96,7 +102,10 @@ namespace osu.Desktop
|
||||
}
|
||||
|
||||
// update user information
|
||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty);
|
||||
if (privacyMode.Value == DiscordRichPresenceMode.Limited)
|
||||
presence.Assets.LargeImageText = string.Empty;
|
||||
else
|
||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty);
|
||||
|
||||
// update ruleset
|
||||
presence.Assets.SmallImageKey = ruleset.Value.ID <= 3 ? $"mode_{ruleset.Value.ID}" : "mode_custom";
|
||||
@@ -137,7 +146,7 @@ namespace osu.Desktop
|
||||
return edit.Beatmap.ToString();
|
||||
|
||||
case UserActivity.InLobby lobby:
|
||||
return lobby.Room.Name.Value;
|
||||
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using osu.Desktop.Overlays;
|
||||
@@ -56,16 +57,16 @@ namespace osu.Desktop
|
||||
|
||||
string stableInstallPath;
|
||||
|
||||
try
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
|
||||
stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", "");
|
||||
try
|
||||
{
|
||||
stableInstallPath = getStableInstallPathFromRegistry();
|
||||
|
||||
if (checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!string.IsNullOrEmpty(stableInstallPath) && checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
|
||||
@@ -79,6 +80,13 @@ namespace osu.Desktop
|
||||
return null;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
private string getStableInstallPathFromRegistry()
|
||||
{
|
||||
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
|
||||
return key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", "");
|
||||
}
|
||||
|
||||
protected override UpdateManager CreateUpdateManager()
|
||||
{
|
||||
switch (RuntimeInfo.OS)
|
||||
|
||||
@@ -26,9 +26,11 @@ namespace osu.Desktop.Overlays
|
||||
|
||||
Alpha = 0;
|
||||
|
||||
FillFlowContainer mainFill;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
mainFill = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
@@ -55,23 +57,30 @@ namespace osu.Desktop.Overlays
|
||||
},
|
||||
}
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Font = OsuFont.Numeric.With(size: 12),
|
||||
Colour = colours.Yellow,
|
||||
Text = @"Development Build"
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Texture = textures.Get(@"Menu/dev-build-footer"),
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!game.IsDeployedBuild)
|
||||
{
|
||||
mainFill.AddRange(new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Font = OsuFont.Numeric.With(size: 12),
|
||||
Colour = colours.Yellow,
|
||||
Text = @"Development Build"
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Texture = textures.Get(@"Menu/dev-build-footer"),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>A free-to-win rhythm game. Rhythm is just a *click* away!</Description>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>A free-to-win rhythm game. Rhythm is just a *click* away!</description>
|
||||
<releaseNotes>testing</releaseNotes>
|
||||
<copyright>Copyright (c) 2020 ppy Pty Ltd</copyright>
|
||||
<copyright>Copyright (c) 2021 ppy Pty Ltd</copyright>
|
||||
<language>en-AU</language>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest
|
||||
{
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
config.BindWith(OsuSetting.BeatmapSkins, BeatmapSkins);
|
||||
config.BindWith(OsuSetting.BeatmapColours, BeatmapColours);
|
||||
}
|
||||
|
||||
[TestCase(true, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(false, false)]
|
||||
public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
|
||||
base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin);
|
||||
AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
|
||||
base.TestBeatmapComboColoursOverride(useBeatmapSkin);
|
||||
AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
|
||||
base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin);
|
||||
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
|
||||
}
|
||||
|
||||
[TestCase(true, true)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, false)]
|
||||
public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false);
|
||||
base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour);
|
||||
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
|
||||
}
|
||||
|
||||
[TestCase(true, true)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, false)]
|
||||
public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false);
|
||||
base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour);
|
||||
AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBeatmapHyperDashColours(bool useBeatmapSkin)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
|
||||
ConfigureTest(useBeatmapSkin, true, true);
|
||||
AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestBeatmapSkin.HYPER_DASH_COLOUR);
|
||||
AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestBeatmapSkin.HYPER_DASH_AFTER_IMAGE_COLOUR);
|
||||
AddAssert("is custom hyper dash fruit colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashFruitColour == TestBeatmapSkin.HYPER_DASH_FRUIT_COLOUR);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBeatmapHyperDashColoursOverride(bool useBeatmapSkin)
|
||||
{
|
||||
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
|
||||
ConfigureTest(useBeatmapSkin, false, true);
|
||||
AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestSkin.HYPER_DASH_COLOUR);
|
||||
AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestSkin.HYPER_DASH_AFTER_IMAGE_COLOUR);
|
||||
AddAssert("is custom hyper dash fruit colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashFruitColour == TestSkin.HYPER_DASH_FRUIT_COLOUR);
|
||||
}
|
||||
|
||||
protected override ExposedPlayer CreateTestPlayer(bool userHasCustomColours) => new CatchExposedPlayer(userHasCustomColours);
|
||||
|
||||
private class CatchExposedPlayer : ExposedPlayer
|
||||
{
|
||||
public CatchExposedPlayer(bool userHasCustomColours)
|
||||
: base(userHasCustomColours)
|
||||
{
|
||||
}
|
||||
|
||||
public Color4 UsableHyperDashColour =>
|
||||
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
|
||||
.First()
|
||||
.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup(CatchSkinColour.HyperDash))?
|
||||
.Value ?? Color4.Red;
|
||||
|
||||
public Color4 UsableHyperDashAfterImageColour =>
|
||||
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
|
||||
.First()
|
||||
.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup(CatchSkinColour.HyperDashAfterImage))?
|
||||
.Value ?? Color4.Red;
|
||||
|
||||
public Color4 UsableHyperDashFruitColour =>
|
||||
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
|
||||
.First()
|
||||
.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup(CatchSkinColour.HyperDashFruit))?
|
||||
.Value ?? Color4.Red;
|
||||
}
|
||||
|
||||
private class CatchCustomSkinWorkingBeatmap : CustomSkinWorkingBeatmap
|
||||
{
|
||||
public CatchCustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
|
||||
: base(createBeatmap(), audio, hasColours)
|
||||
{
|
||||
}
|
||||
|
||||
private static IBeatmap createBeatmap() =>
|
||||
new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo(),
|
||||
Ruleset = new CatchRuleset().RulesetInfo
|
||||
},
|
||||
HitObjects = { new Fruit { StartTime = 1816, X = 56, NewCombo = true } }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
|
||||
@@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
base.ApplySettings(difficulty);
|
||||
|
||||
difficulty.CircleSize = CircleSize.Value;
|
||||
difficulty.ApproachRate = ApproachRate.Value;
|
||||
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
|
||||
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>catch the fruit. to the beat.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Nuget">
|
||||
<Title>osu!catch (ruleset)</Title>
|
||||
<PackageId>ppy.osu.Game.Rulesets.Catch</PackageId>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>smash the keys. to the beat.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Nuget">
|
||||
<Title>osu!mania (ruleset)</Title>
|
||||
<PackageId>ppy.osu.Game.Rulesets.Mania</PackageId>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
@@ -18,8 +22,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
public void TestNoAdjustment() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust(),
|
||||
Beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 8
|
||||
}
|
||||
},
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
new HitCircle { StartTime = 1000 },
|
||||
new HitCircle { StartTime = 2000 }
|
||||
}
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = checkSomeHit
|
||||
PassCondition = () => checkSomeHit() && checkObjectsScale(0.29f)
|
||||
});
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -1,107 +1,91 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneLegacyBeatmapSkin : ScreenTestScene
|
||||
public class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest
|
||||
{
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
config.BindWith(OsuSetting.BeatmapSkins, BeatmapSkins);
|
||||
config.BindWith(OsuSetting.BeatmapColours, BeatmapColours);
|
||||
}
|
||||
|
||||
[TestCase(true, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(false, false)]
|
||||
public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin)
|
||||
{
|
||||
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true);
|
||||
base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin);
|
||||
AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBeatmapComboColours(bool customSkinColoursPresent)
|
||||
public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin)
|
||||
{
|
||||
ExposedPlayer player = null;
|
||||
|
||||
AddStep("load coloured beatmap", () => player = loadBeatmap(customSkinColoursPresent, true));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("is beatmap skin colours", () => player.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
|
||||
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true);
|
||||
base.TestBeatmapComboColoursOverride(useBeatmapSkin);
|
||||
AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapNoComboColours()
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin)
|
||||
{
|
||||
ExposedPlayer player = null;
|
||||
|
||||
AddStep("load no-colour beatmap", () => player = loadBeatmap(false, false));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("is default user skin colours", () => player.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
|
||||
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true);
|
||||
base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin);
|
||||
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapNoComboColoursSkinOverride()
|
||||
[TestCase(true, true)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, false)]
|
||||
public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour)
|
||||
{
|
||||
ExposedPlayer player = null;
|
||||
|
||||
AddStep("load custom-skin colour", () => player = loadBeatmap(true, false));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("is custom user skin colours", () => player.UsableComboColours.SequenceEqual(TestSkin.Colours));
|
||||
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false);
|
||||
base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour);
|
||||
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
|
||||
}
|
||||
|
||||
private ExposedPlayer loadBeatmap(bool userHasCustomColours, bool beatmapHasColours)
|
||||
[TestCase(true, true)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, false)]
|
||||
public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour)
|
||||
{
|
||||
ExposedPlayer player;
|
||||
|
||||
Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasColours);
|
||||
|
||||
LoadScreen(player = new ExposedPlayer(userHasCustomColours));
|
||||
|
||||
return player;
|
||||
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false);
|
||||
base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour);
|
||||
AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
|
||||
}
|
||||
|
||||
private class ExposedPlayer : Player
|
||||
private class OsuCustomSkinWorkingBeatmap : CustomSkinWorkingBeatmap
|
||||
{
|
||||
private readonly bool userHasCustomColours;
|
||||
|
||||
public ExposedPlayer(bool userHasCustomColours)
|
||||
: base(new PlayerConfiguration
|
||||
{
|
||||
AllowPause = false,
|
||||
ShowResults = false,
|
||||
})
|
||||
public OsuCustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
|
||||
: base(createBeatmap(), audio, hasColours)
|
||||
{
|
||||
this.userHasCustomColours = userHasCustomColours;
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<ISkinSource>(new TestSkin(userHasCustomColours));
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public IReadOnlyList<Color4> UsableComboColours =>
|
||||
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
|
||||
.First()
|
||||
.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
|
||||
}
|
||||
|
||||
private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
|
||||
{
|
||||
private readonly bool hasColours;
|
||||
|
||||
public CustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
|
||||
: base(new Beatmap
|
||||
private static IBeatmap createBeatmap() =>
|
||||
new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
@@ -109,50 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
},
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
}, null, null, audio)
|
||||
{
|
||||
this.hasColours = hasColours;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, hasColours);
|
||||
}
|
||||
|
||||
private class TestBeatmapSkin : LegacyBeatmapSkin
|
||||
{
|
||||
public static Color4[] Colours { get; } =
|
||||
{
|
||||
new Color4(50, 100, 150, 255),
|
||||
new Color4(40, 80, 120, 255),
|
||||
};
|
||||
|
||||
public TestBeatmapSkin(BeatmapInfo beatmap, bool hasColours)
|
||||
: base(beatmap, new ResourceStore<byte[]>(), null)
|
||||
{
|
||||
if (hasColours)
|
||||
Configuration.AddComboColours(Colours);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSkin : LegacySkin, ISkinSource
|
||||
{
|
||||
public static Color4[] Colours { get; } =
|
||||
{
|
||||
new Color4(150, 100, 50, 255),
|
||||
new Color4(20, 20, 20, 255),
|
||||
};
|
||||
|
||||
public TestSkin(bool hasCustomColours)
|
||||
: base(new SkinInfo(), null, null, string.Empty)
|
||||
{
|
||||
if (hasCustomColours)
|
||||
Configuration.AddComboColours(Colours);
|
||||
}
|
||||
|
||||
public event Action SourceChanged
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,31 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
checkNextHitObject(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapColourDefault()
|
||||
{
|
||||
AddStep("enable user provider", () => testUserSkin.Enabled = true);
|
||||
|
||||
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
|
||||
checkNextHitObject("beatmap");
|
||||
|
||||
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
|
||||
checkNextHitObject("beatmap");
|
||||
|
||||
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
|
||||
checkNextHitObject("user");
|
||||
|
||||
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
|
||||
checkNextHitObject("user");
|
||||
|
||||
AddStep("disable user provider", () => testUserSkin.Enabled = false);
|
||||
checkNextHitObject(null);
|
||||
}
|
||||
|
||||
private void checkNextHitObject(string skin) =>
|
||||
AddUntilStep($"check skin from {skin}", () =>
|
||||
{
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@@ -34,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[TestCase(true)]
|
||||
public void TestLongSpinner(bool autoplay)
|
||||
{
|
||||
AddStep("Very short spinner", () => SetContents(() => testSingle(5, autoplay, 2000)));
|
||||
AddStep("Very long spinner", () => SetContents(() => testSingle(5, autoplay, 4000)));
|
||||
AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult);
|
||||
AddUntilStep("Check correct progress", () => drawableSpinner.Progress == (autoplay ? 1 : 0));
|
||||
}
|
||||
@@ -55,7 +57,11 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
var spinner = new Spinner
|
||||
{
|
||||
StartTime = Time.Current + delay,
|
||||
EndTime = Time.Current + delay + length
|
||||
EndTime = Time.Current + delay + length,
|
||||
Samples = new List<HitSampleInfo>
|
||||
{
|
||||
new HitSampleInfo("hitnormal")
|
||||
}
|
||||
};
|
||||
|
||||
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize });
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
if (Attributes.ApproachRate > 10.33)
|
||||
approachRateFactor += 0.4 * (Attributes.ApproachRate - 10.33);
|
||||
else if (Attributes.ApproachRate < 8.0)
|
||||
approachRateFactor += 0.1 * (8.0 - Attributes.ApproachRate);
|
||||
approachRateFactor += 0.01 * (8.0 - Attributes.ApproachRate);
|
||||
|
||||
aimValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0));
|
||||
|
||||
|
||||
@@ -30,6 +30,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.HitArea.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
public override Quad SelectionQuad => DrawableObject.HitArea.ScreenSpaceDrawQuad;
|
||||
public override Quad SelectionQuad => CirclePiece.ScreenSpaceDrawQuad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IEditorChangeHandler changeHandler { get; set; }
|
||||
|
||||
public override Quad SelectionQuad => BodyPiece.ScreenSpaceDrawQuad;
|
||||
|
||||
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
|
||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||
|
||||
|
||||
@@ -236,7 +236,20 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
/// </summary>
|
||||
/// <param name="hitObjects">The hit objects to calculate a quad for.</param>
|
||||
private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
|
||||
getSurroundingQuad(hitObjects.SelectMany(h => new[] { h.Position, h.EndPosition }));
|
||||
getSurroundingQuad(hitObjects.SelectMany(h =>
|
||||
{
|
||||
if (h is IHasPath path)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
h.Position,
|
||||
// can't use EndPosition for reverse slider cases.
|
||||
h.Position + path.Path.PositionAt(1)
|
||||
};
|
||||
}
|
||||
|
||||
return new[] { h.Position };
|
||||
}));
|
||||
|
||||
/// <summary>
|
||||
/// Returns a gamefield-space quad surrounding the provided points.
|
||||
|
||||
@@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
base.ApplySettings(difficulty);
|
||||
|
||||
difficulty.CircleSize = CircleSize.Value;
|
||||
difficulty.ApproachRate = ApproachRate.Value;
|
||||
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
|
||||
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,12 +130,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
if (tracking.NewValue)
|
||||
{
|
||||
spinningSample?.Play();
|
||||
spinningSample?.VolumeTo(1, 200);
|
||||
spinningSample?.Play(!spinningSample.IsPlaying);
|
||||
spinningSample?.VolumeTo(1, 300);
|
||||
}
|
||||
else
|
||||
{
|
||||
spinningSample?.VolumeTo(0, 200).Finally(_ => spinningSample.Stop());
|
||||
spinningSample?.VolumeTo(0, 300).OnComplete(_ => spinningSample.Stop());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
private double lastTrailTime;
|
||||
private IBindable<float> cursorSize;
|
||||
|
||||
public LegacyCursorTrail()
|
||||
{
|
||||
Blending = BlendingParameters.Additive;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, OsuConfigManager config)
|
||||
{
|
||||
Texture = skin.GetTexture("cursortrail");
|
||||
disjointTrail = skin.GetTexture("cursormiddle") == null;
|
||||
|
||||
Blending = !disjointTrail ? BlendingParameters.Additive : BlendingParameters.Inherit;
|
||||
|
||||
if (Texture != null)
|
||||
{
|
||||
// stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation.
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>click the circles. to the beat.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Nuget">
|
||||
<Title>osu! (ruleset)</Title>
|
||||
<PackageId>ppy.osu.Game.Rulesets.Osu</PackageId>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
[TestCase("sample-to-type-conversions")]
|
||||
[TestCase("slider-conversion-v6")]
|
||||
[TestCase("slider-conversion-v14")]
|
||||
[TestCase("slider-generating-drumroll-2")]
|
||||
public void Test(string name) => base.Test(name);
|
||||
|
||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
private bool shouldConvertSliderToHits(HitObject obj, IBeatmap beatmap, IHasDistance distanceData, out double taikoDuration, out double tickSpacing)
|
||||
private bool shouldConvertSliderToHits(HitObject obj, IBeatmap beatmap, IHasDistance distanceData, out int taikoDuration, out double tickSpacing)
|
||||
{
|
||||
// DO NOT CHANGE OR REFACTOR ANYTHING IN HERE WITHOUT TESTING AGAINST _ALL_ BEATMAPS.
|
||||
// Some of these calculations look redundant, but they are not - extremely small floating point errors are introduced to maintain 1:1 compatibility with stable.
|
||||
@@ -185,7 +185,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
|
||||
// The velocity and duration of the taiko hit object - calculated as the velocity of a drum roll.
|
||||
double taikoVelocity = sliderScoringPointDistance * beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate;
|
||||
taikoDuration = distance / taikoVelocity * beatLength;
|
||||
taikoDuration = (int)(distance / taikoVelocity * beatLength);
|
||||
|
||||
if (isForCurrentRuleset)
|
||||
{
|
||||
@@ -200,7 +200,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
beatLength = timingPoint.BeatLength;
|
||||
|
||||
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
|
||||
tickSpacing = Math.Min(beatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, taikoDuration / spans);
|
||||
tickSpacing = Math.Min(beatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, (double)taikoDuration / spans);
|
||||
|
||||
return tickSpacing > 0
|
||||
&& distance / osuVelocity * 1000 < 2 * beatLength;
|
||||
|
||||
+12
-295
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"Mappings": [
|
||||
{
|
||||
"StartTime": 2000,
|
||||
"Objects": [{
|
||||
"Objects": [
|
||||
{
|
||||
"StartTime": 2000,
|
||||
"EndTime": 2000,
|
||||
"IsRim": false,
|
||||
@@ -23,7 +25,8 @@
|
||||
},
|
||||
{
|
||||
"StartTime": 4000,
|
||||
"Objects": [{
|
||||
"Objects": [
|
||||
{
|
||||
"StartTime": 4000,
|
||||
"EndTime": 4000,
|
||||
"IsRim": false,
|
||||
@@ -45,7 +48,8 @@
|
||||
},
|
||||
{
|
||||
"StartTime": 6000,
|
||||
"Objects": [{
|
||||
"Objects": [
|
||||
{
|
||||
"StartTime": 6000,
|
||||
"EndTime": 6000,
|
||||
"IsRim": true,
|
||||
@@ -76,300 +80,13 @@
|
||||
},
|
||||
{
|
||||
"StartTime": 8000,
|
||||
"Objects": [{
|
||||
"Objects": [
|
||||
{
|
||||
"StartTime": 8000,
|
||||
"EndTime": 8000,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8026,
|
||||
"EndTime": 8026,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8053,
|
||||
"EndTime": 8053,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8080,
|
||||
"EndTime": 8080,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8107,
|
||||
"EndTime": 8107,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8133,
|
||||
"EndTime": 8133,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8160,
|
||||
"EndTime": 8160,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8187,
|
||||
"EndTime": 8187,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8214,
|
||||
"EndTime": 8214,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8241,
|
||||
"EndTime": 8241,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8267,
|
||||
"EndTime": 8267,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8294,
|
||||
"EndTime": 8294,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8321,
|
||||
"EndTime": 8321,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8348,
|
||||
"EndTime": 8348,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8374,
|
||||
"EndTime": 8374,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8401,
|
||||
"EndTime": 8401,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8428,
|
||||
"EndTime": 8428,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8455,
|
||||
"EndTime": 8455,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8482,
|
||||
"EndTime": 8482,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8508,
|
||||
"EndTime": 8508,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8535,
|
||||
"EndTime": 8535,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8562,
|
||||
"EndTime": 8562,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8589,
|
||||
"EndTime": 8589,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8615,
|
||||
"EndTime": 8615,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8642,
|
||||
"EndTime": 8642,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8669,
|
||||
"EndTime": 8669,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8696,
|
||||
"EndTime": 8696,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8723,
|
||||
"EndTime": 8723,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8749,
|
||||
"EndTime": 8749,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8776,
|
||||
"EndTime": 8776,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8803,
|
||||
"EndTime": 8803,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8830,
|
||||
"EndTime": 8830,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
},
|
||||
{
|
||||
"StartTime": 8857,
|
||||
"EndTime": 8857,
|
||||
"IsRim": false,
|
||||
"IsCentre": true,
|
||||
"IsDrumRoll": false,
|
||||
"IsCentre": false,
|
||||
"IsDrumRoll": true,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"Mappings": [
|
||||
{
|
||||
"StartTime": 51532,
|
||||
"Objects": [
|
||||
{
|
||||
"StartTime": 51532,
|
||||
"EndTime": 52301,
|
||||
"IsRim": false,
|
||||
"IsCentre": false,
|
||||
"IsDrumRoll": true,
|
||||
"IsSwell": false,
|
||||
"IsStrong": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
Mode: 0
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:2
|
||||
CircleSize:3.2
|
||||
OverallDifficulty:2
|
||||
ApproachRate:3
|
||||
SliderMultiplier:0.999999999999999
|
||||
SliderTickRate:1
|
||||
|
||||
[TimingPoints]
|
||||
763,384.615384615385,4,2,0,70,1,0
|
||||
49993,-90.9090909090909,4,2,0,75,0,1
|
||||
|
||||
[HitObjects]
|
||||
51,245,51532,2,0,P|18:150|17:122,2,110.000003356934,0|8|0,0:0|0:0|0:0,0:0:0:0:
|
||||
@@ -5,6 +5,13 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>bash the drum. to the beat.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Nuget">
|
||||
<Title>osu!taiko (ruleset)</Title>
|
||||
<PackageId>ppy.osu.Game.Rulesets.Taiko</PackageId>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -95,6 +95,26 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOutOfOrderStartTimes()
|
||||
{
|
||||
var decoder = new LegacyStoryboardDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("out-of-order-starttimes.osb"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3);
|
||||
Assert.AreEqual(2, background.Elements.Count);
|
||||
|
||||
Assert.AreEqual(1500, background.Elements[0].StartTime);
|
||||
Assert.AreEqual(1000, background.Elements[1].StartTime);
|
||||
|
||||
Assert.AreEqual(1000, storyboard.EarliestEventTime);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeVariableWithSuffix()
|
||||
{
|
||||
|
||||
@@ -246,5 +246,32 @@ namespace osu.Game.Tests.NonVisual
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateCopyIsDeepClone()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(1000, new TimingControlPoint { BeatLength = 500 });
|
||||
|
||||
var cpiCopy = cpi.CreateCopy();
|
||||
|
||||
cpiCopy.Add(2000, new TimingControlPoint { BeatLength = 500 });
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpiCopy.Groups.Count, Is.EqualTo(2));
|
||||
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpiCopy.TimingPoints.Count, Is.EqualTo(2));
|
||||
|
||||
Assert.That(cpi.TimingPoints[0], Is.Not.SameAs(cpiCopy.TimingPoints[0]));
|
||||
Assert.That(cpi.TimingPoints[0].BeatLengthBindable, Is.Not.SameAs(cpiCopy.TimingPoints[0].BeatLengthBindable));
|
||||
|
||||
Assert.That(cpi.TimingPoints[0].BeatLength, Is.EqualTo(cpiCopy.TimingPoints[0].BeatLength));
|
||||
|
||||
cpi.TimingPoints[0].BeatLength = 800;
|
||||
|
||||
Assert.That(cpi.TimingPoints[0].BeatLength, Is.Not.EqualTo(cpiCopy.TimingPoints[0].BeatLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using Humanizer;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Tests.Visual.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual.Multiplayer
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class StatefulMultiplayerClientTest : MultiplayerTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestPlayingUserTracking()
|
||||
{
|
||||
int id = 2000;
|
||||
|
||||
AddRepeatStep("add some users", () => Client.AddUser(new User { Id = id++ }), 5);
|
||||
checkPlayingUserCount(0);
|
||||
|
||||
changeState(3, MultiplayerUserState.WaitingForLoad);
|
||||
checkPlayingUserCount(3);
|
||||
|
||||
changeState(3, MultiplayerUserState.Playing);
|
||||
checkPlayingUserCount(3);
|
||||
|
||||
changeState(3, MultiplayerUserState.Results);
|
||||
checkPlayingUserCount(0);
|
||||
|
||||
changeState(6, MultiplayerUserState.WaitingForLoad);
|
||||
checkPlayingUserCount(6);
|
||||
|
||||
AddStep("another user left", () => Client.RemoveUser(Client.Room?.Users.Last().User));
|
||||
checkPlayingUserCount(5);
|
||||
|
||||
AddStep("leave room", () => Client.LeaveRoom());
|
||||
checkPlayingUserCount(0);
|
||||
}
|
||||
|
||||
private void checkPlayingUserCount(int expectedCount)
|
||||
=> AddAssert($"{"user".ToQuantity(expectedCount)} playing", () => Client.CurrentMatchPlayingUserIds.Count == expectedCount);
|
||||
|
||||
private void changeState(int userCount, MultiplayerUserState state)
|
||||
=> AddStep($"{"user".ToQuantity(userCount)} in {state}", () =>
|
||||
{
|
||||
for (int i = 0; i < userCount; ++i)
|
||||
{
|
||||
var userId = Client.Room?.Users[i].UserID ?? throw new AssertionException("Room cannot be null!");
|
||||
Client.ChangeUserState(userId, state);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
[Events]
|
||||
//Storyboard Layer 0 (Background)
|
||||
Sprite,Background,TopCentre,"img.jpg",320,240
|
||||
F,0,1500,1600,0,1
|
||||
Sprite,Background,TopCentre,"img.jpg",320,240
|
||||
F,0,1000,1100,0,1
|
||||
@@ -9,7 +9,6 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
@@ -5,7 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
});
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,6 +106,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void TestStoryboardBackgroundVisibility()
|
||||
{
|
||||
performFullSetup();
|
||||
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
|
||||
createFakeStoryboard();
|
||||
AddStep("Enable Storyboard", () =>
|
||||
{
|
||||
@@ -198,8 +199,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
})));
|
||||
|
||||
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
|
||||
|
||||
AddUntilStep("Screen is undimmed, original background retained", () =>
|
||||
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect());
|
||||
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && songSelect.CheckBackgroundBlur(results.ExpectedBackgroundBlur));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -224,7 +226,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
AddStep("Resume PlayerLoader", () => player.Restart());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur));
|
||||
}
|
||||
|
||||
private void createFakeStoryboard() => AddStep("Create storyboard", () =>
|
||||
@@ -274,9 +276,11 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private class DummySongSelect : PlaySongSelect
|
||||
{
|
||||
private FadeAccessibleBackground background;
|
||||
|
||||
protected override BackgroundScreen CreateBackground()
|
||||
{
|
||||
FadeAccessibleBackground background = new FadeAccessibleBackground(Beatmap.Value);
|
||||
background = new FadeAccessibleBackground(Beatmap.Value);
|
||||
DimEnabled.BindTo(background.EnableUserDim);
|
||||
return background;
|
||||
}
|
||||
@@ -294,25 +298,27 @@ namespace osu.Game.Tests.Visual.Background
|
||||
config.BindWith(OsuSetting.BlurLevel, BlurLevel);
|
||||
}
|
||||
|
||||
public bool IsBackgroundDimmed() => ((FadeAccessibleBackground)Background).CurrentColour == OsuColour.Gray(1f - ((FadeAccessibleBackground)Background).CurrentDim);
|
||||
public bool IsBackgroundDimmed() => background.CurrentColour == OsuColour.Gray(1f - background.CurrentDim);
|
||||
|
||||
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
|
||||
public bool IsBackgroundUndimmed() => background.CurrentColour == Color4.White;
|
||||
|
||||
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
public bool IsUserBlurApplied() => background.CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
|
||||
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
|
||||
public bool IsUserBlurDisabled() => background.CurrentBlur == new Vector2(0);
|
||||
|
||||
public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0;
|
||||
public bool IsBackgroundInvisible() => background.CurrentAlpha == 0;
|
||||
|
||||
public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1;
|
||||
public bool IsBackgroundVisible() => background.CurrentAlpha == 1;
|
||||
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public bool IsBlurCorrect() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
|
||||
public bool CheckBackgroundBlur(Vector2 expected) => background.CurrentBlur == expected;
|
||||
|
||||
/// <summary>
|
||||
/// Make sure every time a screen gets pushed, the background doesn't get replaced
|
||||
/// </summary>
|
||||
/// <returns>Whether or not the original background (The one created in DummySongSelect) is still the current background</returns>
|
||||
public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen();
|
||||
public bool IsBackgroundCurrent() => background?.IsCurrentScreen() == true;
|
||||
}
|
||||
|
||||
private class FadeAccessibleResults : ResultsScreen
|
||||
@@ -324,12 +330,20 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR);
|
||||
}
|
||||
|
||||
private class LoadBlockingTestPlayer : TestPlayer
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
protected override BackgroundScreen CreateBackground() =>
|
||||
new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
public override void OnEntering(IScreen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
ApplyToBackground(b => ReplacesBackground.BindTo(b.StoryboardReplacesBackground));
|
||||
}
|
||||
|
||||
public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
|
||||
|
||||
@@ -354,15 +368,16 @@ namespace osu.Game.Tests.Visual.Background
|
||||
Thread.Sleep(1);
|
||||
|
||||
StoryboardEnabled = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
ReplacesBackground.BindTo(Background.StoryboardReplacesBackground);
|
||||
DrawableRuleset.IsPaused.BindTo(IsPaused);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestPlayerLoader : PlayerLoader
|
||||
{
|
||||
private FadeAccessibleBackground background;
|
||||
|
||||
public VisualSettings VisualSettingsPos => VisualSettings;
|
||||
public BackgroundScreen ScreenPos => Background;
|
||||
public BackgroundScreen ScreenPos => background;
|
||||
|
||||
public TestPlayerLoader(Player player)
|
||||
: base(() => player)
|
||||
@@ -371,9 +386,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
public void TriggerOnHover() => OnHover(new HoverEvent(new InputState()));
|
||||
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR);
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value);
|
||||
}
|
||||
|
||||
private class FadeAccessibleBackground : BackgroundScreenBeatmap
|
||||
|
||||
@@ -8,7 +8,6 @@ using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Components
|
||||
{
|
||||
@@ -100,7 +99,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
[Test]
|
||||
public void TestNonPresentTrack()
|
||||
{
|
||||
TestPreviewTrack track = null;
|
||||
TestPreviewTrackManager.TestPreviewTrack track = null;
|
||||
|
||||
AddStep("get non-present track", () =>
|
||||
{
|
||||
@@ -182,9 +181,9 @@ namespace osu.Game.Tests.Visual.Components
|
||||
AddAssert("track stopped", () => !track.IsRunning);
|
||||
}
|
||||
|
||||
private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null);
|
||||
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null);
|
||||
|
||||
private TestPreviewTrack getOwnedTrack()
|
||||
private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack()
|
||||
{
|
||||
var track = getTrack();
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
|
||||
{
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||
public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
|
||||
};
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
|
||||
{
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||
public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -74,6 +75,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
Debug.Assert(args.NewItems != null);
|
||||
|
||||
foreach (int user in args.NewItems)
|
||||
{
|
||||
if (user == api.LocalUser.Value.Id)
|
||||
@@ -83,6 +86,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
Debug.Assert(args.OldItems != null);
|
||||
|
||||
foreach (int user in args.OldItems)
|
||||
{
|
||||
if (user == api.LocalUser.Value.Id)
|
||||
@@ -298,7 +303,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
|
||||
{
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||
public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneCreateMultiplayerMatchButton : MultiplayerTestScene
|
||||
{
|
||||
private CreateMultiplayerMatchButton button;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
AddStep("create button", () => Child = button = new CreateMultiplayerMatchButton
|
||||
{
|
||||
Width = 200,
|
||||
Height = 100,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestButtonEnableStateChanges()
|
||||
{
|
||||
IDisposable joiningRoomOperation = null;
|
||||
|
||||
assertButtonEnableState(true);
|
||||
|
||||
AddStep("begin joining room", () => joiningRoomOperation = OngoingOperationTracker.BeginOperation());
|
||||
assertButtonEnableState(false);
|
||||
|
||||
AddStep("end joining room", () => joiningRoomOperation.Dispose());
|
||||
assertButtonEnableState(true);
|
||||
|
||||
AddStep("disconnect client", () => Client.Disconnect());
|
||||
assertButtonEnableState(false);
|
||||
|
||||
AddStep("re-connect client", () => Client.Connect());
|
||||
assertButtonEnableState(true);
|
||||
}
|
||||
|
||||
private void assertButtonEnableState(bool enabled)
|
||||
=> AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => button.Enabled.Value == enabled);
|
||||
}
|
||||
}
|
||||
@@ -201,11 +201,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDownloadButtonHiddenInitiallyWhenBeatmapExists()
|
||||
public void TestDownloadButtonHiddenWhenBeatmapExists()
|
||||
{
|
||||
createPlaylist(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo);
|
||||
|
||||
AddAssert("download button hidden", () => !playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().Single().IsPresent);
|
||||
assertDownloadButtonVisible(false);
|
||||
|
||||
AddStep("delete beatmap set", () => manager.Delete(manager.QueryBeatmapSets(_ => true).Single()));
|
||||
assertDownloadButtonVisible(true);
|
||||
|
||||
AddStep("undelete beatmap set", () => manager.Undelete(manager.QueryBeatmapSets(_ => true).Single()));
|
||||
assertDownloadButtonVisible(false);
|
||||
|
||||
void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}",
|
||||
() => playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().Single().Alpha == (visible ? 1 : 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -222,6 +231,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddAssert("download buttons shown", () => playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().All(d => d.IsPresent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExplicitBeatmapItem()
|
||||
{
|
||||
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
||||
beatmap.BeatmapSet.OnlineInfo.HasExplicitContent = true;
|
||||
|
||||
createPlaylist(beatmap);
|
||||
}
|
||||
|
||||
private void moveToItem(int index, Vector2? offset = null)
|
||||
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>>().ElementAt(index), offset));
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
streamingClient.Start(Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
||||
|
||||
Client.PlayingUsers.Clear();
|
||||
Client.PlayingUsers.AddRange(streamingClient.PlayingUsers);
|
||||
Client.CurrentMatchPlayingUserIds.Clear();
|
||||
Client.CurrentMatchPlayingUserIds.AddRange(streamingClient.PlayingUsers);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestUserQuit()
|
||||
{
|
||||
AddRepeatStep("mark user quit", () => Client.PlayingUsers.RemoveAt(0), users);
|
||||
AddRepeatStep("mark user quit", () => Client.CurrentMatchPlayingUserIds.RemoveAt(0), users);
|
||||
}
|
||||
|
||||
public class TestMultiplayerStreaming : SpectatorStreamingClient
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
@@ -18,6 +20,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
private MultiplayerMatchSubScreen screen;
|
||||
|
||||
[Cached]
|
||||
private OngoingOperationTracker ongoingOperationTracker = new OngoingOperationTracker();
|
||||
|
||||
public TestSceneMultiplayerMatchSubScreen()
|
||||
: base(false)
|
||||
{
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
@@ -23,10 +26,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
public class TestSceneMultiplayerReadyButton : MultiplayerTestScene
|
||||
{
|
||||
private MultiplayerReadyButton button;
|
||||
private BeatmapSetInfo importedSet;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
private IDisposable readyClickOperation;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, AudioManager audio)
|
||||
{
|
||||
@@ -38,9 +44,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[SetUp]
|
||||
public new void Setup() => Schedule(() =>
|
||||
{
|
||||
var beatmap = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First().Beatmaps.First();
|
||||
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap);
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
|
||||
|
||||
Child = button = new MultiplayerReadyButton
|
||||
{
|
||||
@@ -51,13 +56,43 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Value = new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = beatmap },
|
||||
Ruleset = { Value = beatmap.Ruleset }
|
||||
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
|
||||
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset }
|
||||
}
|
||||
},
|
||||
OnReadyClick = async () =>
|
||||
{
|
||||
readyClickOperation = OngoingOperationTracker.BeginOperation();
|
||||
|
||||
if (Client.IsHost && Client.LocalUser?.State == MultiplayerUserState.Ready)
|
||||
{
|
||||
await Client.StartMatch();
|
||||
return;
|
||||
}
|
||||
|
||||
await Client.ToggleReady();
|
||||
readyClickOperation.Dispose();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestDeletedBeatmapDisableReady()
|
||||
{
|
||||
OsuButton readyButton = null;
|
||||
|
||||
AddAssert("ensure ready button enabled", () =>
|
||||
{
|
||||
readyButton = button.ChildrenOfType<OsuButton>().Single();
|
||||
return readyButton.Enabled.Value;
|
||||
});
|
||||
|
||||
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
|
||||
AddAssert("ready button disabled", () => !readyButton.Enabled.Value);
|
||||
AddStep("undelete beatmap", () => beatmaps.Undelete(importedSet));
|
||||
AddAssert("ready button enabled back", () => readyButton.Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToggleStateWhenNotHost()
|
||||
{
|
||||
@@ -89,8 +124,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
addClickButtonStep();
|
||||
AddAssert("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready);
|
||||
|
||||
addClickButtonStep();
|
||||
AddAssert("match started", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
|
||||
verifyGameplayStartFlow();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -105,8 +139,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
addClickButtonStep();
|
||||
AddStep("make user host", () => Client.TransferHost(Client.Room?.Users[0].UserID ?? 0));
|
||||
|
||||
addClickButtonStep();
|
||||
AddAssert("match started", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
|
||||
verifyGameplayStartFlow();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -160,5 +193,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
InputManager.MoveMouseTo(button);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
private void verifyGameplayStartFlow()
|
||||
{
|
||||
addClickButtonStep();
|
||||
AddAssert("user waiting for load", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
|
||||
AddAssert("ready button disabled", () => !button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("transitioned to gameplay", () => readyClickOperation.Dispose());
|
||||
AddAssert("ready button enabled", () => button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,17 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExplicitBeatmap()
|
||||
{
|
||||
AddStep("show explicit map", () =>
|
||||
{
|
||||
var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||
beatmapSet.OnlineInfo.HasExplicitContent = true;
|
||||
overlay.ShowBeatmapSet(beatmapSet);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHide()
|
||||
{
|
||||
|
||||
@@ -99,13 +99,16 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
var normal = CreateWorkingBeatmap(Ruleset.Value).BeatmapSetInfo;
|
||||
var normal = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||
normal.OnlineInfo.HasVideo = true;
|
||||
normal.OnlineInfo.HasStoryboard = true;
|
||||
|
||||
var undownloadable = getUndownloadableBeatmapSet();
|
||||
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
|
||||
|
||||
var explicitMap = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||
explicitMap.OnlineInfo.HasExplicitContent = true;
|
||||
|
||||
Child = new BasicScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -121,9 +124,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
new GridBeatmapPanel(normal),
|
||||
new GridBeatmapPanel(undownloadable),
|
||||
new GridBeatmapPanel(manyDifficulties),
|
||||
new GridBeatmapPanel(explicitMap),
|
||||
new ListBeatmapPanel(normal),
|
||||
new ListBeatmapPanel(undownloadable),
|
||||
new ListBeatmapPanel(manyDifficulties),
|
||||
new ListBeatmapPanel(explicitMap)
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@@ -141,16 +142,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("select changed Difficulty Adjust mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
|
||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<OsuModDifficultyAdjust>().Single();
|
||||
var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
|
||||
var adjustedDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = originalDifficulty.CircleSize,
|
||||
DrainRate = originalDifficulty.DrainRate - 0.5f,
|
||||
OverallDifficulty = originalDifficulty.OverallDifficulty,
|
||||
ApproachRate = originalDifficulty.ApproachRate + 2.2f,
|
||||
};
|
||||
difficultyAdjustMod.ReadFromDifficulty(adjustedDifficulty);
|
||||
|
||||
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
||||
difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f;
|
||||
difficultyAdjustMod.ApproachRate.Value = originalDifficulty.ApproachRate + 2.2f;
|
||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapListing;
|
||||
@@ -19,9 +20,18 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
private readonly BeatmapListingSearchControl control;
|
||||
private BeatmapListingSearchControl control;
|
||||
|
||||
public TestSceneBeatmapListingSearchControl()
|
||||
private OsuConfigManager localConfig;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage));
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
OsuSpriteText query;
|
||||
OsuSpriteText ruleset;
|
||||
@@ -31,30 +41,34 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
OsuSpriteText extra;
|
||||
OsuSpriteText ranks;
|
||||
OsuSpriteText played;
|
||||
OsuSpriteText explicitMap;
|
||||
|
||||
Add(control = new BeatmapListingSearchControl
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
control = new BeatmapListingSearchControl
|
||||
{
|
||||
query = new OsuSpriteText(),
|
||||
ruleset = new OsuSpriteText(),
|
||||
category = new OsuSpriteText(),
|
||||
genre = new OsuSpriteText(),
|
||||
language = new OsuSpriteText(),
|
||||
extra = new OsuSpriteText(),
|
||||
ranks = new OsuSpriteText(),
|
||||
played = new OsuSpriteText()
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
query = new OsuSpriteText(),
|
||||
ruleset = new OsuSpriteText(),
|
||||
category = new OsuSpriteText(),
|
||||
genre = new OsuSpriteText(),
|
||||
language = new OsuSpriteText(),
|
||||
extra = new OsuSpriteText(),
|
||||
ranks = new OsuSpriteText(),
|
||||
played = new OsuSpriteText(),
|
||||
explicitMap = new OsuSpriteText(),
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
control.Query.BindValueChanged(q => query.Text = $"Query: {q.NewValue}", true);
|
||||
control.Ruleset.BindValueChanged(r => ruleset.Text = $"Ruleset: {r.NewValue}", true);
|
||||
@@ -64,7 +78,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
control.Extra.BindCollectionChanged((u, v) => extra.Text = $"Extra: {(control.Extra.Any() ? string.Join('.', control.Extra.Select(i => i.ToString().ToLowerInvariant())) : "")}", true);
|
||||
control.Ranks.BindCollectionChanged((u, v) => ranks.Text = $"Ranks: {(control.Ranks.Any() ? string.Join('.', control.Ranks.Select(i => i.ToString())) : "")}", true);
|
||||
control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true);
|
||||
}
|
||||
control.ExplicitContent.BindValueChanged(e => explicitMap.Text = $"Explicit Maps: {e.NewValue}", true);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestCovers()
|
||||
@@ -74,6 +89,22 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddStep("Set null beatmap", () => control.BeatmapSet = null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExplicitConfig()
|
||||
{
|
||||
AddStep("configure explicit content to allowed", () => localConfig.Set(OsuSetting.ShowOnlineExplicitContent, true));
|
||||
AddAssert("explicit control set to show", () => control.ExplicitContent.Value == SearchExplicit.Show);
|
||||
|
||||
AddStep("configure explicit content to disallowed", () => localConfig.Set(OsuSetting.ShowOnlineExplicitContent, false));
|
||||
AddAssert("explicit control set to hide", () => control.ExplicitContent.Value == SearchExplicit.Hide);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
localConfig?.Dispose();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private static readonly BeatmapSetInfo beatmap_set = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
|
||||
@@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
@@ -14,8 +15,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneLoadingLayer : OsuTestScene
|
||||
{
|
||||
private Drawable dimContent;
|
||||
private LoadingLayer overlay;
|
||||
private TestLoadingLayer overlay;
|
||||
|
||||
private Container content;
|
||||
|
||||
@@ -29,14 +29,14 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Size = new Vector2(300),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Children = new[]
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.SlateGray,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
dimContent = new FillFlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
new TriangleButton { Text = "puush me", Width = 200, Action = () => { } },
|
||||
}
|
||||
},
|
||||
overlay = new LoadingLayer(dimContent),
|
||||
overlay = new TestLoadingLayer(true),
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -64,25 +64,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("show", () => overlay.Show());
|
||||
|
||||
AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
|
||||
AddUntilStep("wait for content dim", () => overlay.BackgroundDimLayer.Alpha > 0);
|
||||
|
||||
AddStep("hide", () => overlay.Hide());
|
||||
|
||||
AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContentRestoreOnDispose()
|
||||
{
|
||||
AddAssert("not visible", () => !overlay.IsPresent);
|
||||
|
||||
AddStep("show", () => overlay.Show());
|
||||
|
||||
AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
|
||||
|
||||
AddStep("expire", () => overlay.Expire());
|
||||
|
||||
AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
|
||||
AddUntilStep("wait for content restore", () => Precision.AlmostEquals(overlay.BackgroundDimLayer.Alpha, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -98,5 +84,15 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("hide", () => overlay.Hide());
|
||||
}
|
||||
|
||||
private class TestLoadingLayer : LoadingLayer
|
||||
{
|
||||
public new Box BackgroundDimLayer => base.BackgroundDimLayer;
|
||||
|
||||
public TestLoadingLayer(bool dimBackground = false, bool withBox = true)
|
||||
: base(dimBackground, withBox)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,18 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddAssert("ensure mods not selected", () => modDisplay.Current.Value.Count == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExternallySetCustomizedMod()
|
||||
{
|
||||
AddStep("set customized mod externally", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.01 } } });
|
||||
|
||||
AddAssert("ensure button is selected and customized accordingly", () =>
|
||||
{
|
||||
var button = modSelect.GetModButton(SelectedMods.Value.Single());
|
||||
return ((OsuModDoubleTime)button.SelectedMod).SpeedChange.Value == 1.01;
|
||||
});
|
||||
}
|
||||
|
||||
private void testSingleMod(Mod mod)
|
||||
{
|
||||
selectNext(mod);
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Tournament.Screens;
|
||||
using osu.Game.Tournament.Screens.Setup;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Tournament.Screens;
|
||||
using osu.Game.Tournament.Screens.Setup;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.IO;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Tournament.Configuration;
|
||||
|
||||
namespace osu.Game.Tournament.IO
|
||||
@@ -13,25 +15,39 @@ namespace osu.Game.Tournament.IO
|
||||
{
|
||||
private const string default_tournament = "default";
|
||||
private readonly Storage storage;
|
||||
private readonly Storage allTournaments;
|
||||
private readonly TournamentStorageManager storageConfig;
|
||||
public readonly Bindable<string> CurrentTournament;
|
||||
|
||||
public TournamentStorage(Storage storage)
|
||||
: base(storage.GetStorageForDirectory("tournaments"), string.Empty)
|
||||
{
|
||||
this.storage = storage;
|
||||
allTournaments = UnderlyingStorage;
|
||||
|
||||
storageConfig = new TournamentStorageManager(storage);
|
||||
|
||||
if (storage.Exists("tournament.ini"))
|
||||
{
|
||||
ChangeTargetStorage(UnderlyingStorage.GetStorageForDirectory(storageConfig.Get<string>(StorageConfig.CurrentTournament)));
|
||||
ChangeTargetStorage(allTournaments.GetStorageForDirectory(storageConfig.Get<string>(StorageConfig.CurrentTournament)));
|
||||
}
|
||||
else
|
||||
Migrate(UnderlyingStorage.GetStorageForDirectory(default_tournament));
|
||||
Migrate(allTournaments.GetStorageForDirectory(default_tournament));
|
||||
|
||||
CurrentTournament = storageConfig.GetBindable<string>(StorageConfig.CurrentTournament);
|
||||
Logger.Log("Using tournament storage: " + GetFullPath(string.Empty));
|
||||
|
||||
CurrentTournament.BindValueChanged(updateTournament);
|
||||
}
|
||||
|
||||
private void updateTournament(ValueChangedEvent<string> newTournament)
|
||||
{
|
||||
ChangeTargetStorage(allTournaments.GetStorageForDirectory(newTournament.NewValue));
|
||||
Logger.Log("Changing tournament storage: " + GetFullPath(string.Empty));
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListTournaments() => allTournaments.GetDirectories(string.Empty);
|
||||
|
||||
public override void Migrate(Storage newStorage)
|
||||
{
|
||||
// this migration only happens once on moving to the per-tournament storage system.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// 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.Drawing;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Tournament
|
||||
{
|
||||
/// <summary>
|
||||
/// We made a change from using SixLabors.ImageSharp.Point to System.Drawing.Point at some stage.
|
||||
/// This handles converting to a standardised format on json serialize/deserialize operations.
|
||||
/// </summary>
|
||||
internal class JsonPointConverter : JsonConverter<Point>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, Point value, JsonSerializer serializer)
|
||||
{
|
||||
// use the format of LaborSharp's Point since it is nicer.
|
||||
serializer.Serialize(writer, new { value.X, value.Y });
|
||||
}
|
||||
|
||||
public override Point ReadJson(JsonReader reader, Type objectType, Point existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
{
|
||||
// if there's no object present then this is using string representation (System.Drawing.Point serializes to "x,y")
|
||||
string str = (string)reader.Value;
|
||||
|
||||
Debug.Assert(str != null);
|
||||
|
||||
return new PointConverter().ConvertFromString(str) as Point? ?? new Point();
|
||||
}
|
||||
|
||||
var point = new Point();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonToken.EndObject) break;
|
||||
|
||||
if (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
var name = reader.Value?.ToString();
|
||||
int? val = reader.ReadAsInt32();
|
||||
|
||||
if (val == null)
|
||||
continue;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "X":
|
||||
point.X = val.Value;
|
||||
break;
|
||||
|
||||
case "Y":
|
||||
point.Y = val.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tournament.Screens.Setup
|
||||
{
|
||||
internal class ActionableInfo : LabelledDrawable<Drawable>
|
||||
{
|
||||
protected OsuButton Button;
|
||||
|
||||
public ActionableInfo()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
public string ButtonText
|
||||
{
|
||||
set => Button.Text = value;
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
set => valueText.Text = value;
|
||||
}
|
||||
|
||||
public bool Failing
|
||||
{
|
||||
set => valueText.Colour = value ? Color4.Red : Color4.White;
|
||||
}
|
||||
|
||||
public Action Action;
|
||||
|
||||
private TournamentSpriteText valueText;
|
||||
protected FillFlowContainer FlowContainer;
|
||||
|
||||
protected override Drawable CreateComponent() => new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
valueText = new TournamentSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
},
|
||||
FlowContainer = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Button = new TriangleButton
|
||||
{
|
||||
Size = new Vector2(100, 40),
|
||||
Action = () => Action?.Invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Tournament.Screens.Setup
|
||||
{
|
||||
internal class ResolutionSelector : ActionableInfo
|
||||
{
|
||||
private const int minimum_window_height = 480;
|
||||
private const int maximum_window_height = 2160;
|
||||
|
||||
public new Action<int> Action;
|
||||
|
||||
private OsuNumberBox numberBox;
|
||||
|
||||
protected override Drawable CreateComponent()
|
||||
{
|
||||
var drawable = base.CreateComponent();
|
||||
FlowContainer.Insert(-1, numberBox = new OsuNumberBox
|
||||
{
|
||||
Text = "1080",
|
||||
Width = 100
|
||||
});
|
||||
|
||||
base.Action = () =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(numberBox.Text))
|
||||
return;
|
||||
|
||||
// box contains text
|
||||
if (!int.TryParse(numberBox.Text, out var number))
|
||||
{
|
||||
// at this point, the only reason we can arrive here is if the input number was too big to parse into an int
|
||||
// so clamp to max allowed value
|
||||
number = maximum_window_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
number = Math.Clamp(number, minimum_window_height, maximum_window_height);
|
||||
}
|
||||
|
||||
// in case number got clamped, reset number in numberBox
|
||||
numberBox.Text = number.ToString();
|
||||
|
||||
Action?.Invoke(number);
|
||||
};
|
||||
return drawable;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-109
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -17,9 +16,8 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tournament.Screens
|
||||
namespace osu.Game.Tournament.Screens.Setup
|
||||
{
|
||||
public class SetupScreen : TournamentScreen, IProvideVideo
|
||||
{
|
||||
@@ -64,9 +62,6 @@ namespace osu.Game.Tournament.Screens
|
||||
reload();
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private Framework.Game game { get; set; }
|
||||
|
||||
private void reload()
|
||||
{
|
||||
var fileBasedIpc = ipc as FileBasedIPC;
|
||||
@@ -111,6 +106,11 @@ namespace osu.Game.Tournament.Screens
|
||||
Items = rulesets.AvailableRulesets,
|
||||
Current = LadderInfo.Ruleset,
|
||||
},
|
||||
new TournamentSwitcher
|
||||
{
|
||||
Label = "Current tournament",
|
||||
Description = "Changes the background videos and bracket to match the selected tournament. This requires a restart to apply changes.",
|
||||
},
|
||||
resolution = new ResolutionSelector
|
||||
{
|
||||
Label = "Stream area resolution",
|
||||
@@ -151,108 +151,5 @@ namespace osu.Game.Tournament.Screens
|
||||
Width = 0.5f,
|
||||
};
|
||||
}
|
||||
|
||||
private class ActionableInfo : LabelledDrawable<Drawable>
|
||||
{
|
||||
private OsuButton button;
|
||||
|
||||
public ActionableInfo()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
public string ButtonText
|
||||
{
|
||||
set => button.Text = value;
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
set => valueText.Text = value;
|
||||
}
|
||||
|
||||
public bool Failing
|
||||
{
|
||||
set => valueText.Colour = value ? Color4.Red : Color4.White;
|
||||
}
|
||||
|
||||
public Action Action;
|
||||
|
||||
private TournamentSpriteText valueText;
|
||||
protected FillFlowContainer FlowContainer;
|
||||
|
||||
protected override Drawable CreateComponent() => new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
valueText = new TournamentSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
},
|
||||
FlowContainer = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
button = new TriangleButton
|
||||
{
|
||||
Size = new Vector2(100, 40),
|
||||
Action = () => Action?.Invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class ResolutionSelector : ActionableInfo
|
||||
{
|
||||
private const int minimum_window_height = 480;
|
||||
private const int maximum_window_height = 2160;
|
||||
|
||||
public new Action<int> Action;
|
||||
|
||||
private OsuNumberBox numberBox;
|
||||
|
||||
protected override Drawable CreateComponent()
|
||||
{
|
||||
var drawable = base.CreateComponent();
|
||||
FlowContainer.Insert(-1, numberBox = new OsuNumberBox
|
||||
{
|
||||
Text = "1080",
|
||||
Width = 100
|
||||
});
|
||||
|
||||
base.Action = () =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(numberBox.Text))
|
||||
return;
|
||||
|
||||
// box contains text
|
||||
if (!int.TryParse(numberBox.Text, out var number))
|
||||
{
|
||||
// at this point, the only reason we can arrive here is if the input number was too big to parse into an int
|
||||
// so clamp to max allowed value
|
||||
number = maximum_window_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
number = Math.Clamp(number, minimum_window_height, maximum_window_height);
|
||||
}
|
||||
|
||||
// in case number got clamped, reset number in numberBox
|
||||
numberBox.Text = number.ToString();
|
||||
|
||||
Action?.Invoke(number);
|
||||
};
|
||||
return drawable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -13,11 +13,11 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tournament.Screens
|
||||
namespace osu.Game.Tournament.Screens.Setup
|
||||
{
|
||||
public class StablePathSelectScreen : TournamentScreen
|
||||
{
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Tournament.IO;
|
||||
|
||||
namespace osu.Game.Tournament.Screens.Setup
|
||||
{
|
||||
internal class TournamentSwitcher : ActionableInfo
|
||||
{
|
||||
private OsuDropdown<string> dropdown;
|
||||
|
||||
[Resolved]
|
||||
private TournamentGameBase game { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TournamentStorage storage)
|
||||
{
|
||||
string startupTournament = storage.CurrentTournament.Value;
|
||||
|
||||
dropdown.Current = storage.CurrentTournament;
|
||||
dropdown.Items = storage.ListTournaments();
|
||||
dropdown.Current.BindValueChanged(v => Button.Enabled.Value = v.NewValue != startupTournament, true);
|
||||
|
||||
Action = () => game.GracefullyExit();
|
||||
|
||||
ButtonText = "Close osu!";
|
||||
}
|
||||
|
||||
protected override Drawable CreateComponent()
|
||||
{
|
||||
var drawable = base.CreateComponent();
|
||||
|
||||
FlowContainer.Insert(-1, dropdown = new OsuDropdown<string>
|
||||
{
|
||||
Width = 510
|
||||
});
|
||||
|
||||
return drawable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,12 @@ using Newtonsoft.Json;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.IO;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
@@ -40,6 +40,8 @@ namespace osu.Game.Tournament
|
||||
Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));
|
||||
|
||||
dependencies.CacheAs<Storage>(storage = new TournamentStorage(baseStorage));
|
||||
dependencies.CacheAs(storage);
|
||||
|
||||
dependencies.Cache(new TournamentVideoResourceStore(storage));
|
||||
|
||||
Textures.AddStore(new TextureLoaderStore(new StorageBackedResourceStore(storage)));
|
||||
@@ -60,7 +62,7 @@ namespace osu.Game.Tournament
|
||||
{
|
||||
using (Stream stream = storage.GetStream(bracket_filename, FileAccess.Read, FileMode.Open))
|
||||
using (var sr = new StreamReader(stream))
|
||||
ladder = JsonConvert.DeserializeObject<LadderInfo>(sr.ReadToEnd());
|
||||
ladder = JsonConvert.DeserializeObject<LadderInfo>(sr.ReadToEnd(), new JsonPointConverter());
|
||||
}
|
||||
|
||||
ladder ??= new LadderInfo();
|
||||
@@ -251,6 +253,7 @@ namespace osu.Game.Tournament
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DefaultValueHandling = DefaultValueHandling.Ignore,
|
||||
Converters = new JsonConverter[] { new JsonPointConverter() }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ using osu.Game.Tournament.Screens.Gameplay;
|
||||
using osu.Game.Tournament.Screens.Ladder;
|
||||
using osu.Game.Tournament.Screens.MapPool;
|
||||
using osu.Game.Tournament.Screens.Schedule;
|
||||
using osu.Game.Tournament.Screens.Setup;
|
||||
using osu.Game.Tournament.Screens.Showcase;
|
||||
using osu.Game.Tournament.Screens.TeamIntro;
|
||||
using osu.Game.Tournament.Screens.TeamWin;
|
||||
|
||||
@@ -50,7 +50,15 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
IBeatmap IBeatmap.Clone() => Clone();
|
||||
|
||||
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
|
||||
public Beatmap<T> Clone()
|
||||
{
|
||||
var clone = (Beatmap<T>)MemberwiseClone();
|
||||
|
||||
clone.ControlPointInfo = ControlPointInfo.CreateCopy();
|
||||
// todo: deep clone other elements as required.
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
public class Beatmap : Beatmap<HitObject>
|
||||
|
||||
@@ -260,17 +260,10 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
catch (BeatmapInvalidForRulesetException e)
|
||||
{
|
||||
// Conversion has failed for the given ruleset, so return the difficulty in the beatmap's default ruleset.
|
||||
|
||||
// Ensure the beatmap's default ruleset isn't the one already being converted to.
|
||||
// This shouldn't happen as it means something went seriously wrong, but if it does an endless loop should be avoided.
|
||||
if (rulesetInfo.Equals(beatmapInfo.Ruleset))
|
||||
{
|
||||
Logger.Error(e, $"Failed to convert {beatmapInfo.OnlineBeatmapID} to the beatmap's default ruleset ({beatmapInfo.Ruleset}).");
|
||||
return new StarDifficulty();
|
||||
}
|
||||
|
||||
return GetAsync(new DifficultyCacheLookup(key.Beatmap, key.Beatmap.Ruleset, key.OrderedMods)).Result;
|
||||
return new StarDifficulty();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -31,6 +31,11 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public BeatmapSetOnlineStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not this beatmap set has explicit content.
|
||||
/// </summary>
|
||||
public bool HasExplicitContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not this beatmap set has a background video.
|
||||
/// </summary>
|
||||
|
||||
@@ -28,5 +28,21 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// <param name="existing">An existing control point to compare with.</param>
|
||||
/// <returns>Whether this <see cref="ControlPoint"/> is redundant when placed alongside <paramref name="existing"/>.</returns>
|
||||
public abstract bool IsRedundant(ControlPoint existing);
|
||||
|
||||
/// <summary>
|
||||
/// Create an unbound copy of this control point.
|
||||
/// </summary>
|
||||
public ControlPoint CreateCopy()
|
||||
{
|
||||
var copy = (ControlPoint)Activator.CreateInstance(GetType());
|
||||
|
||||
copy.CopyFrom(this);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public virtual void CopyFrom(ControlPoint other)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,5 +297,15 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ControlPointInfo CreateCopy()
|
||||
{
|
||||
var controlPointInfo = new ControlPointInfo();
|
||||
|
||||
foreach (var point in AllControlPoints)
|
||||
controlPointInfo.Add(point.Time, point.CreateCopy());
|
||||
|
||||
return controlPointInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,5 +39,12 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
public override bool IsRedundant(ControlPoint existing)
|
||||
=> existing is DifficultyControlPoint existingDifficulty
|
||||
&& SpeedMultiplier == existingDifficulty.SpeedMultiplier;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
SpeedMultiplier = ((DifficultyControlPoint)other).SpeedMultiplier;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,5 +50,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
&& existing is EffectControlPoint existingEffect
|
||||
&& KiaiMode == existingEffect.KiaiMode
|
||||
&& OmitFirstBarLine == existingEffect.OmitFirstBarLine;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
KiaiMode = ((EffectControlPoint)other).KiaiMode;
|
||||
OmitFirstBarLine = ((EffectControlPoint)other).OmitFirstBarLine;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,5 +72,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
=> existing is SampleControlPoint existingSample
|
||||
&& SampleBank == existingSample.SampleBank
|
||||
&& SampleVolume == existingSample.SampleVolume;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
SampleVolume = ((SampleControlPoint)other).SampleVolume;
|
||||
SampleBank = ((SampleControlPoint)other).SampleBank;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,5 +69,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
|
||||
// Timing points are never redundant as they can change the time signature.
|
||||
public override bool IsRedundant(ControlPoint existing) => false;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
TimeSignature = ((TimingControlPoint)other).TimeSignature;
|
||||
BeatLength = ((TimingControlPoint)other).BeatLength;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,13 +164,25 @@ namespace osu.Game.Beatmaps.Formats
|
||||
/// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it.
|
||||
/// DO NOT USE THIS UNLESS 100% SURE.
|
||||
/// </summary>
|
||||
public readonly float BpmMultiplier;
|
||||
public double BpmMultiplier { get; private set; }
|
||||
|
||||
public LegacyDifficultyControlPoint(double beatLength)
|
||||
: this()
|
||||
{
|
||||
// Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?).
|
||||
BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1;
|
||||
}
|
||||
|
||||
public LegacyDifficultyControlPoint()
|
||||
{
|
||||
SpeedMultiplierBindable.Precision = double.Epsilon;
|
||||
}
|
||||
|
||||
BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100f : 1;
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
base.CopyFrom(other);
|
||||
|
||||
BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +204,13 @@ namespace osu.Game.Beatmaps.Formats
|
||||
=> base.IsRedundant(existing)
|
||||
&& existing is LegacySampleControlPoint existingSample
|
||||
&& CustomSampleBank == existingSample.CustomSampleBank;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
base.CopyFrom(other);
|
||||
|
||||
CustomSampleBank = ((LegacySampleControlPoint)other).CustomSampleBank;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.ComponentModel;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum DiscordRichPresenceMode
|
||||
{
|
||||
Off,
|
||||
|
||||
[Description("Hide identifiable information")]
|
||||
Limited,
|
||||
|
||||
Full
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
@@ -60,6 +60,8 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.ExternalLinkWarning, true);
|
||||
Set(OsuSetting.PreferNoVideo, false);
|
||||
|
||||
Set(OsuSetting.ShowOnlineExplicitContent, false);
|
||||
|
||||
// Audio
|
||||
Set(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
||||
|
||||
@@ -82,6 +84,7 @@ namespace osu.Game.Configuration
|
||||
|
||||
Set(OsuSetting.ShowStoryboard, true);
|
||||
Set(OsuSetting.BeatmapSkins, true);
|
||||
Set(OsuSetting.BeatmapColours, true);
|
||||
Set(OsuSetting.BeatmapHitsounds, true);
|
||||
|
||||
Set(OsuSetting.CursorRotation, true);
|
||||
@@ -138,6 +141,8 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
|
||||
Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes);
|
||||
|
||||
Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
|
||||
|
||||
Set(OsuSetting.EditorWaveformOpacity, 1f);
|
||||
}
|
||||
|
||||
@@ -248,6 +253,7 @@ namespace osu.Game.Configuration
|
||||
ScreenshotCaptureMenuCursor,
|
||||
SongSelectRightMouseScroll,
|
||||
BeatmapSkins,
|
||||
BeatmapColours,
|
||||
BeatmapHitsounds,
|
||||
IncreaseFirstObjectVisibility,
|
||||
ScoreDisplayMode,
|
||||
@@ -266,6 +272,8 @@ namespace osu.Game.Configuration
|
||||
GameplayDisableWinKey,
|
||||
SeasonalBackgroundMode,
|
||||
EditorWaveformOpacity,
|
||||
DiscordRichPresence,
|
||||
AutomaticallyDownloadWhenSpectating,
|
||||
ShowOnlineExplicitContent,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// 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.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
@@ -14,6 +16,7 @@ namespace osu.Game.Configuration
|
||||
{
|
||||
Set(Static.LoginOverlayDisplayed, false);
|
||||
Set(Static.MutedAudioNotificationShownOnce, false);
|
||||
Set(Static.LastHoverSoundPlaybackTime, (double?)null);
|
||||
Set<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||
}
|
||||
}
|
||||
@@ -28,5 +31,11 @@ namespace osu.Game.Configuration
|
||||
/// Value under this lookup can be <c>null</c> if there are no backgrounds available (or API is not reachable).
|
||||
/// </summary>
|
||||
SeasonalBackgrounds,
|
||||
|
||||
/// <summary>
|
||||
/// The last playback time in milliseconds of a hover sample (from <see cref="HoverSounds"/>).
|
||||
/// Used to debounce hover sounds game-wide to avoid volume saturation, especially in scrolling views with many UI controls like <see cref="SettingsOverlay"/>.
|
||||
/// </summary>
|
||||
LastHoverSoundPlaybackTime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,13 +115,13 @@ namespace osu.Game.Database
|
||||
return Import(notification, paths.Select(p => new ImportTask(p)).ToArray());
|
||||
}
|
||||
|
||||
public Task Import(Stream stream, string filename)
|
||||
public Task Import(params ImportTask[] tasks)
|
||||
{
|
||||
var notification = new ProgressNotification { State = ProgressNotificationState.Active };
|
||||
|
||||
PostNotification?.Invoke(notification);
|
||||
|
||||
return Import(notification, new ImportTask(stream, filename));
|
||||
return Import(notification, tasks);
|
||||
}
|
||||
|
||||
protected async Task<IEnumerable<TModel>> Import(ProgressNotification notification, params ImportTask[] tasks)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@@ -19,11 +18,10 @@ namespace osu.Game.Database
|
||||
Task Import(params string[] paths);
|
||||
|
||||
/// <summary>
|
||||
/// Import the provided stream as a simple item.
|
||||
/// Import the specified files from the given import tasks.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to import files from. Should be in a supported archive format.</param>
|
||||
/// <param name="filename">The filename of the archive being imported.</param>
|
||||
Task Import(Stream stream, string filename);
|
||||
/// <param name="tasks">The import tasks from which the files should be imported.</param>
|
||||
Task Import(params ImportTask[] tasks);
|
||||
|
||||
/// <summary>
|
||||
/// An array of accepted file extensions (in the standard format of ".abc").
|
||||
|
||||
@@ -135,6 +135,8 @@ namespace osu.Game.Database
|
||||
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.IntAction);
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().Ignore(b => b.KeyCombination);
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().Ignore(b => b.Action);
|
||||
|
||||
modelBuilder.Entity<DatabasedSetting>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Extensions.ExceptionExtensions;
|
||||
using osu.Framework.Logging;
|
||||
|
||||
namespace osu.Game.Extensions
|
||||
@@ -13,13 +17,19 @@ namespace osu.Game.Extensions
|
||||
/// Avoids unobserved exceptions from being fired.
|
||||
/// </summary>
|
||||
/// <param name="task">The task.</param>
|
||||
/// <param name="logOnError">Whether errors should be logged as important, or silently ignored.</param>
|
||||
public static void CatchUnobservedExceptions(this Task task, bool logOnError = false)
|
||||
/// <param name="logAsError">
|
||||
/// Whether errors should be logged as errors visible to users, or as debug messages.
|
||||
/// Logging as debug will essentially silence the errors on non-release builds.
|
||||
/// </param>
|
||||
public static void CatchUnobservedExceptions(this Task task, bool logAsError = false)
|
||||
{
|
||||
task.ContinueWith(t =>
|
||||
{
|
||||
if (logOnError)
|
||||
Logger.Log($"Error running task: {t.Exception?.Message ?? "unknown"}", LoggingTarget.Runtime, LogLevel.Important);
|
||||
Exception? exception = t.Exception?.AsSingular();
|
||||
if (logAsError)
|
||||
Logger.Error(exception, $"Error running task: {exception?.Message ?? "(unknown)"}", LoggingTarget.Runtime, true);
|
||||
else
|
||||
Logger.Log($"Error running task: {exception}", LoggingTarget.Runtime, LogLevel.Debug);
|
||||
}, TaskContinuationOptions.NotOnRanToCompletion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
TooltipText = "Downloading...";
|
||||
break;
|
||||
|
||||
case DownloadState.Downloaded:
|
||||
case DownloadState.Importing:
|
||||
background.FadeColour(colours.Yellow, 500, Easing.InOutExpo);
|
||||
TooltipText = "Importing";
|
||||
break;
|
||||
|
||||
@@ -5,11 +5,12 @@ using System.ComponentModel;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
@@ -22,37 +23,40 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
/// <summary>
|
||||
/// Length of debounce for hover sound playback, in milliseconds. Default is 50ms.
|
||||
/// Length of debounce for hover sound playback, in milliseconds.
|
||||
/// </summary>
|
||||
public double HoverDebounceTime { get; } = 50;
|
||||
public double HoverDebounceTime { get; } = 20;
|
||||
|
||||
protected readonly HoverSampleSet SampleSet;
|
||||
|
||||
private Bindable<double?> lastPlaybackTime;
|
||||
|
||||
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
||||
{
|
||||
SampleSet = sampleSet;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
private ScheduledDelegate playDelegate;
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, SessionStatics statics)
|
||||
{
|
||||
lastPlaybackTime = statics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime);
|
||||
|
||||
sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
playDelegate?.Cancel();
|
||||
bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime;
|
||||
|
||||
if (HoverDebounceTime <= 0)
|
||||
if (enoughTimePassedSinceLastPlayback)
|
||||
{
|
||||
sampleHover?.Play();
|
||||
else
|
||||
playDelegate = Scheduler.AddDelayed(() => sampleHover?.Play(), HoverDebounceTime);
|
||||
lastPlaybackTime.Value = Time.Current;
|
||||
}
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
|
||||
}
|
||||
}
|
||||
|
||||
public enum HoverSampleSet
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@@ -17,22 +18,32 @@ namespace osu.Game.Graphics.UserInterface
|
||||
/// </summary>
|
||||
public class LoadingLayer : LoadingSpinner
|
||||
{
|
||||
private readonly Drawable dimTarget;
|
||||
[CanBeNull]
|
||||
protected Box BackgroundDimLayer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constuct a new loading spinner.
|
||||
/// Construct a new loading spinner.
|
||||
/// </summary>
|
||||
/// <param name="dimTarget">An optional target to dim when displayed.</param>
|
||||
/// <param name="dimBackground">Whether the full background area should be dimmed while loading.</param>
|
||||
/// <param name="withBox">Whether the spinner should have a surrounding black box for visibility.</param>
|
||||
public LoadingLayer(Drawable dimTarget = null, bool withBox = true)
|
||||
public LoadingLayer(bool dimBackground = false, bool withBox = true)
|
||||
: base(withBox)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Size = new Vector2(1);
|
||||
|
||||
this.dimTarget = dimTarget;
|
||||
|
||||
MainContents.RelativeSizeAxes = Axes.None;
|
||||
|
||||
if (dimBackground)
|
||||
{
|
||||
AddInternal(BackgroundDimLayer = new Box
|
||||
{
|
||||
Depth = float.MaxValue,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandleNonPositionalInput => false;
|
||||
@@ -56,31 +67,21 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
dimTarget?.FadeColour(OsuColour.Gray(0.5f), TRANSITION_DURATION, Easing.OutQuint);
|
||||
BackgroundDimLayer?.FadeTo(0.5f, TRANSITION_DURATION * 2, Easing.OutQuint);
|
||||
base.PopIn();
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||
BackgroundDimLayer?.FadeOut(TRANSITION_DURATION, Easing.OutQuint);
|
||||
base.PopOut();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (State.Value == Visibility.Visible)
|
||||
{
|
||||
// ensure we don't leave the target in a bad state.
|
||||
dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace osu.Game.Input.Bindings
|
||||
|
||||
private KeyBindingStore store;
|
||||
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings(variant ?? 0);
|
||||
public override IEnumerable<IKeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings(variant ?? 0);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance.
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace osu.Game.Input.Bindings
|
||||
handler = game;
|
||||
}
|
||||
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings).Concat(AudioControlKeyBindings).Concat(EditorKeyBindings);
|
||||
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings).Concat(AudioControlKeyBindings).Concat(EditorKeyBindings);
|
||||
|
||||
public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
|
||||
|
||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||
@@ -112,8 +112,8 @@ namespace osu.Game.Input.Bindings
|
||||
[Description("Toggle settings")]
|
||||
ToggleSettings,
|
||||
|
||||
[Description("Toggle osu!direct")]
|
||||
ToggleDirect,
|
||||
[Description("Toggle beatmap listing")]
|
||||
ToggleBeatmapListing,
|
||||
|
||||
[Description("Increase volume")]
|
||||
IncreaseVolume,
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace osu.Game.Input
|
||||
}
|
||||
}
|
||||
|
||||
private void insertDefaults(IEnumerable<KeyBinding> defaults, int? rulesetId = null, int? variant = null)
|
||||
private void insertDefaults(IEnumerable<IKeyBinding> defaults, int? rulesetId = null, int? variant = null)
|
||||
{
|
||||
using (var usage = ContextFactory.GetForWrite())
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -293,8 +294,21 @@ namespace osu.Game.Online.API
|
||||
failureCount = 0;
|
||||
return true;
|
||||
}
|
||||
catch (HttpRequestException re)
|
||||
{
|
||||
log.Add($"{nameof(HttpRequestException)} while performing request {req}: {re.Message}");
|
||||
handleFailure();
|
||||
return false;
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
log.Add($"{nameof(SocketException)} while performing request {req}: {se.Message}");
|
||||
handleFailure();
|
||||
return false;
|
||||
}
|
||||
catch (WebException we)
|
||||
{
|
||||
log.Add($"{nameof(WebException)} while performing request {req}: {we.Message}");
|
||||
handleWebException(we);
|
||||
return false;
|
||||
}
|
||||
@@ -312,7 +326,7 @@ namespace osu.Game.Online.API
|
||||
/// </summary>
|
||||
public IBindable<APIState> State => state;
|
||||
|
||||
private bool handleWebException(WebException we)
|
||||
private void handleWebException(WebException we)
|
||||
{
|
||||
HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode
|
||||
?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout);
|
||||
@@ -330,26 +344,24 @@ namespace osu.Game.Online.API
|
||||
{
|
||||
case HttpStatusCode.Unauthorized:
|
||||
Logout();
|
||||
return true;
|
||||
break;
|
||||
|
||||
case HttpStatusCode.RequestTimeout:
|
||||
failureCount++;
|
||||
log.Add($@"API failure count is now {failureCount}");
|
||||
|
||||
if (failureCount < 3)
|
||||
// we might try again at an api level.
|
||||
return false;
|
||||
|
||||
if (State.Value == APIState.Online)
|
||||
{
|
||||
state.Value = APIState.Failing;
|
||||
flushQueue();
|
||||
}
|
||||
|
||||
return true;
|
||||
handleFailure();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
private void handleFailure()
|
||||
{
|
||||
failureCount++;
|
||||
log.Add($@"API failure count is now {failureCount}");
|
||||
|
||||
if (failureCount >= 3 && State.Value == APIState.Online)
|
||||
{
|
||||
state.Value = APIState.Failing;
|
||||
flushQueue();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLoggedIn => localUser.Value.Id > 1;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user