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

Compare commits

...

148 Commits

117 changed files with 1750 additions and 486 deletions
+1
View File
@@ -14,6 +14,7 @@ App.config text eol=crlf
*.bat text eol=crlf
*.cmd text eol=crlf
*.snippet text eol=crlf
*.manifest text eol=crlf
# Check out with lf (UNIX) line endings
*.sh text eol=lf
@@ -0,0 +1,22 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (catch)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -0,0 +1,22 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -0,0 +1,22 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -0,0 +1,22 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (taiko)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="VisualTests (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe" />
<configuration default="false" name="VisualTests (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
@@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<method />
</configuration>
</component>
@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net461/osu!.exe" />
<configuration default="false" name="osu! (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net471/osu!.exe" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
<option name="PASS_PARENT_ENVS" value="1" />
@@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
<method />
</configuration>
</component>
+8 -8
View File
@@ -2,13 +2,13 @@
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net461)",
"name": "VisualTests (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
@@ -16,13 +16,13 @@
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net461)",
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
@@ -30,13 +30,13 @@
"console": "internalConsole"
},
{
"name": "osu! (Debug, net461)",
"name": "osu! (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net461/osu!.exe",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net471/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
@@ -44,13 +44,13 @@
"console": "internalConsole"
},
{
"name": "osu! (Release, net461)",
"name": "osu! (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net461/osu!.exe",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net471/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
+3 -3
View File
@@ -8,7 +8,7 @@
"type": "shell",
"command": "msbuild",
"args": [
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -22,7 +22,7 @@
"command": "msbuild",
"args": [
"/p:Configuration=Release",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -64,7 +64,7 @@
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net461)",
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
+1 -1
View File
@@ -8,7 +8,7 @@ This is still heavily under development and is not intended for end-user use. Th
# Requirements
- A desktop platform that can compile .NET 4.6.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
- A desktop platform that can compile .NET 4.7.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
# Getting Started
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
+46
View File
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" name="osu!" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
<applicationRequestMinimum>
<defaultAssemblyRequest permissionSetReference="Custom" />
<PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
</applicationRequestMinimum>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</asmv1:assembly>
+25 -26
View File
@@ -1,27 +1,26 @@
# 2017-09-14
clone_depth: 1
version: '{branch}-{build}'
image: Visual Studio 2017
configuration: Debug
cache:
- C:\ProgramData\chocolatey\bin -> appveyor.yml
- C:\ProgramData\chocolatey\lib -> appveyor.yml
- inspectcode -> appveyor.yml
- packages -> **\packages.config
install:
- cmd: git submodule update --init --recursive --depth=5
- cmd: choco install resharper-clt -y
- cmd: choco install nvika -y
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
before_build:
- cmd: CodeFileSanity.exe
- cmd: nuget restore -verbosity quiet
environment:
TargetFramework: net461
build:
project: osu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
clone_depth: 1
version: '{branch}-{build}'
image: Visual Studio 2017
configuration: Debug
cache:
- C:\ProgramData\chocolatey\bin -> appveyor.yml
- C:\ProgramData\chocolatey\lib -> appveyor.yml
- inspectcode -> appveyor.yml
- packages -> **\packages.config
install:
- cmd: git submodule update --init --recursive --depth=5
- cmd: choco install resharper-clt -y
- cmd: choco install nvika -y
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
before_build:
- cmd: CodeFileSanity.exe
- cmd: nuget restore -verbosity quiet
environment:
TargetFramework: net471
build:
project: osu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
+34
View File
@@ -0,0 +1,34 @@
branches:
only:
- release
skip_tags: true
skip_branch_with_pr: true
clone_depth: 1
version: '{branch}-{build}'
image: Visual Studio 2017
configuration: Debug
cache:
- packages -> **\packages.config
install:
- cmd: git submodule update --init --recursive --depth=5
before_build:
- cmd: nuget restore -verbosity quiet
build:
project: osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
verbosity: minimal
after_build:
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
- appveyor DownloadFile https://puu.sh/A6g5K/4d08705438.enc # signing certificate
- cmd: appveyor-tools\secure-file -decrypt 4d08705438.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx
- appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
- cmd: appveyor-tools\secure-file -decrypt fdc6f19b04.enc -secret %decode_secret% -out osu.Desktop.Deploy\bin\Debug\net471\osu.Desktop.Deploy.exe.config
- cd osu.Desktop.Deploy\bin\Debug\net471\
- osu.Desktop.Deploy.exe %code_signing_password%
environment:
TargetFramework: net471
decode_secret:
secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY=
code_signing_password:
secure: 34tLNqvjmmZEi97MLKfrnQ==
artifacts:
- path: 'Releases\*'
+2 -2
View File
@@ -7,7 +7,7 @@
"name": "Deploy (Debug)",
"request": "launch",
"type": "mono",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Desktop.Deploy.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Desktop.Deploy.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
"runtimeExecutable": null,
@@ -18,7 +18,7 @@
"name": "Deploy (Release)",
"request": "launch",
"type": "clr",
"program": "${workspaceRoot}/bin/Release/net461/osu.Desktop.Deploy.exe",
"program": "${workspaceRoot}/bin/Release/net471/osu.Desktop.Deploy.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",
"runtimeExecutable": null,
+38 -5
View File
@@ -7,6 +7,7 @@ using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
@@ -57,8 +58,12 @@ namespace osu.Desktop.Deploy
private static string codeSigningPassword;
private static bool interactive;
public static void Main(string[] args)
{
interactive = args.Length == 0;
displayHeader();
findSolutionPath();
@@ -82,19 +87,20 @@ namespace osu.Desktop.Deploy
string version = $"{verBase}{increment}";
Console.ForegroundColor = ConsoleColor.White;
Console.Write($"Ready to deploy {version}: ");
Console.ReadLine();
Console.Write($"Ready to deploy {version}!");
pauseIfInteractive();
sw.Start();
if (!string.IsNullOrEmpty(CodeSigningCertificate))
{
Console.Write("Enter code signing password: ");
codeSigningPassword = readLineMasked();
codeSigningPassword = args.Length > 0 ? args[0] : readLineMasked();
}
write("Updating AssemblyInfo...");
updateCsprojVersion(version);
updateAppveyorVersion(version);
write("Running build process...");
foreach (string targetName in TargetNames.Split(','))
@@ -124,7 +130,7 @@ namespace osu.Desktop.Deploy
updateCsprojVersion("0.0.0");
write("Done!", ConsoleColor.White);
Console.ReadLine();
pauseIfInteractive();
}
private static void displayHeader()
@@ -388,10 +394,37 @@ namespace osu.Desktop.Deploy
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"FATAL ERROR: {message}");
Console.ReadLine();
pauseIfInteractive();
Environment.Exit(-1);
}
private static void pauseIfInteractive()
{
if (interactive)
Console.ReadLine();
else
Console.WriteLine();
}
private static bool updateAppveyorVersion(string version)
{
try
{
using (PowerShell ps = PowerShell.Create())
{
ps.AddScript($"Update-AppveyorBuild -Version \"{version}\"");
ps.Invoke();
}
return true;
}
catch
{
// we don't have appveyor and don't care
}
return false;
}
private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
{
if (sw.ElapsedMilliseconds > 0)
+4 -3
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\osu.Game.props" />
<PropertyGroup Label="Project">
<TargetFrameworks>net461</TargetFrameworks>
<TargetFrameworks>net471</TargetFrameworks>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -12,7 +12,8 @@
<ItemGroup Label="Package References">
<PackageReference Include="NuGet.CommandLine" Version="4.5.1" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net471'" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
<PackageReference Include="System.Management.Automation.dll" Version="10.0.10586" />
</ItemGroup>
</Project>
+3 -3
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\osu.Game.props" />
<PropertyGroup Label="Project">
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
<TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
<OutputType>WinExe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -14,7 +14,7 @@
<FileVersion>0.0.0.0</FileVersion>
</PropertyGroup>
<PropertyGroup Label="Defines">
<DefineConstants Condition="'$(TargetFramework)' == 'net461'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'net471'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<StartupObject>osu.Desktop.Program</StartupObject>
@@ -31,7 +31,7 @@
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net471'" />
</ItemGroup>
<ItemGroup Label="Resources">
<EmbeddedResource Include="lazer.ico" />
+4 -4
View File
@@ -2,13 +2,13 @@
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net461)",
"name": "VisualTests (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
@@ -16,13 +16,13 @@
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net461)",
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
+3 -3
View File
@@ -9,7 +9,7 @@
"command": "msbuild",
"args": [
"osu.Game.Rulesets.Catch.Tests.csproj",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -24,7 +24,7 @@
"args": [
"osu.Game.Rulesets.Catch.Tests.csproj",
"/p:Configuration=Release",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -66,7 +66,7 @@
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net461)",
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
@@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
+39
View File
@@ -12,6 +12,7 @@ using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy;
namespace osu.Game.Rulesets.Catch
{
@@ -29,6 +30,44 @@ namespace osu.Game.Rulesets.Catch
new KeyBinding(InputKey.Shift, CatchAction.Dash),
};
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
{
if (mods.HasFlag(LegacyMods.Nightcore))
yield return new CatchModNightcore();
else if (mods.HasFlag(LegacyMods.DoubleTime))
yield return new CatchModDoubleTime();
if (mods.HasFlag(LegacyMods.Autoplay))
yield return new CatchModAutoplay();
if (mods.HasFlag(LegacyMods.Easy))
yield return new CatchModEasy();
if (mods.HasFlag(LegacyMods.Flashlight))
yield return new CatchModFlashlight();
if (mods.HasFlag(LegacyMods.HalfTime))
yield return new CatchModHalfTime();
if (mods.HasFlag(LegacyMods.HardRock))
yield return new CatchModHardRock();
if (mods.HasFlag(LegacyMods.Hidden))
yield return new CatchModHidden();
if (mods.HasFlag(LegacyMods.NoFail))
yield return new CatchModNoFail();
if (mods.HasFlag(LegacyMods.Perfect))
yield return new CatchModPerfect();
if (mods.HasFlag(LegacyMods.Relax))
yield return new CatchModRelax();
if (mods.HasFlag(LegacyMods.SuddenDeath))
yield return new CatchModSuddenDeath();
}
public override IEnumerable<Mod> GetModsFor(ModType type)
{
switch (type)
@@ -1,13 +1,88 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
using System;
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModHardRock : ModHardRock
public class CatchModHardRock : ModHardRock, IApplicableToHitObject<CatchHitObject>
{
public override double ScoreMultiplier => 1.12;
public override bool Ranked => true;
private float lastStartX;
private int lastStartTime;
public void ApplyToHitObject(CatchHitObject hitObject)
{
float position = hitObject.X;
int startTime = (int)hitObject.StartTime;
if (lastStartX == 0)
{
lastStartX = position;
lastStartTime = startTime;
return;
}
float diff = lastStartX - position;
int timeDiff = startTime - lastStartTime;
if (timeDiff > 1000)
{
lastStartX = position;
lastStartTime = startTime;
return;
}
if (diff == 0)
{
bool right = RNG.NextBool();
float rand = Math.Min(20, (float)RNG.NextDouble(0, timeDiff / 4d)) / CatchPlayfield.BASE_WIDTH;
if (right)
{
if (position + rand <= 1)
position += rand;
else
position -= rand;
}
else
{
if (position - rand >= 0)
position -= rand;
else
position += rand;
}
hitObject.X = position;
return;
}
if (Math.Abs(diff) < timeDiff / 3d)
{
if (diff > 0)
{
if (position - diff > 0)
position -= diff;
}
else
{
if (position - diff < 1)
position -= diff;
}
}
hitObject.X = position;
lastStartX = position;
lastStartTime = startTime;
}
}
}
+4 -4
View File
@@ -2,13 +2,13 @@
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net461)",
"name": "VisualTests (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
@@ -16,13 +16,13 @@
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net461)",
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
+3 -3
View File
@@ -9,7 +9,7 @@
"command": "msbuild",
"args": [
"osu.Game.Rulesets.Mania.Tests.csproj",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -24,7 +24,7 @@
"args": [
"osu.Game.Rulesets.Mania.Tests.csproj",
"/p:Configuration=Release",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -66,7 +66,7 @@
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net461)",
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
@@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
+69
View File
@@ -14,6 +14,7 @@ using osu.Framework.Input.Bindings;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy;
namespace osu.Game.Rulesets.Mania
{
@@ -21,6 +22,74 @@ namespace osu.Game.Rulesets.Mania
{
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new ManiaRulesetContainer(this, beatmap, isForCurrentRuleset);
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
{
if (mods.HasFlag(LegacyMods.Nightcore))
yield return new ManiaModNightcore();
else if (mods.HasFlag(LegacyMods.DoubleTime))
yield return new ManiaModDoubleTime();
if (mods.HasFlag(LegacyMods.Autoplay))
yield return new ManiaModAutoplay();
if (mods.HasFlag(LegacyMods.Easy))
yield return new ManiaModEasy();
if (mods.HasFlag(LegacyMods.FadeIn))
yield return new ManiaModFadeIn();
if (mods.HasFlag(LegacyMods.Flashlight))
yield return new ManiaModFlashlight();
if (mods.HasFlag(LegacyMods.HalfTime))
yield return new ManiaModHalfTime();
if (mods.HasFlag(LegacyMods.HardRock))
yield return new ManiaModHardRock();
if (mods.HasFlag(LegacyMods.Hidden))
yield return new ManiaModHidden();
if (mods.HasFlag(LegacyMods.Key1))
yield return new ManiaModKey1();
if (mods.HasFlag(LegacyMods.Key2))
yield return new ManiaModKey2();
if (mods.HasFlag(LegacyMods.Key3))
yield return new ManiaModKey3();
if (mods.HasFlag(LegacyMods.Key4))
yield return new ManiaModKey4();
if (mods.HasFlag(LegacyMods.Key5))
yield return new ManiaModKey5();
if (mods.HasFlag(LegacyMods.Key6))
yield return new ManiaModKey6();
if (mods.HasFlag(LegacyMods.Key7))
yield return new ManiaModKey7();
if (mods.HasFlag(LegacyMods.Key8))
yield return new ManiaModKey8();
if (mods.HasFlag(LegacyMods.Key9))
yield return new ManiaModKey9();
if (mods.HasFlag(LegacyMods.NoFail))
yield return new ManiaModNoFail();
if (mods.HasFlag(LegacyMods.Perfect))
yield return new ManiaModPerfect();
if (mods.HasFlag(LegacyMods.Random))
yield return new ManiaModRandom();
if (mods.HasFlag(LegacyMods.SuddenDeath))
yield return new ManiaModSuddenDeath();
}
public override IEnumerable<Mod> GetModsFor(ModType type)
{
switch (type)
+4 -4
View File
@@ -2,13 +2,13 @@
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net461)",
"name": "VisualTests (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
@@ -16,13 +16,13 @@
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net461)",
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
+3 -3
View File
@@ -9,7 +9,7 @@
"command": "msbuild",
"args": [
"osu.Game.Rulesets.Osu.Tests.csproj",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -24,7 +24,7 @@
"args": [
"osu.Game.Rulesets.Osu.Tests.csproj",
"/p:Configuration=Release",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -66,7 +66,7 @@
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net461)",
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
@@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
@@ -7,7 +7,6 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuEditPlayfield : OsuPlayfield
{
protected override bool ProxyApproachCircles => false;
protected override bool DisplayJudgements => false;
}
}
@@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
Children = new[]
{
Background = new SpinnerBackground
{
+48
View File
@@ -21,6 +21,7 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy;
namespace osu.Game.Rulesets.Osu
{
@@ -66,6 +67,53 @@ namespace osu.Game.Rulesets.Osu
};
}
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
{
if (mods.HasFlag(LegacyMods.Nightcore))
yield return new OsuModNightcore();
else if (mods.HasFlag(LegacyMods.DoubleTime))
yield return new OsuModDoubleTime();
if (mods.HasFlag(LegacyMods.Autopilot))
yield return new OsuModAutopilot();
if (mods.HasFlag(LegacyMods.Autoplay))
yield return new OsuModAutoplay();
if (mods.HasFlag(LegacyMods.Easy))
yield return new OsuModEasy();
if (mods.HasFlag(LegacyMods.Flashlight))
yield return new OsuModFlashlight();
if (mods.HasFlag(LegacyMods.HalfTime))
yield return new OsuModHalfTime();
if (mods.HasFlag(LegacyMods.HardRock))
yield return new OsuModHardRock();
if (mods.HasFlag(LegacyMods.Hidden))
yield return new OsuModHidden();
if (mods.HasFlag(LegacyMods.NoFail))
yield return new OsuModNoFail();
if (mods.HasFlag(LegacyMods.Perfect))
yield return new OsuModPerfect();
if (mods.HasFlag(LegacyMods.Relax))
yield return new OsuModRelax();
if (mods.HasFlag(LegacyMods.SpunOut))
yield return new OsuModSpunOut();
if (mods.HasFlag(LegacyMods.SuddenDeath))
yield return new OsuModSuddenDeath();
if (mods.HasFlag(LegacyMods.Target))
yield return new OsuModTarget();
}
public override IEnumerable<Mod> GetModsFor(ModType type)
{
switch (type)
+1 -4
View File
@@ -21,9 +21,6 @@ namespace osu.Game.Rulesets.Osu.UI
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
// Todo: This should not be a thing, but is currently required for the editor
// https://github.com/ppy/osu-framework/issues/1283
protected virtual bool ProxyApproachCircles => true;
protected virtual bool DisplayJudgements => true;
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
@@ -59,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.UI
h.OnJudgement += onJudgement;
var c = h as IDrawableHitObjectWithProxiedApproach;
if (c != null && ProxyApproachCircles)
if (c != null)
approachCircles.Add(c.ProxiedLayer.CreateProxy());
base.Add(h);
+4 -4
View File
@@ -2,13 +2,13 @@
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net461)",
"name": "VisualTests (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
@@ -16,13 +16,13 @@
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net461)",
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
+3 -3
View File
@@ -9,7 +9,7 @@
"command": "msbuild",
"args": [
"osu.Game.Rulesets.Taiko.Tests.csproj",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -24,7 +24,7 @@
"args": [
"osu.Game.Rulesets.Taiko.Tests.csproj",
"/p:Configuration=Release",
"/p:TargetFramework=net461",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -66,7 +66,7 @@
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net461)",
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
@@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
+39
View File
@@ -12,6 +12,7 @@ using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Taiko.Replays;
using osu.Game.Beatmaps.Legacy;
namespace osu.Game.Rulesets.Taiko
{
@@ -31,6 +32,44 @@ namespace osu.Game.Rulesets.Taiko
new KeyBinding(InputKey.MouseRight, TaikoAction.RightRim),
};
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
{
if (mods.HasFlag(LegacyMods.Nightcore))
yield return new TaikoModNightcore();
else if (mods.HasFlag(LegacyMods.DoubleTime))
yield return new TaikoModDoubleTime();
if (mods.HasFlag(LegacyMods.Autoplay))
yield return new TaikoModAutoplay();
if (mods.HasFlag(LegacyMods.Easy))
yield return new TaikoModEasy();
if (mods.HasFlag(LegacyMods.Flashlight))
yield return new TaikoModFlashlight();
if (mods.HasFlag(LegacyMods.HalfTime))
yield return new TaikoModHalfTime();
if (mods.HasFlag(LegacyMods.HardRock))
yield return new TaikoModHardRock();
if (mods.HasFlag(LegacyMods.Hidden))
yield return new TaikoModHidden();
if (mods.HasFlag(LegacyMods.NoFail))
yield return new TaikoModNoFail();
if (mods.HasFlag(LegacyMods.Perfect))
yield return new TaikoModPerfect();
if (mods.HasFlag(LegacyMods.Relax))
yield return new TaikoModRelax();
if (mods.HasFlag(LegacyMods.SuddenDeath))
yield return new TaikoModSuddenDeath();
}
public override IEnumerable<Mod> GetModsFor(ModType type)
{
switch (type)
@@ -116,8 +116,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
// [TestCase(with_sb)]
public void TestParity(string beatmap)
{
var beatmaps = decode(beatmap);
beatmaps.jsonDecoded.ShouldDeepEqual(beatmaps.legacyDecoded);
var legacy = decode(beatmap, out Beatmap json);
json.ShouldDeepEqual(legacy);
}
/// <summary>
@@ -126,15 +126,20 @@ namespace osu.Game.Tests.Beatmaps.Formats
/// </summary>
/// <param name="filename">The .osu file to decode.</param>
/// <returns>The <see cref="Beatmap"/> after being decoded by an <see cref="LegacyBeatmapDecoder"/>.</returns>
private Beatmap decodeAsJson(string filename) => decode(filename).jsonDecoded;
private Beatmap decodeAsJson(string filename)
{
decode(filename, out Beatmap jsonDecoded);
return jsonDecoded;
}
/// <summary>
/// Reads a .osu file first with a <see cref="LegacyBeatmapDecoder"/>, serializes the resulting <see cref="Beatmap"/> to JSON
/// and then deserializes the result back into a <see cref="Beatmap"/> through an <see cref="JsonBeatmapDecoder"/>.
/// </summary>
/// <param name="filename">The .osu file to decode.</param>
/// <param name="jsonDecoded">The <see cref="Beatmap"/> after being decoded by an <see cref="JsonBeatmapDecoder"/>.</param>
/// <returns>The <see cref="Beatmap"/> after being decoded by an <see cref="LegacyBeatmapDecoder"/>.</returns>
private (Beatmap legacyDecoded, Beatmap jsonDecoded) decode(string filename)
private Beatmap decode(string filename, out Beatmap jsonDecoded)
{
using (var stream = Resource.OpenResource(filename))
using (var sr = new StreamReader(stream))
@@ -149,7 +154,9 @@ namespace osu.Game.Tests.Beatmaps.Formats
sw.Flush();
ms.Position = 0;
return (legacyDecoded, new JsonBeatmapDecoder().Decode(sr2));
jsonDecoded = new JsonBeatmapDecoder().Decode(sr2);
return legacyDecoded;
}
}
}
@@ -0,0 +1,62 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseBadgeContainer : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BadgeContainer) };
public TestCaseBadgeContainer()
{
BadgeContainer badgeContainer;
Child = badgeContainer = new BadgeContainer
{
RelativeSizeAxes = Axes.Both
};
AddStep("Show 1 badge", () => badgeContainer.ShowBadges(new[]
{
new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = "Appreciates compasses",
ImageUrl = "https://assets.ppy.sh/profile-badges/mg2018-1star.png",
}
}));
AddStep("Show 2 badges", () => badgeContainer.ShowBadges(new[]
{
new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = "Contributed to osu!lazer testing",
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.png",
},
new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = "Appreciates compasses",
ImageUrl = "https://assets.ppy.sh/profile-badges/mg2018-1star.png",
}
}));
AddStep("Show many badges", () => badgeContainer.ShowBadges(Enumerable.Range(1, 20).Select(i => new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = $"Contributed to osu!lazer testing {i} times",
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg",
}).ToArray()));
}
}
}
@@ -52,6 +52,9 @@ namespace osu.Game.Tests.Visual
infoWedge.UpdateBeatmap(beatmap);
});
// select part is redundant, but wait for load isn't
selectBeatmap(beatmap.Value.Beatmap);
AddWaitStep(3);
AddStep("hide", () => { infoWedge.State = Visibility.Hidden; });
@@ -63,10 +66,11 @@ namespace osu.Game.Tests.Visual
foreach (var rulesetInfo in rulesets.AvailableRulesets)
{
var ruleset = rulesetInfo.CreateInstance();
beatmaps.Add(createTestBeatmap(rulesetInfo));
var testBeatmap = createTestBeatmap(rulesetInfo);
var name = rulesetInfo.ShortName;
selectBeatmap(name);
beatmaps.Add(testBeatmap);
selectBeatmap(testBeatmap);
// TODO: adjust cases once more info is shown for other gamemodes
switch (ruleset)
@@ -108,14 +112,14 @@ namespace osu.Game.Tests.Visual
AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any());
}
private void selectBeatmap(string name)
private void selectBeatmap(Beatmap b)
{
var infoBefore = infoWedge.Info;
BeatmapInfoWedge.BufferedWedgeInfo infoBefore = null;
AddStep($"select {name} beatmap", () =>
AddStep($"select {b.Metadata.Title} beatmap", () =>
{
beatmap.Value = new TestWorkingBeatmap(beatmaps.First(b => b.BeatmapInfo.Ruleset.ShortName == name));
infoWedge.UpdateBeatmap(beatmap);
infoBefore = infoWedge.Info;
infoWedge.UpdateBeatmap(beatmap.Value = new TestWorkingBeatmap(b));
});
AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load");
@@ -14,6 +14,8 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using System.Collections.Generic;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu;
namespace osu.Game.Tests.Visual
{
@@ -47,11 +49,11 @@ namespace osu.Game.Tests.Visual
AddStep("scores pack 1", () => scoresContainer.Scores = scores);
AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores);
AddStep("only top score", () => scoresContainer.Scores = new[] { topScore });
AddStep("remove scores", scoresContainer.CleanAllScores);
AddStep("turn on loading", () => scoresContainer.IsLoading = true);
AddStep("turn off loading", () => scoresContainer.IsLoading = false);
AddStep("remove scores", () => scoresContainer.Scores = null);
AddStep("resize to big", () => container.ResizeWidthTo(1, 300));
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapSetID = 1, OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo });
scores = new[]
{
@@ -8,6 +8,9 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets;
using osu.Game.Users;
@@ -18,6 +21,26 @@ namespace osu.Game.Tests.Visual
{
private readonly BeatmapSetOverlay overlay;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Header),
typeof(ClickableUsername),
typeof(DrawableScore),
typeof(DrawableTopScore),
typeof(ScoresContainer),
typeof(AuthorInfo),
typeof(BasicStats),
typeof(BeatmapPicker),
typeof(Details),
typeof(DownloadButton),
typeof(FavouriteButton),
typeof(Header),
typeof(HeaderButton),
typeof(Info),
typeof(PreviewButton),
typeof(SuccessRate),
};
public TestCaseBeatmapSetOverlay()
{
Add(overlay = new BeatmapSetOverlay());
@@ -29,6 +52,10 @@ namespace osu.Game.Tests.Visual
var mania = rulesets.GetRuleset(3);
var taiko = rulesets.GetRuleset(1);
AddStep(@"show loading", () => overlay.ShowBeatmapSet(null));
AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55));
AddStep(@"show first", () =>
{
overlay.ShowBeatmapSet(new BeatmapSetInfo
@@ -0,0 +1,24 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
{
public class TestCasePlayerLoader : OsuTestCase
{
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player
{
InitialBeatmap = new DummyWorkingBeatmap(game),
AllowPause = false,
AllowLeadIn = false,
AllowResults = false,
})));
}
}
}
+1 -1
View File
@@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Overlays.Profile;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
@@ -11,6 +10,7 @@ using System.Collections.Generic;
using System;
using NUnit.Framework;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
+23 -2
View File
@@ -5,9 +5,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
@@ -16,6 +19,7 @@ namespace osu.Game.Tests.Visual
public class TestCaseUserProfile : OsuTestCase
{
private readonly TestUserProfileOverlay profile;
private APIAccess api;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -23,6 +27,7 @@ namespace osu.Game.Tests.Visual
typeof(UserProfileOverlay),
typeof(RankGraph),
typeof(LineGraph),
typeof(BadgeContainer)
};
public TestCaseUserProfile()
@@ -30,6 +35,12 @@ namespace osu.Game.Tests.Visual
Add(profile = new TestUserProfileOverlay());
}
[BackgroundDependencyLoader]
private void load(APIAccess api)
{
this.api = api;
}
protected override void LoadComplete()
{
base.LoadComplete();
@@ -53,6 +64,15 @@ namespace osu.Game.Tests.Visual
{
Mode = @"osu",
Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray()
},
Badges = new[]
{
new Badge
{
AwardedAt = DateTimeOffset.FromUnixTimeSeconds(1505741569),
Description = "Outstanding help by being a voluntary test subject.",
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg"
}
}
}, false));
@@ -68,9 +88,10 @@ namespace osu.Game.Tests.Visual
{
Username = @"peppy",
Id = 2,
IsSupporter = true,
Country = new Country { FullName = @"Australia", FlagName = @"AU" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
}));
}, api.IsLoggedIn));
checkSupporterTag(true);
@@ -80,7 +101,7 @@ namespace osu.Game.Tests.Visual
Id = 3103765,
Country = new Country { FullName = @"Japan", FlagName = @"JP" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
}));
}, api.IsLoggedIn));
AddStep("Hide", profile.Hide);
AddStep("Show without reload", profile.Show);
+1 -1
View File
@@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
+3
View File
@@ -3,6 +3,9 @@
<PropertyGroup Label="C#">
<LangVersion>7</LangVersion>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>..\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup Label="License">
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
+1 -1
View File
@@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps.Formats
return output;
}
protected abstract void ParseStreamInto(StreamReader stream, TOutput beatmap);
protected abstract void ParseStreamInto(StreamReader stream, TOutput output);
}
public abstract class Decoder
@@ -13,15 +13,15 @@ namespace osu.Game.Beatmaps.Formats
AddDecoder<Beatmap>("{", m => new JsonBeatmapDecoder());
}
protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap)
protected override void ParseStreamInto(StreamReader stream, Beatmap output)
{
stream.BaseStream.Position = 0;
stream.DiscardBufferedData();
stream.ReadToEnd().DeserializeInto(beatmap);
stream.ReadToEnd().DeserializeInto(output);
foreach (var hitObject in beatmap.HitObjects)
hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty);
foreach (var hitObject in output.HitObjects)
hitObject.ApplyDefaults(output.ControlPointInfo, output.BeatmapInfo.BaseDifficulty);
}
}
}
+10 -3
View File
@@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps.Formats
FormatVersion = version;
}
protected override void ParseStreamInto(StreamReader stream, T beatmap)
protected override void ParseStreamInto(StreamReader stream, T output)
{
Section section = Section.None;
@@ -33,14 +33,21 @@ namespace osu.Game.Beatmaps.Formats
{
if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section))
{
Logger.Log($"Unknown section \"{line}\" in {beatmap}");
Logger.Log($"Unknown section \"{line}\" in {output}");
section = Section.None;
}
continue;
}
ParseLine(beatmap, section, line);
try
{
ParseLine(output, section, line);
}
catch (Exception e)
{
Logger.Error(e, $"Failed to process line \"{line}\" into {output}");
}
}
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Beatmaps.Legacy
{
[Flags]
public enum LegacyMods
{
None = 0,
NoFail = 1 << 0,
Easy = 1 << 1,
TouchDevice = 1 << 2,
Hidden = 1 << 3,
HardRock = 1 << 4,
SuddenDeath = 1 << 5,
DoubleTime = 1 << 6,
Relax = 1 << 7,
HalfTime = 1 << 8,
Nightcore = 1 << 9,
Flashlight = 1 << 10,
Autoplay = 1 << 11,
SpunOut = 1 << 12,
Autopilot = 1 << 13,
Perfect = 1 << 14,
Key4 = 1 << 15,
Key5 = 1 << 16,
Key6 = 1 << 17,
Key7 = 1 << 18,
Key8 = 1 << 19,
FadeIn = 1 << 20,
Random = 1 << 21,
Cinema = 1 << 22,
Target = 1 << 23,
Key9 = 1 << 24,
KeyCoop = 1 << 25,
Key1 = 1 << 26,
Key3 = 1 << 27,
Key2 = 1 << 28,
}
}
-23
View File
@@ -1,23 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
namespace osu.Game.Beatmaps
{
public enum RankStatus
{
Any = 7,
[Description("Ranked & Approved")]
RankedApproved = 0,
Approved = 1,
Loved = 8,
Favourites = 2,
[Description("Mod Requests")]
ModRequests = 3,
Pending = 4,
Graveyard = 5,
[Description("My Maps")]
MyMaps = 6,
}
}
+9 -1
View File
@@ -60,6 +60,9 @@ namespace osu.Game.Configuration
Set(OsuSetting.ShowFpsDisplay, false);
Set(OsuSetting.ShowStoryboard, true);
Set(OsuSetting.BeatmapSkins, true);
Set(OsuSetting.BeatmapHitsounds, true);
Set(OsuSetting.CursorRotation, true);
Set(OsuSetting.MenuParallax, true);
@@ -85,6 +88,8 @@ namespace osu.Game.Configuration
Set(OsuSetting.ScreenshotFormat, ScreenshotFormat.Jpg);
Set(OsuSetting.ScreenshotCaptureMenuCursor, false);
Set(OsuSetting.SongSelectRightMouseScroll, false);
}
public OsuConfigManager(Storage storage) : base(storage)
@@ -130,6 +135,9 @@ namespace osu.Game.Configuration
SpeedChangeVisualisation,
Skin,
ScreenshotFormat,
ScreenshotCaptureMenuCursor
ScreenshotCaptureMenuCursor,
SongSelectRightMouseScroll,
BeatmapSkins,
BeatmapHitsounds
}
}
@@ -61,9 +61,9 @@ namespace osu.Game.Graphics.Containers
AddText(text.Substring(previousLinkEnd));
}
public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null)
public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null, Action<SpriteText> creationParameters = null)
{
AddInternal(new DrawableLinkCompiler(AddText(text).ToList())
AddInternal(new DrawableLinkCompiler(AddText(text, creationParameters).ToList())
{
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
Action = () =>
@@ -71,9 +71,9 @@ namespace osu.Game.Graphics.Containers
switch (linkType)
{
case LinkAction.OpenBeatmap:
// todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented.
if (int.TryParse(linkArgument, out int beatmapId))
Process.Start($"https://osu.ppy.sh/b/{beatmapId}");
// TODO: proper query params handling
if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId))
game?.ShowBeatmap(beatmapId);
break;
case LinkAction.OpenBeatmapSet:
if (int.TryParse(linkArgument, out int setId))
+1 -2
View File
@@ -1,14 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.IO.Stores;
namespace osu.Game.IO.Archives
{
public abstract class ArchiveReader : IDisposable, IResourceStore<byte[]>
public abstract class ArchiveReader : IResourceStore<byte[]>
{
/// <summary>
/// Opens a stream for reading a specific file from this archive.
@@ -5,13 +5,21 @@ namespace osu.Game.Online.API.Requests
{
public class GetBeatmapSetRequest : APIRequest<APIResponseBeatmapSet>
{
private readonly int beatmapSetId;
private readonly int id;
private readonly BeatmapSetLookupType type;
public GetBeatmapSetRequest(int beatmapSetId)
public GetBeatmapSetRequest(int id, BeatmapSetLookupType type = BeatmapSetLookupType.SetId)
{
this.beatmapSetId = beatmapSetId;
this.id = id;
this.type = type;
}
protected override string Target => $@"beatmapsets/{beatmapSetId}";
protected override string Target => type == BeatmapSetLookupType.SetId ? $@"beatmapsets/{id}" : $@"beatmapsets/lookup?beatmap_id={id}";
}
public enum BeatmapSetLookupType
{
SetId,
BeatmapId,
}
}
@@ -11,7 +11,7 @@ namespace osu.Game.Online.API.Requests
public class GetMessagesRequest : APIRequest<List<Message>>
{
private readonly List<Channel> channels;
private long? since;
private readonly long? since;
public GetMessagesRequest(List<Channel> channels, long? sinceId)
{
@@ -7,7 +7,7 @@ namespace osu.Game.Online.API.Requests
{
public class GetUserRequest : APIRequest<User>
{
private long? userId;
private readonly long? userId;
public GetUserRequest(long? userId = null)
{
@@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Game.Beatmaps;
using System.ComponentModel;
using osu.Game.Overlays;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
@@ -13,21 +13,36 @@ namespace osu.Game.Online.API.Requests
{
private readonly string query;
private readonly RulesetInfo ruleset;
private readonly RankStatus rankStatus;
private readonly BeatmapSearchCategory searchCategory;
private readonly DirectSortCriteria sortCriteria;
private readonly SortDirection direction;
private string directionString => direction == SortDirection.Descending ? @"desc" : @"asc";
public SearchBeatmapSetsRequest(string query, RulesetInfo ruleset, RankStatus rankStatus = RankStatus.Any, DirectSortCriteria sortCriteria = DirectSortCriteria.Ranked, SortDirection direction = SortDirection.Descending)
public SearchBeatmapSetsRequest(string query, RulesetInfo ruleset, BeatmapSearchCategory searchCategory = BeatmapSearchCategory.Any, DirectSortCriteria sortCriteria = DirectSortCriteria.Ranked, SortDirection direction = SortDirection.Descending)
{
this.query = System.Uri.EscapeDataString(query);
this.ruleset = ruleset;
this.rankStatus = rankStatus;
this.searchCategory = searchCategory;
this.sortCriteria = sortCriteria;
this.direction = direction;
}
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={(int)rankStatus}&sort={sortCriteria.ToString().ToLower()}_{directionString}";
protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={(int)searchCategory}&sort={sortCriteria.ToString().ToLower()}_{directionString}";
}
public enum BeatmapSearchCategory
{
Any = 7,
[Description("Ranked & Approved")]
RankedApproved = 0,
Approved = 1,
Loved = 8,
Favourites = 2,
Qualified = 3,
Pending = 4,
Graveyard = 5,
[Description("My Maps")]
MyMaps = 6,
}
}
+8 -1
View File
@@ -158,7 +158,7 @@ namespace osu.Game
/// Show a beatmap set as an overlay.
/// </summary>
/// <param name="setId">The set to display.</param>
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.ShowBeatmapSet(setId);
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.FetchAndShowBeatmapSet(setId);
/// <summary>
/// Show a user's profile as an overlay.
@@ -166,6 +166,12 @@ namespace osu.Game
/// <param name="userId">The user to display.</param>
public void ShowUser(long userId) => userProfile.ShowUser(userId);
/// <summary>
/// Show a beatmap's set as an overlay, displaying the given beatmap.
/// </summary>
/// <param name="beatmapId">The beatmap to show.</param>
public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
protected void LoadScore(Score s)
{
scoreLoad?.Cancel();
@@ -196,6 +202,7 @@ namespace osu.Game
}
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap);
Beatmap.Value.Mods.Value = s.Mods;
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
}
+14 -14
View File
@@ -188,6 +188,20 @@ namespace osu.Game
FileStore.Cleanup();
AddInternal(api);
GlobalActionContainer globalBinding;
CursorOverrideContainer = new CursorOverrideContainer { RelativeSizeAxes = Axes.Both };
CursorOverrideContainer.Child = globalBinding = new GlobalActionContainer(this)
{
RelativeSizeAxes = Axes.Both,
Child = content = new OsuTooltipContainer(CursorOverrideContainer.Cursor) { RelativeSizeAxes = Axes.Both }
};
base.Content.Add(new DrawSizePreservingFillContainer { Child = CursorOverrideContainer });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
}
private void runMigrations()
@@ -217,20 +231,6 @@ namespace osu.Game
{
base.LoadComplete();
GlobalActionContainer globalBinding;
CursorOverrideContainer = new CursorOverrideContainer { RelativeSizeAxes = Axes.Both };
CursorOverrideContainer.Child = globalBinding = new GlobalActionContainer(this)
{
RelativeSizeAxes = Axes.Both,
Child = content = new OsuTooltipContainer(CursorOverrideContainer.Cursor) { RelativeSizeAxes = Axes.Both }
};
base.Content.Add(new DrawSizePreservingFillContainer { Child = CursorOverrideContainer });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
// TODO: This is temporary until we reimplement the local FPS display.
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);
+34 -22
View File
@@ -23,9 +23,8 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly ClickableArea clickableArea;
private readonly FillFlowContainer fields;
private UserProfileOverlay profile;
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
{
get { return beatmapSet; }
@@ -34,28 +33,36 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmapSet) return;
beatmapSet = value;
var i = BeatmapSet.OnlineInfo;
updateDisplay();
}
}
avatar.User = BeatmapSet.Metadata.Author;
clickableArea.Action = () => profile?.ShowUser(avatar.User);
private void updateDisplay()
{
avatar.User = BeatmapSet?.Metadata.Author;
fields.Children = new Drawable[]
{
new Field("made by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"),
new Field("submitted on", i.Submitted.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")
{
Margin = new MarginPadding { Top = 5 },
},
};
fields.Clear();
if (BeatmapSet == null)
return;
if (i.Ranked.HasValue)
var online = BeatmapSet.OnlineInfo;
fields.Children = new Drawable[]
{
new Field("made by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"),
new Field("submitted on", online.Submitted.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")
{
fields.Add(new Field("ranked on ", i.Ranked.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold"));
}
else if (i.LastUpdated.HasValue)
{
fields.Add(new Field("last updated on ", i.LastUpdated.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold"));
}
Margin = new MarginPadding { Top = 5 },
},
};
if (online.Ranked.HasValue)
{
fields.Add(new Field("ranked on ", online.Ranked.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold"));
}
else if (online.LastUpdated.HasValue)
{
fields.Add(new Field("last updated on ", online.LastUpdated.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold"));
}
}
@@ -73,6 +80,7 @@ namespace osu.Game.Overlays.BeatmapSet
Masking = true,
Child = avatar = new UpdateableAvatar
{
ShowGuestOnNull = false,
Size = new Vector2(height),
},
EdgeEffect = new EdgeEffectParameters
@@ -95,8 +103,12 @@ namespace osu.Game.Overlays.BeatmapSet
[BackgroundDependencyLoader(true)]
private void load(UserProfileOverlay profile)
{
this.profile = profile;
clickableArea.Action = () => profile?.ShowUser(avatar.User);
clickableArea.Action = () =>
{
if (avatar.User != null) profile?.ShowUser(avatar.User);
};
updateDisplay();
}
private class Field : FillFlowContainer
+26 -1
View File
@@ -18,6 +18,7 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly Statistic length, bpm, circleCount, sliderCount;
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
{
get { return beatmapSet; }
@@ -26,11 +27,12 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmapSet) return;
beatmapSet = value;
bpm.Value = BeatmapSet.OnlineInfo.BPM.ToString(@"0.##");
updateDisplay();
}
}
private BeatmapInfo beatmap;
public BeatmapInfo Beatmap
{
get { return beatmap; }
@@ -39,6 +41,22 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmap) return;
beatmap = value;
updateDisplay();
}
}
private void updateDisplay()
{
bpm.Value = BeatmapSet?.OnlineInfo.BPM.ToString(@"0.##") ?? "-";
if (beatmap == null)
{
length.Value = string.Empty;
circleCount.Value = string.Empty;
sliderCount.Value = string.Empty;
}
else
{
length.Value = TimeSpan.FromSeconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss");
circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString();
sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString();
@@ -62,12 +80,19 @@ namespace osu.Game.Overlays.BeatmapSet
};
}
[BackgroundDependencyLoader]
private void load()
{
updateDisplay();
}
private class Statistic : Container, IHasTooltip
{
private readonly string name;
private readonly OsuSpriteText value;
public string TooltipText => name;
public string Value
{
get { return value.Text; }
+23 -10
View File
@@ -41,9 +41,16 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmapSet) return;
beatmapSet = value;
Beatmap.Value = BeatmapSet.Beatmaps.First();
plays.Value = BeatmapSet.OnlineInfo.PlayCount;
favourites.Value = BeatmapSet.OnlineInfo.FavouriteCount;
updateDisplay();
}
}
private void updateDisplay()
{
difficulties.Clear();
if (BeatmapSet != null)
{
difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty).Select(b => new DifficultySelectorButton(b)
{
State = DifficultySelectorState.NotSelected,
@@ -53,14 +60,16 @@ namespace osu.Game.Overlays.BeatmapSet
starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##");
starRating.FadeIn(100);
},
OnClicked = beatmap =>
{
Beatmap.Value = beatmap;
},
OnClicked = beatmap => { Beatmap.Value = beatmap; },
});
updateDifficultyButtons();
}
starRating.FadeOut(100);
Beatmap.Value = BeatmapSet?.Beatmaps.FirstOrDefault();
plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0;
favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0;
updateDifficultyButtons();
}
public BeatmapPicker()
@@ -140,6 +149,7 @@ namespace osu.Game.Overlays.BeatmapSet
private void load(OsuColour colours)
{
starRating.Colour = colours.Yellow;
updateDisplay();
}
protected override void LoadComplete()
@@ -150,7 +160,10 @@ namespace osu.Game.Overlays.BeatmapSet
Beatmap.TriggerChange();
}
private void showBeatmap(BeatmapInfo beatmap) => version.Text = beatmap.Version;
private void showBeatmap(BeatmapInfo beatmap)
{
version.Text = beatmap?.Version;
}
private void updateDifficultyButtons()
{
@@ -7,7 +7,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Overlays.BeatmapSet
namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class DownloadButton : HeaderButton
{
@@ -10,7 +10,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using OpenTK;
namespace osu.Game.Overlays.BeatmapSet
namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class FavouriteButton : HeaderButton
{
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Framework.Allocation;
namespace osu.Game.Overlays.BeatmapSet
namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class HeaderButton : TriangleButton
{
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -11,12 +12,11 @@ using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays.Direct;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Overlays.Direct;
using osu.Framework.Configuration;
namespace osu.Game.Overlays.BeatmapSet
namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class PreviewButton : OsuClickableContainer
{
@@ -85,6 +85,8 @@ namespace osu.Game.Overlays.BeatmapSet
// prevent negative (potential infinite) width if a track without length was loaded
progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f;
}
else
progress.Width = 0;
}
protected override void Dispose(bool isDisposing)
+17 -3
View File
@@ -1,11 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Screens.Select.Details;
using OpenTK;
using OpenTK.Graphics;
@@ -20,6 +22,7 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly UserRatings ratings;
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
{
get { return beatmapSet; }
@@ -33,19 +36,24 @@ namespace osu.Game.Overlays.BeatmapSet
}
private BeatmapInfo beatmap;
public BeatmapInfo Beatmap
{
get { return beatmap; }
set
{
if (value == beatmap) return;
beatmap = value;
basic.Beatmap = advanced.Beatmap = Beatmap;
ratings.Metrics = Beatmap.Metrics;
basic.Beatmap = advanced.Beatmap = beatmap = value;
updateDisplay();
}
}
private void updateDisplay()
{
ratings.Metrics = Beatmap?.Metrics;
}
public Details()
{
Width = BeatmapSetOverlay.RIGHT_WIDTH;
@@ -88,6 +96,12 @@ namespace osu.Game.Overlays.BeatmapSet
};
}
[BackgroundDependencyLoader]
private void load()
{
updateDisplay();
}
public void StopPreview() => preview.Playing.Value = false;
private class DetailBox : Container
+28 -8
View File
@@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.BeatmapSet.Buttons;
using OpenTK;
using OpenTK.Graphics;
@@ -18,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
public class Header : Container
{
private const float transition_duration = 250;
private const float transition_duration = 200;
private const float tabs_height = 50;
private const float buttons_height = 45;
private const float buttons_spacing = 5;
@@ -34,12 +35,13 @@ namespace osu.Game.Overlays.BeatmapSet
public Details Details;
private BeatmapManager beatmaps;
private DelayedLoadWrapper cover;
public readonly BeatmapPicker Picker;
private BeatmapSetInfo beatmapSet;
private readonly FavouriteButton favouriteButton;
public BeatmapSetInfo BeatmapSet
{
get { return beatmapSet; }
@@ -49,15 +51,26 @@ namespace osu.Game.Overlays.BeatmapSet
beatmapSet = value;
Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet;
title.Text = BeatmapSet.Metadata.Title;
artist.Text = BeatmapSet.Metadata.Artist;
onlineStatusPill.Status = BeatmapSet.OnlineInfo.Status;
downloadButtonsContainer.FadeIn();
updateDisplay();
}
}
private void updateDisplay()
{
title.Text = BeatmapSet?.Metadata.Title ?? string.Empty;
artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty;
onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
cover?.FadeOut(400, Easing.Out);
if (BeatmapSet != null)
{
downloadButtonsContainer.FadeIn(transition_duration);
favouriteButton.FadeIn(transition_duration);
noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration);
videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration);
cover?.FadeOut(400, Easing.Out);
coverContainer.Add(cover = new DelayedLoadWrapper(
new BeatmapSetCover(BeatmapSet)
{
@@ -71,6 +84,11 @@ namespace osu.Game.Overlays.BeatmapSet
RelativeSizeAxes = Axes.Both,
});
}
else
{
downloadButtonsContainer.FadeOut(transition_duration);
favouriteButton.FadeOut(transition_duration);
}
}
public Header()
@@ -166,7 +184,7 @@ namespace osu.Game.Overlays.BeatmapSet
Margin = new MarginPadding { Top = 10 },
Children = new Drawable[]
{
new FavouriteButton(),
favouriteButton = new FavouriteButton(),
downloadButtonsContainer = new Container
{
RelativeSizeAxes = Axes.Both,
@@ -238,6 +256,8 @@ namespace osu.Game.Overlays.BeatmapSet
this.beatmaps = beatmaps;
beatmaps.ItemAdded += handleBeatmapAdd;
updateDisplay();
}
protected override void Dispose(bool isDisposing)
+9 -2
View File
@@ -34,11 +34,16 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmapSet) return;
beatmapSet = value;
source.Text = BeatmapSet.Metadata.Source;
tags.Text = BeatmapSet.Metadata.Tags;
updateDisplay();
}
}
private void updateDisplay()
{
source.Text = BeatmapSet?.Metadata.Source ?? string.Empty;
tags.Text = BeatmapSet?.Metadata.Tags ?? string.Empty;
}
public BeatmapInfo Beatmap
{
get { return successRate.Beatmap; }
@@ -132,6 +137,8 @@ namespace osu.Game.Overlays.BeatmapSet
successRateBackground.Colour = colours.GrayE;
source.TextColour = description.TextColour = colours.Gray5;
tags.TextColour = colours.BlueDark;
updateDisplay();
}
private class MetadataSection : FillFlowContainer
@@ -2,15 +2,15 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
@@ -22,49 +22,75 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly FillFlowContainer flow;
private readonly DrawableTopScore topScore;
private readonly LoadingAnimation loadingAnimation;
private readonly Box foreground;
private bool isLoading;
public bool IsLoading
private bool loading
{
get { return isLoading; }
set
{
if (isLoading == value) return;
isLoading = value;
foreground.FadeTo(isLoading ? 1 : 0, fade_duration);
loadingAnimation.FadeTo(isLoading ? 1 : 0, fade_duration);
}
set => loadingAnimation.FadeTo(value ? 1 : 0, fade_duration);
}
private IEnumerable<OnlineScore> scores;
private BeatmapInfo beatmap;
public IEnumerable<OnlineScore> Scores
{
get { return scores; }
set
{
getScoresRequest?.Cancel();
scores = value;
var scoresAmount = scores.Count();
if (scoresAmount == 0)
{
CleanAllScores();
return;
}
topScore.Score = scores.FirstOrDefault();
topScore.Show();
flow.Clear();
if (scoresAmount < 2)
return;
for (int i = 1; i < scoresAmount; i++)
flow.Add(new DrawableScore(i, scores.ElementAt(i)));
updateDisplay();
}
}
private GetScoresRequest getScoresRequest;
private APIAccess api;
public BeatmapInfo Beatmap
{
get => beatmap;
set
{
beatmap = value;
Scores = null;
if (beatmap?.OnlineBeatmapID.HasValue != true)
return;
loading = true;
getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset);
getScoresRequest.Success += r => Scores = r.Scores;
api.Queue(getScoresRequest);
}
}
private void updateDisplay()
{
loading = false;
var scoreCount = scores?.Count() ?? 0;
if (scoreCount == 0)
{
topScore.Hide();
flow.Clear();
return;
}
topScore.Score = scores.FirstOrDefault();
topScore.Show();
flow.Clear();
if (scoreCount < 2)
return;
for (int i = 1; i < scoreCount; i++)
flow.Add(new DrawableScore(i, scores.ElementAt(i)));
}
public ScoresContainer()
{
RelativeSizeAxes = Axes.X;
@@ -93,23 +119,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
},
}
},
foreground = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.7f),
Alpha = 0,
},
loadingAnimation = new LoadingAnimation
{
Alpha = 0,
Margin = new MarginPadding(20)
},
};
}
public void CleanAllScores()
[BackgroundDependencyLoader]
private void load(APIAccess api)
{
topScore.Hide();
flow.Clear();
this.api = api;
updateDisplay();
}
}
}
+16 -10
View File
@@ -29,18 +29,23 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmap) return;
beatmap = value;
int passCount = beatmap.OnlineInfo.PassCount;
int playCount = beatmap.OnlineInfo.PlayCount;
var rate = playCount != 0 ? (float)passCount / playCount : 0;
successPercent.Text = rate.ToString("P0");
successRate.Length = rate;
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
graph.Metrics = Beatmap.Metrics;
updateDisplay();
}
}
private void updateDisplay()
{
int passCount = beatmap?.OnlineInfo.PassCount ?? 0;
int playCount = beatmap?.OnlineInfo.PlayCount ?? 0;
var rate = playCount != 0 ? (float)passCount / playCount : 0;
successPercent.Text = rate.ToString("P0");
successRate.Length = rate;
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
graph.Metrics = beatmap?.Metrics;
}
public SuccessRate()
{
Children = new Drawable[]
@@ -74,7 +79,6 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopCentre,
Text = @"0%",
TextSize = 13,
},
},
@@ -103,6 +107,8 @@ namespace osu.Game.Overlays.BeatmapSet
successRateLabel.Colour = successPercent.Colour = graphLabel.Colour = colours.Gray5;
successRate.AccentColour = colours.Green;
successRate.BackgroundColour = colours.GrayD;
updateDisplay();
}
protected override void UpdateAfterChildren()
+38 -28
View File
@@ -17,29 +17,45 @@ using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using osu.Game.Overlays.BeatmapSet.Scores;
using System.Linq;
namespace osu.Game.Overlays
{
public class BeatmapSetOverlay : WaveOverlayContainer
{
private const int fade_duration = 300;
public const float X_PADDING = 40;
public const float RIGHT_WIDTH = 275;
private readonly Header header;
private readonly Info info;
private readonly ScoresContainer scores;
private APIAccess api;
private RulesetStore rulesets;
private GetScoresRequest getScoresRequest;
private readonly ScrollContainer scroll;
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
{
get => beatmapSet;
set
{
if (value == beatmapSet)
return;
header.BeatmapSet = info.BeatmapSet = beatmapSet = value;
}
}
// receive input outside our bounds so we can trigger a close event on ourselves.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
public BeatmapSetOverlay()
{
ScoresContainer scores;
Waves.FirstWaveColour = OsuColour.Gray(0.4f);
Waves.SecondWaveColour = OsuColour.Gray(0.3f);
Waves.ThirdWaveColour = OsuColour.Gray(0.2f);
@@ -88,31 +104,10 @@ namespace osu.Game.Overlays
header.Picker.Beatmap.ValueChanged += b =>
{
info.Beatmap = b;
updateScores(b);
scores.Beatmap = b;
};
}
private void updateScores(BeatmapInfo beatmap)
{
getScoresRequest?.Cancel();
if (!beatmap.OnlineBeatmapID.HasValue)
{
scores.CleanAllScores();
return;
}
scores.IsLoading = true;
getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset);
getScoresRequest.Success += r =>
{
scores.Scores = r.Scores;
scores.IsLoading = false;
};
api.Queue(getScoresRequest);
}
[BackgroundDependencyLoader]
private void load(APIAccess api, RulesetStore rulesets)
{
@@ -130,7 +125,8 @@ namespace osu.Game.Overlays
{
base.PopOut();
header.Details.StopPreview();
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out);
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null);
}
protected override bool OnClick(InputState state)
@@ -139,17 +135,31 @@ namespace osu.Game.Overlays
return true;
}
public void ShowBeatmapSet(int beatmapSetId)
public void FetchAndShowBeatmap(int beatmapId)
{
// todo: display the overlay while we are loading here. we need to support setting BeatmapSet to null for this to work.
BeatmapSet = null;
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
req.Success += res =>
{
ShowBeatmapSet(res.ToBeatmapSet(rulesets));
header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
};
api.Queue(req);
Show();
}
public void FetchAndShowBeatmapSet(int beatmapSetId)
{
BeatmapSet = null;
var req = new GetBeatmapSetRequest(beatmapSetId);
req.Success += res => ShowBeatmapSet(res.ToBeatmapSet(rulesets));
api.Queue(req);
Show();
}
public void ShowBeatmapSet(BeatmapSetInfo set)
{
header.BeatmapSet = info.BeatmapSet = set;
BeatmapSet = set;
Show();
scroll.ScrollTo(0);
}
+2
View File
@@ -307,6 +307,8 @@ namespace osu.Game.Overlays.Chat
{
public override bool IsRemovable => false;
public override bool IsSwitchable => false;
public ChannelSelectorTabItem(Channel value) : base(value)
{
Depth = float.MaxValue;
+2 -2
View File
@@ -7,15 +7,15 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.SearchableList;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.Direct
{
public class FilterControl : SearchableListFilterControl<DirectSortCriteria, RankStatus>
public class FilterControl : SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory>
{
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private FillFlowContainer<RulesetToggleButton> modeButtons;
+10 -6
View File
@@ -78,12 +78,7 @@ namespace osu.Game.Overlays.Direct
loadingAnimation = new LoadingAnimation(),
});
Playing.ValueChanged += playing =>
{
icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play;
icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint);
updatePreviewTrack(playing);
};
Playing.ValueChanged += updatePreviewTrack;
}
[BackgroundDependencyLoader]
@@ -125,6 +120,15 @@ namespace osu.Game.Overlays.Direct
private void updatePreviewTrack(bool playing)
{
if (playing && BeatmapSet == null)
{
Playing.Value = false;
return;
}
icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play;
icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint);
if (playing)
{
if (Preview == null)
+2 -2
View File
@@ -22,7 +22,7 @@ using OpenTK.Graphics;
namespace osu.Game.Overlays
{
public class DirectOverlay : SearchableListOverlay<DirectTab, DirectSortCriteria, RankStatus>
public class DirectOverlay : SearchableListOverlay<DirectTab, DirectSortCriteria, BeatmapSearchCategory>
{
private const float panel_padding = 10f;
@@ -40,7 +40,7 @@ namespace osu.Game.Overlays
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265");
protected override SearchableListHeader<DirectTab> CreateHeader() => new Header();
protected override SearchableListFilterControl<DirectSortCriteria, RankStatus> CreateFilterControl() => new FilterControl();
protected override SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory> CreateFilterControl() => new FilterControl();
private IEnumerable<BeatmapSetInfo> beatmapSets;
@@ -0,0 +1,191 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using OpenTK;
namespace osu.Game.Overlays.Profile.Header
{
public class BadgeContainer : Container
{
private static readonly Vector2 badge_size = new Vector2(86, 40);
private static readonly MarginPadding outer_padding = new MarginPadding(3);
private OsuSpriteText badgeCountText;
private FillFlowContainer badgeFlowContainer;
private FillFlowContainer outerBadgeContainer;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Child = new Container
{
Masking = true,
CornerRadius = 4,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray3
},
outerBadgeContainer = new OuterBadgeContainer(onOuterHover, onOuterHoverLost)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Direction = FillDirection.Vertical,
Padding = outer_padding,
Width = DrawableBadge.DRAWABLE_BADGE_SIZE.X + outer_padding.TotalHorizontal,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
badgeCountText = new OsuSpriteText
{
Alpha = 0,
TextSize = 12,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Font = "Exo2.0-Regular"
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
AutoSizeAxes = Axes.Both,
Child = badgeFlowContainer = new FillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
}
}
}
},
}
};
Scheduler.AddDelayed(rotateBadges, 3000, true);
}
private void rotateBadges()
{
if (outerBadgeContainer.IsHovered) return;
visibleBadge = (visibleBadge + 1) % badgeCount;
badgeFlowContainer.MoveToX(-DrawableBadge.DRAWABLE_BADGE_SIZE.X * visibleBadge, 500, Easing.InOutQuad);
}
private int visibleBadge;
private int badgeCount;
public void ShowBadges(Badge[] badges)
{
if (badges == null || badges.Length == 0)
{
Hide();
return;
}
badgeCount = badges.Length;
badgeCountText.FadeTo(badgeCount > 1 ? 1 : 0);
badgeCountText.Text = $"{badges.Length} badges";
Show();
visibleBadge = 0;
badgeFlowContainer.Clear();
foreach (var badge in badges)
{
LoadComponentAsync(new DrawableBadge(badge)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
}, badgeFlowContainer.Add);
}
}
private void onOuterHover()
{
badgeFlowContainer.ClearTransforms();
badgeFlowContainer.X = 0;
badgeFlowContainer.Direction = FillDirection.Full;
outerBadgeContainer.AutoSizeAxes = Axes.Both;
badgeFlowContainer.MaximumSize = new Vector2(ChildSize.X, float.MaxValue);
}
private void onOuterHoverLost()
{
badgeFlowContainer.X = -DrawableBadge.DRAWABLE_BADGE_SIZE.X * visibleBadge;
badgeFlowContainer.Direction = FillDirection.Horizontal;
outerBadgeContainer.AutoSizeAxes = Axes.Y;
outerBadgeContainer.Width = DrawableBadge.DRAWABLE_BADGE_SIZE.X + outer_padding.TotalHorizontal;
}
private class OuterBadgeContainer : FillFlowContainer
{
private readonly Action hoverAction;
private readonly Action hoverLostAction;
public OuterBadgeContainer(Action hoverAction, Action hoverLostAction)
{
this.hoverAction = hoverAction;
this.hoverLostAction = hoverLostAction;
}
protected override bool OnHover(InputState state)
{
hoverAction();
return true;
}
protected override void OnHoverLost(InputState state) => hoverLostAction();
}
private class DrawableBadge : Container, IHasTooltip
{
public static readonly Vector2 DRAWABLE_BADGE_SIZE = badge_size + outer_padding.Total;
private readonly Badge badge;
public DrawableBadge(Badge badge)
{
this.badge = badge;
Padding = outer_padding;
Size = DRAWABLE_BADGE_SIZE;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Child = new Sprite
{
FillMode = FillMode.Fit,
RelativeSizeAxes = Axes.Both,
Texture = textures.Get(badge.ImageUrl),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Child.FadeInFromZero(200);
}
public string TooltipText => badge.Description;
}
}
}
@@ -2,9 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -14,10 +15,9 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Users;
using System.Collections.Generic;
using osu.Framework.Configuration;
using OpenTK;
namespace osu.Game.Overlays.Profile
namespace osu.Game.Overlays.Profile.Header
{
public class RankGraph : Container
{
@@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -9,8 +8,9 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using OpenTK;
namespace osu.Game.Overlays.Profile
namespace osu.Game.Overlays.Profile.Header
{
public class SupporterIcon : CircularContainer, IHasTooltip
{
+28 -9
View File
@@ -17,13 +17,14 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile
{
public class ProfileHeader : Container
{
private readonly OsuTextFlowContainer infoTextLeft;
private readonly LinkFlowContainer infoTextLeft;
private readonly LinkFlowContainer infoTextRight;
private readonly FillFlowContainer<SpriteText> scoreText, scoreNumberText;
private readonly RankGraph rankGraph;
@@ -35,6 +36,7 @@ namespace osu.Game.Overlays.Profile
private readonly GradeBadge gradeSSPlus, gradeSS, gradeSPlus, gradeS, gradeA;
private readonly Box colourBar;
private readonly DrawableFlag countryFlag;
private readonly BadgeContainer badgeContainer;
private const float cover_height = 350;
private const float info_height = 150;
@@ -42,6 +44,7 @@ namespace osu.Game.Overlays.Profile
private const float avatar_size = 110;
private const float level_position = 30;
private const float level_height = 60;
private const float stats_width = 280;
public ProfileHeader(User user)
{
@@ -66,9 +69,9 @@ namespace osu.Game.Overlays.Profile
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
X = UserProfileOverlay.CONTENT_X_MARGIN,
Y = -20,
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN, Bottom = 20, Right = stats_width + UserProfileOverlay.CONTENT_X_MARGIN },
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Children = new Drawable[]
{
new UpdateableAvatar
@@ -116,7 +119,15 @@ namespace osu.Game.Overlays.Profile
Height = 20
}
}
}
},
badgeContainer = new BadgeContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Bottom = 5 },
Alpha = 0,
},
}
},
colourBar = new Box
@@ -130,7 +141,7 @@ namespace osu.Game.Overlays.Profile
}
}
},
infoTextLeft = new OsuTextFlowContainer(t => t.TextSize = 14)
infoTextLeft = new LinkFlowContainer(t => t.TextSize = 14)
{
X = UserProfileOverlay.CONTENT_X_MARGIN,
Y = cover_height + 20,
@@ -156,7 +167,7 @@ namespace osu.Game.Overlays.Profile
{
X = -UserProfileOverlay.CONTENT_X_MARGIN,
RelativeSizeAxes = Axes.Y,
Width = 280,
Width = stats_width,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Children = new Drawable[]
@@ -339,7 +350,7 @@ namespace osu.Game.Overlays.Profile
if (user.Country != null)
{
infoTextLeft.AddText("from ", lightText);
infoTextLeft.AddText("From ", lightText);
infoTextLeft.AddText(user.Country.FullName, boldItalic);
countryFlag.Country = user.Country;
}
@@ -367,6 +378,10 @@ namespace osu.Game.Overlays.Profile
infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic);
}
infoTextLeft.NewLine();
infoTextLeft.AddText("Contributed ", lightText);
infoTextLeft.AddLink($@"{user.PostCount} forum posts", url: $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: boldItalic);
string websiteWithoutProtcol = user.Website;
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
{
@@ -381,8 +396,10 @@ namespace osu.Game.Overlays.Profile
infoTextRight.NewParagraph();
if (!string.IsNullOrEmpty(user.Twitter))
tryAddInfoRightLine(FontAwesome.fa_twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
tryAddInfoRightLine(FontAwesome.fa_globe, websiteWithoutProtcol, user.Website);
tryAddInfoRightLine(FontAwesome.fa_gamepad, user.Discord);
tryAddInfoRightLine(FontAwesome.fa_skype, user.Skype, @"skype:" + user.Skype + @"?chat");
tryAddInfoRightLine(FontAwesome.fa_lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
tryAddInfoRightLine(FontAwesome.fa_globe, websiteWithoutProtcol, user.Website);
if (user.Statistics != null)
{
@@ -417,6 +434,8 @@ namespace osu.Game.Overlays.Profile
rankGraph.User.Value = user;
}
badgeContainer.ShowBadges(user.Badges);
}
private void tryAddInfoRightLine(FontAwesome icon, string str, string url = null)
@@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections
{
Action = () =>
{
if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value);
if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value);
};
Child = new FillFlowContainer
@@ -17,6 +17,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{
Children = new Drawable[]
{
new SettingsCheckbox
{
LabelText = "Right mouse drag to absolute scroll",
Bindable = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
},
new SettingsCheckbox
{
LabelText = "Show converted beatmaps",
+8
View File
@@ -14,6 +14,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Beatmaps.Legacy;
namespace osu.Game.Rulesets
{
@@ -33,6 +34,13 @@ namespace osu.Game.Rulesets
public abstract IEnumerable<Mod> GetModsFor(ModType type);
/// <summary>
/// Converts mods from legacy enum values. Do not override if you're not a legacy ruleset.
/// </summary>
/// <param name="mods">The legacy enum which will be converted</param>
/// <returns>An enumerable of constructed <see cref="Mod"/>s</returns>
public virtual IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) => new Mod[] { };
public Mod GetAutoplayMod() => GetAllMods().First(mod => mod is ModAutoplay);
protected Ruleset(RulesetInfo rulesetInfo = null)
@@ -9,6 +9,8 @@ using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Users;
using SharpCompress.Compressors.LZMA;
using osu.Game.Beatmaps.Legacy;
using System.Linq;
namespace osu.Game.Rulesets.Scoring.Legacy
{
@@ -64,7 +66,7 @@ namespace osu.Game.Rulesets.Scoring.Legacy
/* score.Perfect = */
sr.ReadBoolean();
/* score.EnabledMods = (Mods)*/
sr.ReadInt32();
score.Mods = currentRuleset.ConvertLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();
/* score.HpGraphString = */
sr.ReadString();
/* score.Date = */
@@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
base.UpdateAfterChildrenLife();
// We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions
speedChangeVisualiser.ComputePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize);
speedChangeVisualiser.UpdatePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize);
}
}
}
@@ -10,24 +10,23 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
public interface ISpeedChangeVisualiser
{
/// <summary>
/// Computes the states of <see cref="DrawableHitObject"/>s that are constant, such as lifetime and spatial length.
/// Computes the states of <see cref="DrawableHitObject"/>s that remain constant while scrolling, such as lifetime and spatial length.
/// This is invoked once whenever <paramref name="timeRange"/> or <paramref name="length"/> changes.
/// </summary>
/// <param name="hitObjects">The <see cref="DrawableHitObject"/>s whose states should be computed.</param>
/// <param name="direction">The scrolling direction.</param>
/// <param name="timeRange">The duration required to scroll through one length of the screen before any control point adjustments.</param>
/// <param name="timeRange">The duration required to scroll through one length of the screen before any speed adjustments.</param>
/// <param name="length">The length of the screen that is scrolled through.</param>
void ComputeInitialStates(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double timeRange, Vector2 length);
/// <summary>
/// Computes the states of <see cref="DrawableHitObject"/>s that change depending on <paramref name="currentTime"/>, such as position.
/// This is invoked once per frame.
/// Updates the positions of <see cref="DrawableHitObject"/>s, depending on the current time. This is invoked once per frame.
/// </summary>
/// <param name="hitObjects">The <see cref="DrawableHitObject"/>s whose states should be computed.</param>
/// <param name="hitObjects">The <see cref="DrawableHitObject"/>s whose positions should be computed.</param>
/// <param name="direction">The scrolling direction.</param>
/// <param name="currentTime">The current time.</param>
/// <param name="timeRange">The duration required to scroll through one length of the screen before any control point adjustments.</param>
/// <param name="timeRange">The duration required to scroll through one length of the screen before any speed adjustments.</param>
/// <param name="length">The length of the screen that is scrolled through.</param>
void ComputePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length);
void UpdatePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length);
}
}
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using osu.Framework.Lists;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Timing;
using OpenTK;
@@ -22,24 +23,45 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
{
foreach (var obj in hitObjects)
{
var controlPoint = controlPointAt(obj.HitObject.StartTime);
obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPoint.Multiplier;
// The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases
double visibleDuration = timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier;
obj.LifetimeStart = obj.HitObject.StartTime - visibleDuration;
if (obj.HitObject is IHasEndTime endTime)
{
// At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin.
// This results in a negative-position value, and the absolute of it indicates the length of the hitobject.
var hitObjectLength = -hitObjectPositionAt(obj, endTime.EndTime, timeRange);
switch (direction)
{
case ScrollingDirection.Up:
case ScrollingDirection.Down:
obj.Height = (float)(hitObjectLength * length.Y);
break;
case ScrollingDirection.Left:
case ScrollingDirection.Right:
obj.Width = (float)(hitObjectLength * length.X);
break;
}
}
if (obj.HasNestedHitObjects)
{
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
// Nested hitobjects don't need to scroll, but they do need accurate positions
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
}
}
}
public void ComputePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
public void UpdatePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
{
foreach (var obj in hitObjects)
{
var controlPoint = controlPointAt(obj.HitObject.StartTime);
var position = (obj.HitObject.StartTime - currentTime) * controlPoint.Multiplier / timeRange;
var position = hitObjectPositionAt(obj, currentTime, timeRange);
switch (direction)
{
@@ -59,7 +81,28 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
}
}
/// <summary>
/// Computes the position of a <see cref="DrawableHitObject"/> at a point in time.
/// <para>
/// At t &lt; startTime, position &gt; 0. <br />
/// At t = startTime, position = 0. <br />
/// At t &gt; startTime, position &lt; 0.
/// </para>
/// </summary>
/// <param name="obj">The <see cref="DrawableHitObject"/>.</param>
/// <param name="time">The time to find the position of <paramref name="obj"/> at.</param>
/// <param name="timeRange">The amount of time visualised by the scrolling area.</param>
/// <returns>The position of <paramref name="obj"/> in the scrolling area at time = <paramref name="time"/>.</returns>
private double hitObjectPositionAt(DrawableHitObject obj, double time, double timeRange)
=> (obj.HitObject.StartTime - time) / timeRange * controlPointAt(obj.HitObject.StartTime).Multiplier;
private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint();
/// <summary>
/// Finds the <see cref="MultiplierControlPoint"/> which affects the speed of hitobjects at a specific time.
/// </summary>
/// <param name="time">The time which the <see cref="MultiplierControlPoint"/> should affect.</param>
/// <returns>The <see cref="MultiplierControlPoint"/>.</returns>
private MultiplierControlPoint controlPointAt(double time)
{
if (controlPoints.Count == 0)
@@ -25,23 +25,25 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
{
foreach (var obj in hitObjects)
{
// To reduce iterations when updating hitobject positions later on, their initial positions are cached
var startPosition = hitObjectPositions[obj] = positionAt(obj.HitObject.StartTime, timeRange);
// Todo: This is approximate and will be incorrect in the case of extreme speed changes
obj.LifetimeStart = obj.HitObject.StartTime - timeRange - 1000;
if (obj.HitObject is IHasEndTime endTime)
{
var diff = positionAt(endTime.EndTime, timeRange) - startPosition;
var hitObjectLength = positionAt(endTime.EndTime, timeRange) - startPosition;
switch (direction)
{
case ScrollingDirection.Up:
case ScrollingDirection.Down:
obj.Height = (float)(diff * length.Y);
obj.Height = (float)(hitObjectLength * length.Y);
break;
case ScrollingDirection.Left:
case ScrollingDirection.Right:
obj.Width = (float)(diff * length.X);
obj.Width = (float)(hitObjectLength * length.X);
break;
}
}
@@ -49,12 +51,14 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
if (obj.HasNestedHitObjects)
{
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
// Nested hitobjects don't need to scroll, but they do need accurate positions
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
}
}
}
public void ComputePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
public void UpdatePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
{
var timelinePosition = positionAt(currentTime, timeRange);
@@ -80,21 +84,38 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
}
}
/// <summary>
/// Finds the position which corresponds to a point in time.
/// This is a non-linear operation that depends on all the control points up to and including the one active at the time value.
/// </summary>
/// <param name="time">The time to find the position at.</param>
/// <param name="timeRange">The amount of time visualised by the scrolling area.</param>
/// <returns>A positive value indicating the position at <paramref name="time"/>.</returns>
private double positionAt(double time, double timeRange)
{
double length = 0;
// We need to consider all timing points until the specified time and not just the currently-active one,
// since each timing point individually affects the positions of _all_ hitobjects after its start time
for (int i = 0; i < controlPoints.Count; i++)
{
var current = controlPoints[i];
var next = i < controlPoints.Count - 1 ? controlPoints[i + 1] : null;
// We don't need to consider any control points beyond the current time, since it will not yet
// affect any hitobjects
if (i > 0 && current.StartTime > time)
continue;
// Duration of the current control point
var currentDuration = (next?.StartTime ?? double.PositiveInfinity) - current.StartTime;
length += Math.Min(currentDuration, time - current.StartTime) * current.Multiplier / timeRange;
// We want to consider the minimal amount of time that this control point has affected,
// which may be either its duration, or the amount of time that has passed within it
var durationInCurrent = Math.Min(currentDuration, time - current.StartTime);
// Figure out how much of the time range the duration represents, and adjust it by the speed multiplier
length += durationInCurrent / timeRange * current.Multiplier;
}
return length;
+2 -4
View File
@@ -26,14 +26,14 @@ namespace osu.Game.Screens
return false;
}
public override bool Push(Screen screen)
public override void Push(Screen screen)
{
// When trying to push a non-loaded screen, load it asynchronously and re-invoke Push
// once it's done.
if (screen.LoadState == LoadState.NotLoaded)
{
LoadComponentAsync(screen, d => Push((BackgroundScreen)d));
return true;
return;
}
// Make sure the in-progress loading is complete before pushing the screen.
@@ -41,8 +41,6 @@ namespace osu.Game.Screens
Thread.Sleep(1);
base.Push(screen);
return true;
}
protected override void Update()
+1 -1
View File
@@ -178,7 +178,7 @@ namespace osu.Game.Screens.Edit
}
currentScreen.Beatmap.BindTo(Beatmap);
screenContainer.Add(currentScreen);
LoadComponentAsync(currentScreen, screenContainer.Add);
}
protected override bool OnWheel(InputState state)
@@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
var dragLayer = new DragLayer(maskContainer.Select);
dragLayer.DragEnd += () => maskSelection.UpdateVisibility();
InternalChildren = new Drawable[]
InternalChildren = new[]
{
dragLayer,
maskSelection,
@@ -43,6 +43,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
public override void Add(HitObjectMask drawable)
{
if (drawable == null) throw new ArgumentNullException(nameof(drawable));
base.Add(drawable);
drawable.Selected += onMaskSelected;
@@ -53,6 +55,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
public override bool Remove(HitObjectMask drawable)
{
if (drawable == null) throw new ArgumentNullException(nameof(drawable));
var result = base.Remove(drawable);
if (result)
+5 -3
View File
@@ -39,6 +39,7 @@ namespace osu.Game.Screens.Menu
private Bindable<bool> menuVoice;
private Bindable<bool> menuMusic;
private Track track;
private WorkingBeatmap beatmap;
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game)
@@ -69,9 +70,8 @@ namespace osu.Game.Screens.Menu
}
}
Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
track = Beatmap.Value.Track;
beatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
track = beatmap.Track;
welcome = audio.Sample.Get(@"welcome");
seeya = audio.Sample.Get(@"seeya");
@@ -81,6 +81,8 @@ namespace osu.Game.Screens.Menu
{
base.OnEntering(last);
Game.Beatmap.Value = beatmap;
if (menuVoice)
welcome.Play();
+7 -9
View File
@@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play
private DrawableStoryboard storyboard;
private Container storyboardContainer;
private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true;
public bool LoadedBeatmapSuccessfully => RulesetContainer?.Objects.Any() == true;
[BackgroundDependencyLoader]
private void load(AudioManager audio, APIAccess api, OsuConfigManager config)
@@ -86,10 +86,7 @@ namespace osu.Game.Screens.Play
WorkingBeatmap working = Beatmap.Value;
if (working is DummyWorkingBeatmap)
{
Exit();
return;
}
sampleRestart = audio.Sample.Get(@"Gameplay/restart");
@@ -122,14 +119,15 @@ namespace osu.Game.Screens.Play
}
if (!RulesetContainer.Objects.Any())
throw new InvalidOperationException("Beatmap contains no hit objects!");
{
Logger.Error(new InvalidOperationException("Beatmap contains no hit objects!"), "Beatmap contains no hit objects!");
return;
}
}
catch (Exception e)
{
Logger.Error(e, "Could not load beatmap sucessfully!");
//couldn't load, hard abort!
Exit();
return;
}
@@ -293,7 +291,7 @@ namespace osu.Game.Screens.Play
{
base.OnEntering(last);
if (!loadedSuccessfully)
if (!LoadedBeatmapSuccessfully)
return;
Content.Alpha = 0;
@@ -343,7 +341,7 @@ namespace osu.Game.Screens.Play
return base.OnExiting(next);
}
if (loadedSuccessfully)
if (LoadedBeatmapSuccessfully)
pauseContainer?.Pause();
return true;
+7 -7
View File
@@ -159,14 +159,14 @@ namespace osu.Game.Screens.Play
loadTask = null;
if (!Push(player))
Exit();
//By default, we want to load the player and never be returned to.
//Note that this may change if the player we load requested a re-run.
ValidForResume = false;
if (player.LoadedBeatmapSuccessfully)
Push(player);
else
{
//By default, we want to load the player and never be returned to.
//Note that this may change if the player we load requested a re-run.
ValidForResume = false;
}
Exit();
});
}, 500);
}
@@ -15,6 +15,8 @@ namespace osu.Game.Screens.Play.PlayerSettings
private readonly PlayerSliderBar<double> dimSliderBar;
private readonly PlayerSliderBar<double> blurSliderBar;
private readonly PlayerCheckbox showStoryboardToggle;
private readonly PlayerCheckbox beatmapSkinsToggle;
private readonly PlayerCheckbox beatmapHitsoundsToggle;
public VisualSettings()
{
@@ -34,7 +36,9 @@ namespace osu.Game.Screens.Play.PlayerSettings
{
Text = "Toggles:"
},
showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" }
showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" },
beatmapSkinsToggle = new PlayerCheckbox { LabelText = "Beatmap skins" },
beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hitsounds" }
};
}
@@ -44,6 +48,8 @@ namespace osu.Game.Screens.Play.PlayerSettings
dimSliderBar.Bindable = config.GetBindable<double>(OsuSetting.DimLevel);
blurSliderBar.Bindable = config.GetBindable<double>(OsuSetting.BlurLevel);
showStoryboardToggle.Bindable = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
beatmapSkinsToggle.Bindable = config.GetBindable<bool>(OsuSetting.BeatmapSkins);
beatmapHitsoundsToggle.Bindable = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds);
}
}
}
+5 -5
View File
@@ -223,11 +223,11 @@ namespace osu.Game.Screens.Ranking
private class DateTimeDisplay : Container
{
private DateTime datetime;
private readonly DateTime date;
public DateTimeDisplay(DateTime datetime)
public DateTimeDisplay(DateTime date)
{
this.datetime = datetime;
this.date = date;
AutoSizeAxes = Axes.Y;
@@ -251,7 +251,7 @@ namespace osu.Game.Screens.Ranking
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Text = datetime.ToShortDateString(),
Text = date.ToShortDateString(),
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
Colour = Color4.White,
},
@@ -259,7 +259,7 @@ namespace osu.Game.Screens.Ranking
{
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Text = datetime.ToShortTimeString(),
Text = date.ToShortTimeString(),
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
Colour = Color4.White,
}

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