diff --git a/.gitattributes b/.gitattributes
index f9cb7c5c9a..baf69b41d1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,19 +1,23 @@
-# This won't normalise line endings, but it will ensure that merge drivers use CRLF
-* -text eol=crlf
-
-# Currently in-use binary file extensions
-*.blend binary
-*.bmp binary
-*.dll binary
-*.exe binary
-*.icns binary
-*.ico binary
-*.jpg binary
-*.osz2 binary
-*.pdn binary
-*.psd binary
-*.PSD binary
-*.tga binary
-*.ttf binary
-*.wav binary
-*.xnb binary
+# Autodetect text files and ensure that we normalise their
+# line endings to lf internally. When checked out they may
+# use different line endings.
+* text=auto
+
+# Check out with crlf (Windows) line endings
+*.sln text eol=crlf
+*.csproj text eol=crlf
+*.cs text diff=csharp eol=crlf
+*.resx text eol=crlf
+*.vsixmanifest text eol=crlf
+packages.config text eol=crlf
+App.config text eol=crlf
+*.bat text eol=crlf
+*.cmd text eol=crlf
+*.snippet text eol=crlf
+
+# Check out with lf (UNIX) line endings
+*.sh text eol=lf
+.gitignore text eol=lf
+.gitattributes text eol=lf
+*.md text eol=lf
+.travis.yml text eol=lf
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 33ff47e0df..5138e940ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,259 +1,259 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-bin/[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-
-# Visual Studio 2015 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# DNX
-project.lock.json
-project.fragment.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
-
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# JetBrains Rider
-.idea/
-*.sln.iml
-
-# CodeRush
-.cr/
-
-# Python Tools for Visual Studio (PTVS)
-__pycache__/
-*.pyc
-Staging/
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+bin/[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+Staging/
diff --git a/.travis.yml b/.travis.yml
index cb2b6d92db..ce353d9b27 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,2 +1,2 @@
-language: csharp
+language: csharp
solution: osu.sln
\ No newline at end of file
diff --git a/app.manifest b/app.manifest
new file mode 100644
index 0000000000..d1c97498f4
--- /dev/null
+++ b/app.manifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/osu-framework b/osu-framework
index 02d7a0fa47..16e6a453db 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 02d7a0fa4798d197cd08570ee48951edbb7c7860
+Subproject commit 16e6a453db9a8f4454238a2911eb5f1444b7ec2a
diff --git a/osu.Desktop.Deploy/App.config b/osu.Desktop.Deploy/App.config
index f6673fef1a..9ec53d5a31 100644
--- a/osu.Desktop.Deploy/App.config
+++ b/osu.Desktop.Deploy/App.config
@@ -1,21 +1,21 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/GitHubObject.cs b/osu.Desktop.Deploy/GitHubObject.cs
index 59c15f8015..02ff16fa69 100644
--- a/osu.Desktop.Deploy/GitHubObject.cs
+++ b/osu.Desktop.Deploy/GitHubObject.cs
@@ -1,16 +1,16 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using Newtonsoft.Json;
-
-namespace osu.Desktop.Deploy
-{
- public class GitHubObject
- {
- [JsonProperty(@"id")]
- public int Id;
-
- [JsonProperty(@"name")]
- public string Name;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using Newtonsoft.Json;
+
+namespace osu.Desktop.Deploy
+{
+ public class GitHubObject
+ {
+ [JsonProperty(@"id")]
+ public int Id;
+
+ [JsonProperty(@"name")]
+ public string Name;
+ }
+}
diff --git a/osu.Desktop.Deploy/GitHubRelease.cs b/osu.Desktop.Deploy/GitHubRelease.cs
index 22820b047a..faf312d4f7 100644
--- a/osu.Desktop.Deploy/GitHubRelease.cs
+++ b/osu.Desktop.Deploy/GitHubRelease.cs
@@ -1,28 +1,28 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using Newtonsoft.Json;
-
-namespace osu.Desktop.Deploy
-{
- public class GitHubRelease
- {
- [JsonProperty(@"id")]
- public int Id;
-
- [JsonProperty(@"tag_name")]
- public string TagName => $"v{Name}";
-
- [JsonProperty(@"name")]
- public string Name;
-
- [JsonProperty(@"draft")]
- public bool Draft;
-
- [JsonProperty(@"prerelease")]
- public bool PreRelease;
-
- [JsonProperty(@"upload_url")]
- public string UploadUrl;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using Newtonsoft.Json;
+
+namespace osu.Desktop.Deploy
+{
+ public class GitHubRelease
+ {
+ [JsonProperty(@"id")]
+ public int Id;
+
+ [JsonProperty(@"tag_name")]
+ public string TagName => $"v{Name}";
+
+ [JsonProperty(@"name")]
+ public string Name;
+
+ [JsonProperty(@"draft")]
+ public bool Draft;
+
+ [JsonProperty(@"prerelease")]
+ public bool PreRelease;
+
+ [JsonProperty(@"upload_url")]
+ public string UploadUrl;
+ }
+}
diff --git a/osu.Desktop.Deploy/Program.cs b/osu.Desktop.Deploy/Program.cs
index 3c1451d555..6095ce062d 100644
--- a/osu.Desktop.Deploy/Program.cs
+++ b/osu.Desktop.Deploy/Program.cs
@@ -1,438 +1,438 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using Newtonsoft.Json;
-using osu.Framework.IO.Network;
-using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
-using WebRequest = osu.Framework.IO.Network.WebRequest;
-
-namespace osu.Desktop.Deploy
-{
- internal static class Program
- {
- private static string packages => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
- private static string nugetPath => Path.Combine(packages, @"nuget.commandline\4.5.1\tools\NuGet.exe");
- private static string squirrelPath => Path.Combine(packages, @"squirrel.windows\1.7.8\tools\Squirrel.exe");
- private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
-
- public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
- public static string ReleasesFolder = ConfigurationManager.AppSettings["ReleasesFolder"];
- public static string GitHubAccessToken = ConfigurationManager.AppSettings["GitHubAccessToken"];
- public static string GitHubUsername = ConfigurationManager.AppSettings["GitHubUsername"];
- public static string GitHubRepoName = ConfigurationManager.AppSettings["GitHubRepoName"];
- public static string SolutionName = ConfigurationManager.AppSettings["SolutionName"];
- public static string ProjectName = ConfigurationManager.AppSettings["ProjectName"];
- public static string NuSpecName = ConfigurationManager.AppSettings["NuSpecName"];
- public static string TargetNames = ConfigurationManager.AppSettings["TargetName"];
- public static string PackageName = ConfigurationManager.AppSettings["PackageName"];
- public static string IconName = ConfigurationManager.AppSettings["IconName"];
- public static string CodeSigningCertificate = ConfigurationManager.AppSettings["CodeSigningCertificate"];
-
- public static string GitHubApiEndpoint => $"https://api.github.com/repos/{GitHubUsername}/{GitHubRepoName}/releases";
- public static string GitHubReleasePage => $"https://github.com/{GitHubUsername}/{GitHubRepoName}/releases";
-
- ///
- /// How many previous build deltas we want to keep when publishing.
- ///
- private const int keep_delta_count = 4;
-
- private static string codeSigningCmd => string.IsNullOrEmpty(codeSigningPassword) ? "" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\"";
-
- private static string homeDir => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
- private static string codeSigningCertPath => Path.Combine(homeDir, CodeSigningCertificate);
- private static string solutionPath => Environment.CurrentDirectory;
- private static string stagingPath => Path.Combine(solutionPath, StagingFolder);
- private static string iconPath => Path.Combine(solutionPath, ProjectName, IconName);
-
- private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
- private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
-
- private static readonly Stopwatch sw = new Stopwatch();
-
- private static string codeSigningPassword;
-
- public static void Main(string[] args)
- {
- displayHeader();
-
- findSolutionPath();
-
- if (!Directory.Exists(ReleasesFolder))
- {
- write("WARNING: No release directory found. Make sure you want this!", ConsoleColor.Yellow);
- Directory.CreateDirectory(ReleasesFolder);
- }
-
- checkGitHubReleases();
-
- refreshDirectory(StagingFolder);
-
- //increment build number until we have a unique one.
- string verBase = DateTime.Now.ToString("yyyy.Mdd.");
- int increment = 0;
- while (Directory.GetFiles(ReleasesFolder, $"*{verBase}{increment}*").Any())
- increment++;
-
- string version = $"{verBase}{increment}";
-
- Console.ForegroundColor = ConsoleColor.White;
- Console.Write($"Ready to deploy {version}: ");
- Console.ReadLine();
-
- sw.Start();
-
- if (!string.IsNullOrEmpty(CodeSigningCertificate))
- {
- Console.Write("Enter code signing password: ");
- codeSigningPassword = readLineMasked();
- }
-
- write("Updating AssemblyInfo...");
- updateCsprojVersion(version);
-
- write("Running build process...");
- foreach (string targetName in TargetNames.Split(','))
- runCommand(msbuild_path, $"/v:quiet /m /t:{targetName.Replace('.', '_')} /p:OutputPath={stagingPath};Targets=\"Clean;Build\";Configuration=Release {SolutionName}.sln");
-
- write("Creating NuGet deployment package...");
- runCommand(nugetPath, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");
-
- //prune once before checking for files so we can avoid erroring on files which aren't even needed for this build.
- pruneReleases();
-
- checkReleaseFiles();
-
- write("Running squirrel build...");
- runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
-
- //prune again to clean up before upload.
- pruneReleases();
-
- //rename setup to install.
- File.Copy(Path.Combine(ReleasesFolder, "Setup.exe"), Path.Combine(ReleasesFolder, "install.exe"), true);
- File.Delete(Path.Combine(ReleasesFolder, "Setup.exe"));
-
- uploadBuild(version);
-
- //reset assemblyinfo.
- updateCsprojVersion("0.0.0");
-
- write("Done!", ConsoleColor.White);
- Console.ReadLine();
- }
-
- private static void displayHeader()
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine();
- Console.WriteLine(" Please note that OSU! and PPY are registered trademarks and as such covered by trademark law.");
- Console.WriteLine(" Do not distribute builds of this project publicly that make use of these.");
- Console.ResetColor();
- Console.WriteLine();
- }
-
- ///
- /// Ensure we have all the files in the release directory which are expected to be there.
- /// This should have been accounted for in earlier steps, and just serves as a verification step.
- ///
- private static void checkReleaseFiles()
- {
- if (!canGitHub) return;
-
- var releaseLines = getReleaseLines();
-
- //ensure we have all files necessary
- foreach (var l in releaseLines)
- if (!File.Exists(Path.Combine(ReleasesFolder, l.Filename)))
- error($"Local file missing {l.Filename}");
- }
-
- private static IEnumerable getReleaseLines() => File.ReadAllLines(Path.Combine(ReleasesFolder, "RELEASES")).Select(l => new ReleaseLine(l));
-
- private static void pruneReleases()
- {
- if (!canGitHub) return;
-
- write("Pruning RELEASES...");
-
- var releaseLines = getReleaseLines().ToList();
-
- var fulls = releaseLines.Where(l => l.Filename.Contains("-full")).Reverse().Skip(1);
-
- //remove any FULL releases (except most recent)
- foreach (var l in fulls)
- {
- write($"- Removing old release {l.Filename}", ConsoleColor.Yellow);
- File.Delete(Path.Combine(ReleasesFolder, l.Filename));
- releaseLines.Remove(l);
- }
-
- //remove excess deltas
- var deltas = releaseLines.Where(l => l.Filename.Contains("-delta")).ToArray();
- if (deltas.Length > keep_delta_count)
- {
- foreach (var l in deltas.Take(deltas.Length - keep_delta_count))
- {
- write($"- Removing old delta {l.Filename}", ConsoleColor.Yellow);
- File.Delete(Path.Combine(ReleasesFolder, l.Filename));
- releaseLines.Remove(l);
- }
- }
-
- var lines = new List();
- releaseLines.ForEach(l => lines.Add(l.ToString()));
- File.WriteAllLines(Path.Combine(ReleasesFolder, "RELEASES"), lines);
- }
-
- private static void uploadBuild(string version)
- {
- if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
- return;
-
- write("Publishing to GitHub...");
-
- write($"- Creating release {version}...", ConsoleColor.Yellow);
- var req = new JsonWebRequest($"{GitHubApiEndpoint}")
- {
- Method = HttpMethod.POST,
- };
- req.AddRaw(JsonConvert.SerializeObject(new GitHubRelease
- {
- Name = version,
- Draft = true,
- PreRelease = true
- }));
- req.AuthenticatedBlockingPerform();
-
- var assetUploadUrl = req.ResponseObject.UploadUrl.Replace("{?name,label}", "?name={0}");
- foreach (var a in Directory.GetFiles(ReleasesFolder).Reverse()) //reverse to upload RELEASES first.
- {
- write($"- Adding asset {a}...", ConsoleColor.Yellow);
- var upload = new WebRequest(assetUploadUrl, Path.GetFileName(a))
- {
- Method = HttpMethod.POST,
- Timeout = 240000,
- ContentType = "application/octet-stream",
- };
-
- upload.AddRaw(File.ReadAllBytes(a));
- upload.AuthenticatedBlockingPerform();
- }
-
- openGitHubReleasePage();
- }
-
- private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
-
- private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
-
- private static void checkGitHubReleases()
- {
- if (!canGitHub) return;
-
- write("Checking GitHub releases...");
- var req = new JsonWebRequest>($"{GitHubApiEndpoint}");
- req.AuthenticatedBlockingPerform();
-
- var lastRelease = req.ResponseObject.FirstOrDefault();
-
- if (lastRelease == null)
- return;
-
- if (lastRelease.Draft)
- {
- openGitHubReleasePage();
- error("There's a pending draft release! You probably don't want to push a build with this present.");
- }
-
- //there's a previous release for this project.
- var assetReq = new JsonWebRequest>($"{GitHubApiEndpoint}/{lastRelease.Id}/assets");
- assetReq.AuthenticatedBlockingPerform();
- var assets = assetReq.ResponseObject;
-
- //make sure our RELEASES file is the same as the last build on the server.
- var releaseAsset = assets.FirstOrDefault(a => a.Name == "RELEASES");
-
- //if we don't have a RELEASES asset then the previous release likely wasn't a Squirrel one.
- if (releaseAsset == null) return;
-
- write($"Last GitHub release was {lastRelease.Name}.");
-
- bool requireDownload = false;
-
- if (!File.Exists(Path.Combine(ReleasesFolder, nupkgDistroFilename(lastRelease.Name))))
- {
- write("Last version's package not found locally.", ConsoleColor.Red);
- requireDownload = true;
- }
- else
- {
- var lastReleases = new RawFileWebRequest($"{GitHubApiEndpoint}/assets/{releaseAsset.Id}");
- lastReleases.AuthenticatedBlockingPerform();
- if (File.ReadAllText(Path.Combine(ReleasesFolder, "RELEASES")) != lastReleases.ResponseString)
- {
- write("Server's RELEASES differed from ours.", ConsoleColor.Red);
- requireDownload = true;
- }
- }
-
- if (!requireDownload) return;
-
- write("Refreshing local releases directory...");
- refreshDirectory(ReleasesFolder);
-
- foreach (var a in assets)
- {
- if (a.Name.EndsWith(".exe")) continue;
-
- write($"- Downloading {a.Name}...", ConsoleColor.Yellow);
- new FileWebRequest(Path.Combine(ReleasesFolder, a.Name), $"{GitHubApiEndpoint}/assets/{a.Id}").AuthenticatedBlockingPerform();
- }
- }
-
- private static void refreshDirectory(string directory)
- {
- if (Directory.Exists(directory))
- Directory.Delete(directory, true);
- Directory.CreateDirectory(directory);
- }
-
- private static void updateCsprojVersion(string version)
- {
- var toUpdate = new[] { "", "" };
- string file = Path.Combine(ProjectName, $"{ProjectName}.csproj");
-
- var l1 = File.ReadAllLines(file);
- List l2 = new List();
- foreach (var l in l1)
- {
- string line = l;
-
- foreach (var tag in toUpdate)
- {
- int startIndex = l.IndexOf(tag, StringComparison.InvariantCulture);
- if (startIndex == -1)
- continue;
- startIndex += tag.Length;
-
- int endIndex = l.IndexOf("<", startIndex, StringComparison.InvariantCulture);
- line = $"{l.Substring(0, startIndex)}{version}{l.Substring(endIndex)}";
- }
-
- l2.Add(line);
- }
-
- File.WriteAllLines(file, l2);
- }
-
- ///
- /// Find the base path of the active solution (git checkout location)
- ///
- private static void findSolutionPath()
- {
- string path = Path.GetDirectoryName(Environment.CommandLine.Replace("\"", "").Trim());
-
- if (string.IsNullOrEmpty(path))
- path = Environment.CurrentDirectory;
-
- while (!File.Exists(Path.Combine(path, $"{SolutionName}.sln")))
- path = path.Remove(path.LastIndexOf(Path.DirectorySeparatorChar));
- path += Path.DirectorySeparatorChar;
-
- Environment.CurrentDirectory = path;
- }
-
- private static bool runCommand(string command, string args)
- {
- var psi = new ProcessStartInfo(command, args)
- {
- WorkingDirectory = solutionPath,
- CreateNoWindow = true,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- UseShellExecute = false,
- WindowStyle = ProcessWindowStyle.Hidden
- };
-
- Process p = Process.Start(psi);
- if (p == null) return false;
-
- string output = p.StandardOutput.ReadToEnd();
- output += p.StandardError.ReadToEnd();
-
- if (p.ExitCode == 0) return true;
-
- write(output);
- error($"Command {command} {args} failed!");
- return false;
- }
-
- private static string readLineMasked()
- {
- var fg = Console.ForegroundColor;
- Console.ForegroundColor = Console.BackgroundColor;
- var ret = Console.ReadLine();
- Console.ForegroundColor = fg;
-
- return ret;
- }
-
- private static void error(string message)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"FATAL ERROR: {message}");
-
- Console.ReadLine();
- Environment.Exit(-1);
- }
-
- private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
- {
- if (sw.ElapsedMilliseconds > 0)
- {
- Console.ForegroundColor = ConsoleColor.Green;
- Console.Write(sw.ElapsedMilliseconds.ToString().PadRight(8));
- }
- Console.ForegroundColor = col;
- Console.WriteLine(message);
- }
-
- public static void AuthenticatedBlockingPerform(this WebRequest r)
- {
- r.AddHeader("Authorization", $"token {GitHubAccessToken}");
- r.Perform();
- }
- }
-
- internal class RawFileWebRequest : WebRequest
- {
- public RawFileWebRequest(string url) : base(url)
- {
- }
-
- protected override string Accept => "application/octet-stream";
- }
-
- internal class ReleaseLine
- {
- public string Hash;
- public string Filename;
- public int Filesize;
-
- public ReleaseLine(string line)
- {
- var split = line.Split(' ');
- Hash = split[0];
- Filename = split[1];
- Filesize = int.Parse(split[2]);
- }
-
- public override string ToString() => $"{Hash} {Filename} {Filesize}";
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json;
+using osu.Framework.IO.Network;
+using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
+using WebRequest = osu.Framework.IO.Network.WebRequest;
+
+namespace osu.Desktop.Deploy
+{
+ internal static class Program
+ {
+ private static string packages => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
+ private static string nugetPath => Path.Combine(packages, @"nuget.commandline\4.5.1\tools\NuGet.exe");
+ private static string squirrelPath => Path.Combine(packages, @"squirrel.windows\1.7.8\tools\Squirrel.exe");
+ private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
+
+ public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
+ public static string ReleasesFolder = ConfigurationManager.AppSettings["ReleasesFolder"];
+ public static string GitHubAccessToken = ConfigurationManager.AppSettings["GitHubAccessToken"];
+ public static string GitHubUsername = ConfigurationManager.AppSettings["GitHubUsername"];
+ public static string GitHubRepoName = ConfigurationManager.AppSettings["GitHubRepoName"];
+ public static string SolutionName = ConfigurationManager.AppSettings["SolutionName"];
+ public static string ProjectName = ConfigurationManager.AppSettings["ProjectName"];
+ public static string NuSpecName = ConfigurationManager.AppSettings["NuSpecName"];
+ public static string TargetNames = ConfigurationManager.AppSettings["TargetName"];
+ public static string PackageName = ConfigurationManager.AppSettings["PackageName"];
+ public static string IconName = ConfigurationManager.AppSettings["IconName"];
+ public static string CodeSigningCertificate = ConfigurationManager.AppSettings["CodeSigningCertificate"];
+
+ public static string GitHubApiEndpoint => $"https://api.github.com/repos/{GitHubUsername}/{GitHubRepoName}/releases";
+ public static string GitHubReleasePage => $"https://github.com/{GitHubUsername}/{GitHubRepoName}/releases";
+
+ ///
+ /// How many previous build deltas we want to keep when publishing.
+ ///
+ private const int keep_delta_count = 4;
+
+ private static string codeSigningCmd => string.IsNullOrEmpty(codeSigningPassword) ? "" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\"";
+
+ private static string homeDir => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ private static string codeSigningCertPath => Path.Combine(homeDir, CodeSigningCertificate);
+ private static string solutionPath => Environment.CurrentDirectory;
+ private static string stagingPath => Path.Combine(solutionPath, StagingFolder);
+ private static string iconPath => Path.Combine(solutionPath, ProjectName, IconName);
+
+ private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
+ private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
+
+ private static readonly Stopwatch sw = new Stopwatch();
+
+ private static string codeSigningPassword;
+
+ public static void Main(string[] args)
+ {
+ displayHeader();
+
+ findSolutionPath();
+
+ if (!Directory.Exists(ReleasesFolder))
+ {
+ write("WARNING: No release directory found. Make sure you want this!", ConsoleColor.Yellow);
+ Directory.CreateDirectory(ReleasesFolder);
+ }
+
+ checkGitHubReleases();
+
+ refreshDirectory(StagingFolder);
+
+ //increment build number until we have a unique one.
+ string verBase = DateTime.Now.ToString("yyyy.Mdd.");
+ int increment = 0;
+ while (Directory.GetFiles(ReleasesFolder, $"*{verBase}{increment}*").Any())
+ increment++;
+
+ string version = $"{verBase}{increment}";
+
+ Console.ForegroundColor = ConsoleColor.White;
+ Console.Write($"Ready to deploy {version}: ");
+ Console.ReadLine();
+
+ sw.Start();
+
+ if (!string.IsNullOrEmpty(CodeSigningCertificate))
+ {
+ Console.Write("Enter code signing password: ");
+ codeSigningPassword = readLineMasked();
+ }
+
+ write("Updating AssemblyInfo...");
+ updateCsprojVersion(version);
+
+ write("Running build process...");
+ foreach (string targetName in TargetNames.Split(','))
+ runCommand(msbuild_path, $"/v:quiet /m /t:{targetName.Replace('.', '_')} /p:OutputPath={stagingPath};Targets=\"Clean;Build\";Configuration=Release {SolutionName}.sln");
+
+ write("Creating NuGet deployment package...");
+ runCommand(nugetPath, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");
+
+ //prune once before checking for files so we can avoid erroring on files which aren't even needed for this build.
+ pruneReleases();
+
+ checkReleaseFiles();
+
+ write("Running squirrel build...");
+ runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
+
+ //prune again to clean up before upload.
+ pruneReleases();
+
+ //rename setup to install.
+ File.Copy(Path.Combine(ReleasesFolder, "Setup.exe"), Path.Combine(ReleasesFolder, "install.exe"), true);
+ File.Delete(Path.Combine(ReleasesFolder, "Setup.exe"));
+
+ uploadBuild(version);
+
+ //reset assemblyinfo.
+ updateCsprojVersion("0.0.0");
+
+ write("Done!", ConsoleColor.White);
+ Console.ReadLine();
+ }
+
+ private static void displayHeader()
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine();
+ Console.WriteLine(" Please note that OSU! and PPY are registered trademarks and as such covered by trademark law.");
+ Console.WriteLine(" Do not distribute builds of this project publicly that make use of these.");
+ Console.ResetColor();
+ Console.WriteLine();
+ }
+
+ ///
+ /// Ensure we have all the files in the release directory which are expected to be there.
+ /// This should have been accounted for in earlier steps, and just serves as a verification step.
+ ///
+ private static void checkReleaseFiles()
+ {
+ if (!canGitHub) return;
+
+ var releaseLines = getReleaseLines();
+
+ //ensure we have all files necessary
+ foreach (var l in releaseLines)
+ if (!File.Exists(Path.Combine(ReleasesFolder, l.Filename)))
+ error($"Local file missing {l.Filename}");
+ }
+
+ private static IEnumerable getReleaseLines() => File.ReadAllLines(Path.Combine(ReleasesFolder, "RELEASES")).Select(l => new ReleaseLine(l));
+
+ private static void pruneReleases()
+ {
+ if (!canGitHub) return;
+
+ write("Pruning RELEASES...");
+
+ var releaseLines = getReleaseLines().ToList();
+
+ var fulls = releaseLines.Where(l => l.Filename.Contains("-full")).Reverse().Skip(1);
+
+ //remove any FULL releases (except most recent)
+ foreach (var l in fulls)
+ {
+ write($"- Removing old release {l.Filename}", ConsoleColor.Yellow);
+ File.Delete(Path.Combine(ReleasesFolder, l.Filename));
+ releaseLines.Remove(l);
+ }
+
+ //remove excess deltas
+ var deltas = releaseLines.Where(l => l.Filename.Contains("-delta")).ToArray();
+ if (deltas.Length > keep_delta_count)
+ {
+ foreach (var l in deltas.Take(deltas.Length - keep_delta_count))
+ {
+ write($"- Removing old delta {l.Filename}", ConsoleColor.Yellow);
+ File.Delete(Path.Combine(ReleasesFolder, l.Filename));
+ releaseLines.Remove(l);
+ }
+ }
+
+ var lines = new List();
+ releaseLines.ForEach(l => lines.Add(l.ToString()));
+ File.WriteAllLines(Path.Combine(ReleasesFolder, "RELEASES"), lines);
+ }
+
+ private static void uploadBuild(string version)
+ {
+ if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
+ return;
+
+ write("Publishing to GitHub...");
+
+ write($"- Creating release {version}...", ConsoleColor.Yellow);
+ var req = new JsonWebRequest($"{GitHubApiEndpoint}")
+ {
+ Method = HttpMethod.POST,
+ };
+ req.AddRaw(JsonConvert.SerializeObject(new GitHubRelease
+ {
+ Name = version,
+ Draft = true,
+ PreRelease = true
+ }));
+ req.AuthenticatedBlockingPerform();
+
+ var assetUploadUrl = req.ResponseObject.UploadUrl.Replace("{?name,label}", "?name={0}");
+ foreach (var a in Directory.GetFiles(ReleasesFolder).Reverse()) //reverse to upload RELEASES first.
+ {
+ write($"- Adding asset {a}...", ConsoleColor.Yellow);
+ var upload = new WebRequest(assetUploadUrl, Path.GetFileName(a))
+ {
+ Method = HttpMethod.POST,
+ Timeout = 240000,
+ ContentType = "application/octet-stream",
+ };
+
+ upload.AddRaw(File.ReadAllBytes(a));
+ upload.AuthenticatedBlockingPerform();
+ }
+
+ openGitHubReleasePage();
+ }
+
+ private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
+
+ private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
+
+ private static void checkGitHubReleases()
+ {
+ if (!canGitHub) return;
+
+ write("Checking GitHub releases...");
+ var req = new JsonWebRequest>($"{GitHubApiEndpoint}");
+ req.AuthenticatedBlockingPerform();
+
+ var lastRelease = req.ResponseObject.FirstOrDefault();
+
+ if (lastRelease == null)
+ return;
+
+ if (lastRelease.Draft)
+ {
+ openGitHubReleasePage();
+ error("There's a pending draft release! You probably don't want to push a build with this present.");
+ }
+
+ //there's a previous release for this project.
+ var assetReq = new JsonWebRequest>($"{GitHubApiEndpoint}/{lastRelease.Id}/assets");
+ assetReq.AuthenticatedBlockingPerform();
+ var assets = assetReq.ResponseObject;
+
+ //make sure our RELEASES file is the same as the last build on the server.
+ var releaseAsset = assets.FirstOrDefault(a => a.Name == "RELEASES");
+
+ //if we don't have a RELEASES asset then the previous release likely wasn't a Squirrel one.
+ if (releaseAsset == null) return;
+
+ write($"Last GitHub release was {lastRelease.Name}.");
+
+ bool requireDownload = false;
+
+ if (!File.Exists(Path.Combine(ReleasesFolder, nupkgDistroFilename(lastRelease.Name))))
+ {
+ write("Last version's package not found locally.", ConsoleColor.Red);
+ requireDownload = true;
+ }
+ else
+ {
+ var lastReleases = new RawFileWebRequest($"{GitHubApiEndpoint}/assets/{releaseAsset.Id}");
+ lastReleases.AuthenticatedBlockingPerform();
+ if (File.ReadAllText(Path.Combine(ReleasesFolder, "RELEASES")) != lastReleases.ResponseString)
+ {
+ write("Server's RELEASES differed from ours.", ConsoleColor.Red);
+ requireDownload = true;
+ }
+ }
+
+ if (!requireDownload) return;
+
+ write("Refreshing local releases directory...");
+ refreshDirectory(ReleasesFolder);
+
+ foreach (var a in assets)
+ {
+ if (a.Name.EndsWith(".exe")) continue;
+
+ write($"- Downloading {a.Name}...", ConsoleColor.Yellow);
+ new FileWebRequest(Path.Combine(ReleasesFolder, a.Name), $"{GitHubApiEndpoint}/assets/{a.Id}").AuthenticatedBlockingPerform();
+ }
+ }
+
+ private static void refreshDirectory(string directory)
+ {
+ if (Directory.Exists(directory))
+ Directory.Delete(directory, true);
+ Directory.CreateDirectory(directory);
+ }
+
+ private static void updateCsprojVersion(string version)
+ {
+ var toUpdate = new[] { "", "" };
+ string file = Path.Combine(ProjectName, $"{ProjectName}.csproj");
+
+ var l1 = File.ReadAllLines(file);
+ List l2 = new List();
+ foreach (var l in l1)
+ {
+ string line = l;
+
+ foreach (var tag in toUpdate)
+ {
+ int startIndex = l.IndexOf(tag, StringComparison.InvariantCulture);
+ if (startIndex == -1)
+ continue;
+ startIndex += tag.Length;
+
+ int endIndex = l.IndexOf("<", startIndex, StringComparison.InvariantCulture);
+ line = $"{l.Substring(0, startIndex)}{version}{l.Substring(endIndex)}";
+ }
+
+ l2.Add(line);
+ }
+
+ File.WriteAllLines(file, l2);
+ }
+
+ ///
+ /// Find the base path of the active solution (git checkout location)
+ ///
+ private static void findSolutionPath()
+ {
+ string path = Path.GetDirectoryName(Environment.CommandLine.Replace("\"", "").Trim());
+
+ if (string.IsNullOrEmpty(path))
+ path = Environment.CurrentDirectory;
+
+ while (!File.Exists(Path.Combine(path, $"{SolutionName}.sln")))
+ path = path.Remove(path.LastIndexOf(Path.DirectorySeparatorChar));
+ path += Path.DirectorySeparatorChar;
+
+ Environment.CurrentDirectory = path;
+ }
+
+ private static bool runCommand(string command, string args)
+ {
+ var psi = new ProcessStartInfo(command, args)
+ {
+ WorkingDirectory = solutionPath,
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ WindowStyle = ProcessWindowStyle.Hidden
+ };
+
+ Process p = Process.Start(psi);
+ if (p == null) return false;
+
+ string output = p.StandardOutput.ReadToEnd();
+ output += p.StandardError.ReadToEnd();
+
+ if (p.ExitCode == 0) return true;
+
+ write(output);
+ error($"Command {command} {args} failed!");
+ return false;
+ }
+
+ private static string readLineMasked()
+ {
+ var fg = Console.ForegroundColor;
+ Console.ForegroundColor = Console.BackgroundColor;
+ var ret = Console.ReadLine();
+ Console.ForegroundColor = fg;
+
+ return ret;
+ }
+
+ private static void error(string message)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"FATAL ERROR: {message}");
+
+ Console.ReadLine();
+ Environment.Exit(-1);
+ }
+
+ private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
+ {
+ if (sw.ElapsedMilliseconds > 0)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.Write(sw.ElapsedMilliseconds.ToString().PadRight(8));
+ }
+ Console.ForegroundColor = col;
+ Console.WriteLine(message);
+ }
+
+ public static void AuthenticatedBlockingPerform(this WebRequest r)
+ {
+ r.AddHeader("Authorization", $"token {GitHubAccessToken}");
+ r.Perform();
+ }
+ }
+
+ internal class RawFileWebRequest : WebRequest
+ {
+ public RawFileWebRequest(string url) : base(url)
+ {
+ }
+
+ protected override string Accept => "application/octet-stream";
+ }
+
+ internal class ReleaseLine
+ {
+ public string Hash;
+ public string Filename;
+ public int Filesize;
+
+ public ReleaseLine(string line)
+ {
+ var split = line.Split(' ');
+ Hash = split[0];
+ Filename = split[1];
+ Filesize = int.Parse(split[2]);
+ }
+
+ public override string ToString() => $"{Hash} {Filename} {Filesize}";
+ }
+}
diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
index a18db9477a..6b7509a381 100644
--- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
+++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 3704d2d5d8..a495d7048d 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -1,120 +1,120 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading.Tasks;
-using osu.Desktop.Overlays;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Platform;
-using osu.Game;
-using OpenTK.Input;
-using Microsoft.Win32;
-
-namespace osu.Desktop
-{
- internal class OsuGameDesktop : OsuGame
- {
- private readonly bool noVersionOverlay;
-
- public OsuGameDesktop(string[] args = null)
- : base(args)
- {
- noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
- }
-
- public override Storage GetStorageForStableInstall()
- {
- try
- {
- return new StableStorage();
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// A method of accessing an osu-stable install in a controlled fashion.
- ///
- private class StableStorage : DesktopStorage
- {
- protected override string LocateBasePath()
- {
- bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs"));
-
- string stableInstallPath;
-
- try
- {
- using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
- stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
-
- if (checkExists(stableInstallPath))
- return stableInstallPath;
- }
- catch
- {
- }
-
- stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
- if (checkExists(stableInstallPath))
- return stableInstallPath;
-
- stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
- if (checkExists(stableInstallPath))
- return stableInstallPath;
-
- return null;
- }
-
- public StableStorage()
- : base(string.Empty)
- {
- }
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- if (!noVersionOverlay)
- {
- LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
- {
- Add(v);
- v.State = Visibility.Visible;
- });
- }
- }
-
- public override void SetHost(GameHost host)
- {
- base.SetHost(host);
- var desktopWindow = host.Window as DesktopGameWindow;
- if (desktopWindow != null)
- {
- desktopWindow.CursorState |= CursorState.Hidden;
-
- desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
- desktopWindow.Title = Name;
-
- desktopWindow.FileDrop += fileDrop;
- }
- }
-
- private void fileDrop(object sender, FileDropEventArgs e)
- {
- var filePaths = new[] { e.FileName };
-
- var firstExtension = Path.GetExtension(filePaths.First());
-
- if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
-
- Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using osu.Desktop.Overlays;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Platform;
+using osu.Game;
+using OpenTK.Input;
+using Microsoft.Win32;
+
+namespace osu.Desktop
+{
+ internal class OsuGameDesktop : OsuGame
+ {
+ private readonly bool noVersionOverlay;
+
+ public OsuGameDesktop(string[] args = null)
+ : base(args)
+ {
+ noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
+ }
+
+ public override Storage GetStorageForStableInstall()
+ {
+ try
+ {
+ return new StableStorage();
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// A method of accessing an osu-stable install in a controlled fashion.
+ ///
+ private class StableStorage : DesktopStorage
+ {
+ protected override string LocateBasePath()
+ {
+ bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs"));
+
+ string stableInstallPath;
+
+ try
+ {
+ using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
+ stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
+
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+ }
+ catch
+ {
+ }
+
+ stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+
+ stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+
+ return null;
+ }
+
+ public StableStorage()
+ : base(string.Empty)
+ {
+ }
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ if (!noVersionOverlay)
+ {
+ LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
+ {
+ Add(v);
+ v.State = Visibility.Visible;
+ });
+ }
+ }
+
+ public override void SetHost(GameHost host)
+ {
+ base.SetHost(host);
+ var desktopWindow = host.Window as DesktopGameWindow;
+ if (desktopWindow != null)
+ {
+ desktopWindow.CursorState |= CursorState.Hidden;
+
+ desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
+ desktopWindow.Title = Name;
+
+ desktopWindow.FileDrop += fileDrop;
+ }
+ }
+
+ private void fileDrop(object sender, FileDropEventArgs e)
+ {
+ var filePaths = new[] { e.FileName };
+
+ var firstExtension = Path.GetExtension(filePaths.First());
+
+ if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
+
+ Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
+ }
+ }
+}
diff --git a/osu.Desktop/Overlays/SquirrelUpdateManager.cs b/osu.Desktop/Overlays/SquirrelUpdateManager.cs
index 61d8a75ae3..ea86d2f028 100644
--- a/osu.Desktop/Overlays/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Overlays/SquirrelUpdateManager.cs
@@ -1,164 +1,164 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-#if NET_FRAMEWORK
-using System;
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Colour;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Logging;
-using osu.Game;
-using osu.Game.Graphics;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Notifications;
-using OpenTK;
-using OpenTK.Graphics;
-using Squirrel;
-
-namespace osu.Desktop.Overlays
-{
- public class SquirrelUpdateManager : Component
- {
- private UpdateManager updateManager;
- private NotificationOverlay notificationOverlay;
-
- public void PrepareUpdate()
- {
- // Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
- UpdateManager.RestartAppWhenExited().Wait();
- }
-
- [BackgroundDependencyLoader]
- private void load(NotificationOverlay notification, OsuGameBase game)
- {
- notificationOverlay = notification;
-
- if (game.IsDeployedBuild)
- Schedule(() => checkForUpdateAsync());
- }
-
- private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
- {
- //should we schedule a retry on completion of this check?
- bool scheduleRetry = true;
-
- try
- {
- if (updateManager == null) updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
-
- var info = await updateManager.CheckForUpdate(!useDeltaPatching);
- if (info.ReleasesToApply.Count == 0)
- //no updates available. bail and retry later.
- return;
-
- if (notification == null)
- {
- notification = new UpdateProgressNotification(this) { State = ProgressNotificationState.Active };
- Schedule(() => notificationOverlay.Post(notification));
- }
-
- notification.Progress = 0;
- notification.Text = @"Downloading update...";
-
- try
- {
- await updateManager.DownloadReleases(info.ReleasesToApply, p => notification.Progress = p / 100f);
-
- notification.Progress = 0;
- notification.Text = @"Installing update...";
-
- await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f);
-
- notification.State = ProgressNotificationState.Completed;
- }
- catch (Exception e)
- {
- if (useDeltaPatching)
- {
- Logger.Error(e, @"delta patching failed!");
-
- //could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
- //try again without deltas.
- checkForUpdateAsync(false, notification);
- scheduleRetry = false;
- }
- else
- {
- Logger.Error(e, @"update failed!");
- }
- }
- }
- catch (Exception)
- {
- // we'll ignore this and retry later. can be triggered by no internet connection or thread abortion.
- }
- finally
- {
- if (scheduleRetry)
- {
- if (notification != null)
- notification.State = ProgressNotificationState.Cancelled;
-
- //check again in 30 minutes.
- Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
- }
- }
- }
-
- protected override void Dispose(bool isDisposing)
- {
- base.Dispose(isDisposing);
- updateManager?.Dispose();
- }
-
- private class UpdateProgressNotification : ProgressNotification
- {
- private readonly SquirrelUpdateManager updateManager;
- private OsuGame game;
-
- public UpdateProgressNotification(SquirrelUpdateManager updateManager)
- {
- this.updateManager = updateManager;
- }
-
- protected override Notification CreateCompletionNotification()
- {
- return new ProgressCompletionNotification
- {
- Text = @"Update ready to install. Click to restart!",
- Activated = () =>
- {
- updateManager.PrepareUpdate();
- game.GracefullyExit();
- return true;
- }
- };
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours, OsuGame game)
- {
- this.game = game;
-
- IconContent.AddRange(new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
- },
- new SpriteIcon
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Icon = FontAwesome.fa_upload,
- Colour = Color4.White,
- Size = new Vector2(20),
- }
- });
- }
- }
- }
-}
-#endif
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+#if NET_FRAMEWORK
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Logging;
+using osu.Game;
+using osu.Game.Graphics;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
+using OpenTK;
+using OpenTK.Graphics;
+using Squirrel;
+
+namespace osu.Desktop.Overlays
+{
+ public class SquirrelUpdateManager : Component
+ {
+ private UpdateManager updateManager;
+ private NotificationOverlay notificationOverlay;
+
+ public void PrepareUpdate()
+ {
+ // Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
+ UpdateManager.RestartAppWhenExited().Wait();
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(NotificationOverlay notification, OsuGameBase game)
+ {
+ notificationOverlay = notification;
+
+ if (game.IsDeployedBuild)
+ Schedule(() => checkForUpdateAsync());
+ }
+
+ private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
+ {
+ //should we schedule a retry on completion of this check?
+ bool scheduleRetry = true;
+
+ try
+ {
+ if (updateManager == null) updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
+
+ var info = await updateManager.CheckForUpdate(!useDeltaPatching);
+ if (info.ReleasesToApply.Count == 0)
+ //no updates available. bail and retry later.
+ return;
+
+ if (notification == null)
+ {
+ notification = new UpdateProgressNotification(this) { State = ProgressNotificationState.Active };
+ Schedule(() => notificationOverlay.Post(notification));
+ }
+
+ notification.Progress = 0;
+ notification.Text = @"Downloading update...";
+
+ try
+ {
+ await updateManager.DownloadReleases(info.ReleasesToApply, p => notification.Progress = p / 100f);
+
+ notification.Progress = 0;
+ notification.Text = @"Installing update...";
+
+ await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f);
+
+ notification.State = ProgressNotificationState.Completed;
+ }
+ catch (Exception e)
+ {
+ if (useDeltaPatching)
+ {
+ Logger.Error(e, @"delta patching failed!");
+
+ //could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
+ //try again without deltas.
+ checkForUpdateAsync(false, notification);
+ scheduleRetry = false;
+ }
+ else
+ {
+ Logger.Error(e, @"update failed!");
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // we'll ignore this and retry later. can be triggered by no internet connection or thread abortion.
+ }
+ finally
+ {
+ if (scheduleRetry)
+ {
+ if (notification != null)
+ notification.State = ProgressNotificationState.Cancelled;
+
+ //check again in 30 minutes.
+ Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
+ }
+ }
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+ updateManager?.Dispose();
+ }
+
+ private class UpdateProgressNotification : ProgressNotification
+ {
+ private readonly SquirrelUpdateManager updateManager;
+ private OsuGame game;
+
+ public UpdateProgressNotification(SquirrelUpdateManager updateManager)
+ {
+ this.updateManager = updateManager;
+ }
+
+ protected override Notification CreateCompletionNotification()
+ {
+ return new ProgressCompletionNotification
+ {
+ Text = @"Update ready to install. Click to restart!",
+ Activated = () =>
+ {
+ updateManager.PrepareUpdate();
+ game.GracefullyExit();
+ return true;
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours, OsuGame game)
+ {
+ this.game = game;
+
+ IconContent.AddRange(new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
+ },
+ new SpriteIcon
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Icon = FontAwesome.fa_upload,
+ Colour = Color4.White,
+ Size = new Vector2(20),
+ }
+ });
+ }
+ }
+ }
+}
+#endif
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index b61603dcc5..b984c0bbba 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -1,142 +1,142 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Diagnostics;
-using osu.Framework.Allocation;
-using osu.Framework.Development;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.Textures;
-using osu.Game;
-using osu.Game.Configuration;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Notifications;
-using OpenTK;
-using OpenTK.Graphics;
-
-namespace osu.Desktop.Overlays
-{
- public class VersionManager : OverlayContainer
- {
- private OsuConfigManager config;
- private OsuGameBase game;
- private NotificationOverlay notificationOverlay;
-
- public override bool HandleKeyboardInput => false;
- public override bool HandleMouseInput => false;
-
- [BackgroundDependencyLoader]
- private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
- {
- notificationOverlay = notification;
- this.config = config;
- this.game = game;
-
- AutoSizeAxes = Axes.Both;
- Anchor = Anchor.BottomCentre;
- Origin = Anchor.BottomCentre;
-
- Alpha = 0;
-
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(5),
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Font = @"Exo2.0-Bold",
- Text = game.Name
- },
- new OsuSpriteText
- {
- Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
- Text = game.Version
- },
- }
- },
- new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- TextSize = 12,
- Colour = colours.Yellow,
- Font = @"Venera",
- Text = @"Development Build"
- },
- new Sprite
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Texture = textures.Get(@"Menu/dev-build-footer"),
- },
- }
- }
- };
-
-#if NET_FRAMEWORK
- Add(new SquirrelUpdateManager());
-#endif
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- var version = game.Version;
- var lastVersion = config.Get(OsuSetting.Version);
- if (game.IsDeployedBuild && version != lastVersion)
- {
- config.Set(OsuSetting.Version, version);
-
- // only show a notification if we've previously saved a version to the config file (ie. not the first run).
- if (!string.IsNullOrEmpty(lastVersion))
- notificationOverlay.Post(new UpdateCompleteNotification(version));
- }
- }
-
- private class UpdateCompleteNotification : SimpleNotification
- {
- public UpdateCompleteNotification(string version)
- {
- Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
- Icon = FontAwesome.fa_check_square;
- Activated = delegate
- {
- Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}");
- return true;
- };
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- IconBackgound.Colour = colours.BlueDark;
- }
- }
-
- protected override void PopIn()
- {
- this.FadeIn(1000);
- }
-
- protected override void PopOut()
- {
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Diagnostics;
+using osu.Framework.Allocation;
+using osu.Framework.Development;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Game;
+using osu.Game.Configuration;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Desktop.Overlays
+{
+ public class VersionManager : OverlayContainer
+ {
+ private OsuConfigManager config;
+ private OsuGameBase game;
+ private NotificationOverlay notificationOverlay;
+
+ public override bool HandleKeyboardInput => false;
+ public override bool HandleMouseInput => false;
+
+ [BackgroundDependencyLoader]
+ private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
+ {
+ notificationOverlay = notification;
+ this.config = config;
+ this.game = game;
+
+ AutoSizeAxes = Axes.Both;
+ Anchor = Anchor.BottomCentre;
+ Origin = Anchor.BottomCentre;
+
+ Alpha = 0;
+
+ Children = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(5),
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Font = @"Exo2.0-Bold",
+ Text = game.Name
+ },
+ new OsuSpriteText
+ {
+ Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
+ Text = game.Version
+ },
+ }
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ TextSize = 12,
+ Colour = colours.Yellow,
+ Font = @"Venera",
+ Text = @"Development Build"
+ },
+ new Sprite
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Texture = textures.Get(@"Menu/dev-build-footer"),
+ },
+ }
+ }
+ };
+
+#if NET_FRAMEWORK
+ Add(new SquirrelUpdateManager());
+#endif
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ var version = game.Version;
+ var lastVersion = config.Get(OsuSetting.Version);
+ if (game.IsDeployedBuild && version != lastVersion)
+ {
+ config.Set(OsuSetting.Version, version);
+
+ // only show a notification if we've previously saved a version to the config file (ie. not the first run).
+ if (!string.IsNullOrEmpty(lastVersion))
+ notificationOverlay.Post(new UpdateCompleteNotification(version));
+ }
+ }
+
+ private class UpdateCompleteNotification : SimpleNotification
+ {
+ public UpdateCompleteNotification(string version)
+ {
+ Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
+ Icon = FontAwesome.fa_check_square;
+ Activated = delegate
+ {
+ Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}");
+ return true;
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ IconBackgound.Colour = colours.BlueDark;
+ }
+ }
+
+ protected override void PopIn()
+ {
+ this.FadeIn(1000);
+ }
+
+ protected override void PopOut()
+ {
+ }
+ }
+}
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 7258610f90..61d2006315 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -1,66 +1,66 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.IO;
-using System.Linq;
-using osu.Framework;
-using osu.Framework.Platform;
-using osu.Game.IPC;
-#if NET_FRAMEWORK
-using System.Runtime;
-#endif
-
-namespace osu.Desktop
-{
- public static class Program
- {
- [STAThread]
- public static int Main(string[] args)
- {
- // required to initialise native SQLite libraries on some platforms.
-
- if (!RuntimeInfo.IsMono)
- useMulticoreJit();
-
- // Back up the cwd before DesktopGameHost changes it
- var cwd = Environment.CurrentDirectory;
-
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
- {
- if (!host.IsPrimaryInstance)
- {
- var importer = new ArchiveImportIPCChannel(host);
- // Restore the cwd so relative paths given at the command line work correctly
- Directory.SetCurrentDirectory(cwd);
- foreach (var file in args)
- {
- Console.WriteLine(@"Importing {0}", file);
- if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
- throw new TimeoutException(@"IPC took too long to send");
- }
- }
- else
- {
- switch (args.FirstOrDefault() ?? string.Empty)
- {
- default:
- host.Run(new OsuGameDesktop(args));
- break;
- }
- }
-
- return 0;
- }
- }
-
- private static void useMulticoreJit()
- {
-#if NET_FRAMEWORK
- var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
- ProfileOptimization.SetProfileRoot(directory.FullName);
- ProfileOptimization.StartProfile("Startup.Profile");
-#endif
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.IO;
+using System.Linq;
+using osu.Framework;
+using osu.Framework.Platform;
+using osu.Game.IPC;
+#if NET_FRAMEWORK
+using System.Runtime;
+#endif
+
+namespace osu.Desktop
+{
+ public static class Program
+ {
+ [STAThread]
+ public static int Main(string[] args)
+ {
+ // required to initialise native SQLite libraries on some platforms.
+
+ if (!RuntimeInfo.IsMono)
+ useMulticoreJit();
+
+ // Back up the cwd before DesktopGameHost changes it
+ var cwd = Environment.CurrentDirectory;
+
+ using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ {
+ if (!host.IsPrimaryInstance)
+ {
+ var importer = new ArchiveImportIPCChannel(host);
+ // Restore the cwd so relative paths given at the command line work correctly
+ Directory.SetCurrentDirectory(cwd);
+ foreach (var file in args)
+ {
+ Console.WriteLine(@"Importing {0}", file);
+ if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
+ throw new TimeoutException(@"IPC took too long to send");
+ }
+ }
+ else
+ {
+ switch (args.FirstOrDefault() ?? string.Empty)
+ {
+ default:
+ host.Run(new OsuGameDesktop(args));
+ break;
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ private static void useMulticoreJit()
+ {
+#if NET_FRAMEWORK
+ var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
+ ProfileOptimization.SetProfileRoot(directory.FullName);
+ ProfileOptimization.StartProfile("Startup.Profile");
+#endif
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
index e40510b71b..bd0cc209b6 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
@@ -1,67 +1,67 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using NUnit.Framework;
-using osu.Framework.MathUtils;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Objects;
-using osu.Game.Tests.Beatmaps;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- public class CatchBeatmapConversionTest : BeatmapConversionTest
- {
- protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
-
- [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")]
- public new void Test(string name)
- {
- base.Test(name);
- }
-
- protected override IEnumerable CreateConvertValue(HitObject hitObject)
- {
- if (hitObject is JuiceStream stream)
- {
- foreach (var nested in stream.NestedHitObjects)
- {
- yield return new ConvertValue
- {
- StartTime = nested.StartTime,
- Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH
- };
- }
- }
- else
- {
- yield return new ConvertValue
- {
- StartTime = hitObject.StartTime,
- Position = ((CatchHitObject)hitObject).X * CatchPlayfield.BASE_WIDTH
- };
- }
- }
-
- protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new CatchBeatmapConverter();
- }
-
- public struct ConvertValue : IEquatable
- {
- ///
- /// A sane value to account for osu!stable using ints everwhere.
- ///
- private const float conversion_lenience = 2;
-
- public double StartTime;
- public float Position;
-
- public bool Equals(ConvertValue other)
- => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
- && Precision.AlmostEquals(Position, other.Position, conversion_lenience);
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.MathUtils;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Tests.Beatmaps;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class CatchBeatmapConversionTest : BeatmapConversionTest
+ {
+ protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
+
+ [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")]
+ public new void Test(string name)
+ {
+ base.Test(name);
+ }
+
+ protected override IEnumerable CreateConvertValue(HitObject hitObject)
+ {
+ if (hitObject is JuiceStream stream)
+ {
+ foreach (var nested in stream.NestedHitObjects)
+ {
+ yield return new ConvertValue
+ {
+ StartTime = nested.StartTime,
+ Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH
+ };
+ }
+ }
+ else
+ {
+ yield return new ConvertValue
+ {
+ StartTime = hitObject.StartTime,
+ Position = ((CatchHitObject)hitObject).X * CatchPlayfield.BASE_WIDTH
+ };
+ }
+ }
+
+ protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new CatchBeatmapConverter();
+ }
+
+ public struct ConvertValue : IEquatable
+ {
+ ///
+ /// A sane value to account for osu!stable using ints everwhere.
+ ///
+ private const float conversion_lenience = 2;
+
+ public double StartTime;
+ public float Position;
+
+ public bool Equals(ConvertValue other)
+ => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
+ && Precision.AlmostEquals(Position, other.Position, conversion_lenience);
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
index 11a22c69f3..bce20520d3 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
@@ -1,62 +1,62 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Collections.Generic;
-using System.Linq;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Screens.Play;
-using osu.Game.Tests.Visual;
-using OpenTK;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- public class TestCaseAutoJuiceStream : TestCasePlayer
- {
- public TestCaseAutoJuiceStream()
- : base(new CatchRuleset())
- {
- }
-
- protected override Beatmap CreateBeatmap(Ruleset ruleset)
- {
- var beatmap = new Beatmap
- {
- BeatmapInfo = new BeatmapInfo
- {
- BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
- Ruleset = ruleset.RulesetInfo
- }
- };
-
- for (int i = 0; i < 100; i++)
- {
- float width = (i % 10 + 1) / 20f;
-
- beatmap.HitObjects.Add(new JuiceStream
- {
- X = 0.5f - width / 2,
- ControlPoints = new List
- {
- Vector2.Zero,
- new Vector2(width * CatchPlayfield.BASE_WIDTH, 0)
- },
- CurveType = CurveType.Linear,
- Distance = width * CatchPlayfield.BASE_WIDTH,
- StartTime = i * 2000,
- NewCombo = i % 8 == 0
- });
- }
-
- return beatmap;
- }
-
- protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
- {
- beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
- return base.CreatePlayer(beatmap, ruleset);
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
+using OpenTK;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class TestCaseAutoJuiceStream : TestCasePlayer
+ {
+ public TestCaseAutoJuiceStream()
+ : base(new CatchRuleset())
+ {
+ }
+
+ protected override Beatmap CreateBeatmap(Ruleset ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
+ Ruleset = ruleset.RulesetInfo
+ }
+ };
+
+ for (int i = 0; i < 100; i++)
+ {
+ float width = (i % 10 + 1) / 20f;
+
+ beatmap.HitObjects.Add(new JuiceStream
+ {
+ X = 0.5f - width / 2,
+ ControlPoints = new List
+ {
+ Vector2.Zero,
+ new Vector2(width * CatchPlayfield.BASE_WIDTH, 0)
+ },
+ CurveType = CurveType.Linear,
+ Distance = width * CatchPlayfield.BASE_WIDTH,
+ StartTime = i * 2000,
+ NewCombo = i % 8 == 0
+ });
+ }
+
+ return beatmap;
+ }
+
+ protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
+ {
+ beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
+ return base.CreatePlayer(beatmap, ruleset);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
index ec9dd15673..d13a6bb860 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
@@ -1,47 +1,47 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using NUnit.Framework;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
-using osu.Game.Rulesets.Catch.UI;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(BananaShower),
- typeof(DrawableBananaShower),
-
- typeof(CatchRuleset),
- typeof(CatchRulesetContainer),
- };
-
- public TestCaseBananaShower()
- : base(new CatchRuleset())
- {
- }
-
- protected override Beatmap CreateBeatmap(Ruleset ruleset)
- {
- var beatmap = new Beatmap
- {
- BeatmapInfo = new BeatmapInfo
- {
- BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
- Ruleset = ruleset.RulesetInfo
- }
- };
-
- beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
-
- return beatmap;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.UI;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(BananaShower),
+ typeof(DrawableBananaShower),
+
+ typeof(CatchRuleset),
+ typeof(CatchRulesetContainer),
+ };
+
+ public TestCaseBananaShower()
+ : base(new CatchRuleset())
+ {
+ }
+
+ protected override Beatmap CreateBeatmap(Ruleset ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
+ Ruleset = ruleset.RulesetInfo
+ }
+ };
+
+ beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
+
+ return beatmap;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
index efebfa9739..a2c886f1f3 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
@@ -1,15 +1,15 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
- {
- public TestCaseCatchPlayer() : base(new CatchRuleset())
- {
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using NUnit.Framework;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
+ {
+ public TestCaseCatchPlayer() : base(new CatchRuleset())
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
index 8e5843f40a..2b58fcc93c 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
@@ -1,36 +1,36 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
- {
- public TestCaseCatchStacker()
- : base(new CatchRuleset())
- {
- }
-
- protected override Beatmap CreateBeatmap(Ruleset ruleset)
- {
- var beatmap = new Beatmap
- {
- BeatmapInfo = new BeatmapInfo
- {
- BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
- Ruleset = ruleset.RulesetInfo
- }
- };
-
-
- for (int i = 0; i < 512; i++)
- beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
-
- return beatmap;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
+ {
+ public TestCaseCatchStacker()
+ : base(new CatchRuleset())
+ {
+ }
+
+ protected override Beatmap CreateBeatmap(Ruleset ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
+ Ruleset = ruleset.RulesetInfo
+ }
+ };
+
+
+ for (int i = 0; i < 512; i++)
+ beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
+
+ return beatmap;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
index 0329921c92..f239290ed4 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
@@ -1,61 +1,61 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using NUnit.Framework;
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Tests.Visual;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseCatcherArea : OsuTestCase
- {
- private RulesetInfo catchRuleset;
- private TestCatcherArea catcherArea;
-
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(CatcherArea),
- };
-
- public TestCaseCatcherArea()
- {
- AddSliderStep("CircleSize", 0, 8, 5, createCatcher);
- AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t));
- }
-
- private void createCatcher(float size)
- {
- Child = new CatchInputManager(catchRuleset)
- {
- RelativeSizeAxes = Axes.Both,
- Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.BottomLeft
- },
- };
- }
-
- [BackgroundDependencyLoader]
- private void load(RulesetStore rulesets)
- {
- catchRuleset = rulesets.GetRuleset(2);
- }
-
- private class TestCatcherArea : CatcherArea
- {
- public TestCatcherArea(BeatmapDifficulty beatmapDifficulty)
- : base(beatmapDifficulty)
- {
- }
-
- public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCaseCatcherArea : OsuTestCase
+ {
+ private RulesetInfo catchRuleset;
+ private TestCatcherArea catcherArea;
+
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CatcherArea),
+ };
+
+ public TestCaseCatcherArea()
+ {
+ AddSliderStep("CircleSize", 0, 8, 5, createCatcher);
+ AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t));
+ }
+
+ private void createCatcher(float size)
+ {
+ Child = new CatchInputManager(catchRuleset)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.BottomLeft
+ },
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(RulesetStore rulesets)
+ {
+ catchRuleset = rulesets.GetRuleset(2);
+ }
+
+ private class TestCatcherArea : CatcherArea
+ {
+ public TestCatcherArea(BeatmapDifficulty beatmapDifficulty)
+ : base(beatmapDifficulty)
+ {
+ }
+
+ public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
index 595ca6cb24..275752523d 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
@@ -1,74 +1,74 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using NUnit.Framework;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
-using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
-using osu.Game.Tests.Visual;
-using OpenTK;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseFruitObjects : OsuTestCase
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(CatchHitObject),
- typeof(Fruit),
- typeof(Droplet),
- typeof(DrawableCatchHitObject),
- typeof(DrawableFruit),
- typeof(DrawableDroplet),
- typeof(Pulp),
- };
-
- public TestCaseFruitObjects()
- {
- Add(new GridContainer
- {
- RelativeSizeAxes = Axes.Both,
- Content = new[]
- {
- new Drawable[]
- {
- createDrawable(0),
- createDrawable(1),
- createDrawable(2),
- },
- new Drawable[]
- {
- createDrawable(3),
- createDrawable(4),
- createDrawable(5),
- },
- }
- });
- }
-
- private DrawableFruit createDrawable(int index)
- {
- var fruit = new Fruit
- {
- StartTime = 1000000000000,
- IndexInBeatmap = index,
- Scale = 1.5f,
- };
-
- return new DrawableFruit(fruit)
- {
- Anchor = Anchor.Centre,
- RelativePositionAxes = Axes.Both,
- Position = Vector2.Zero,
- Alpha = 1,
- LifetimeStart = double.NegativeInfinity,
- LifetimeEnd = double.PositiveInfinity,
- };
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
+using osu.Game.Tests.Visual;
+using OpenTK;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCaseFruitObjects : OsuTestCase
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CatchHitObject),
+ typeof(Fruit),
+ typeof(Droplet),
+ typeof(DrawableCatchHitObject),
+ typeof(DrawableFruit),
+ typeof(DrawableDroplet),
+ typeof(Pulp),
+ };
+
+ public TestCaseFruitObjects()
+ {
+ Add(new GridContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ createDrawable(0),
+ createDrawable(1),
+ createDrawable(2),
+ },
+ new Drawable[]
+ {
+ createDrawable(3),
+ createDrawable(4),
+ createDrawable(5),
+ },
+ }
+ });
+ }
+
+ private DrawableFruit createDrawable(int index)
+ {
+ var fruit = new Fruit
+ {
+ StartTime = 1000000000000,
+ IndexInBeatmap = index,
+ Scale = 1.5f,
+ };
+
+ return new DrawableFruit(fruit)
+ {
+ Anchor = Anchor.Centre,
+ RelativePositionAxes = Axes.Both,
+ Position = Vector2.Zero,
+ Alpha = 1,
+ LifetimeStart = double.NegativeInfinity,
+ LifetimeEnd = double.PositiveInfinity,
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperdash.cs
index 7564adea8c..e7f936ca2a 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperdash.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperdash.cs
@@ -1,30 +1,30 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
- {
- public TestCaseHyperdash()
- : base(new CatchRuleset())
- {
- }
-
- protected override Beatmap CreateBeatmap(Ruleset ruleset)
- {
- var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
-
-
- for (int i = 0; i < 512; i++)
- if (i % 5 < 3)
- beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 });
-
- return beatmap;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
+ {
+ public TestCaseHyperdash()
+ : base(new CatchRuleset())
+ {
+ }
+
+ protected override Beatmap CreateBeatmap(Ruleset ruleset)
+ {
+ var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
+
+
+ for (int i = 0; i < 512; i++)
+ if (i % 5 < 3)
+ beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 });
+
+ return beatmap;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs
index 2be6dd005d..9512cf2061 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs
@@ -1,16 +1,16 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
- {
- public TestCasePerformancePoints()
- : base(new CatchRuleset())
- {
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using NUnit.Framework;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
+ {
+ public TestCasePerformancePoints()
+ : base(new CatchRuleset())
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 51c6d18f1f..7a4c7b3f1c 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -1,10 +1,10 @@
-
-
-
- WinExe
- netcoreapp2.0;net461
-
-
-
-
+
+
+
+ WinExe
+ netcoreapp2.0;net461
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
index 01aa7abb9f..34e5f425fd 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
@@ -1,68 +1,68 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using System.Collections.Generic;
-using System;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Objects;
-
-namespace osu.Game.Rulesets.Catch.Beatmaps
-{
- public class CatchBeatmapConverter : BeatmapConverter
- {
- protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
-
- protected override IEnumerable ConvertHitObject(HitObject obj, Beatmap beatmap)
- {
- var curveData = obj as IHasCurve;
- var positionData = obj as IHasXPosition;
- var comboData = obj as IHasCombo;
- var endTime = obj as IHasEndTime;
-
- if (positionData == null)
- yield break;
-
- if (curveData != null)
- {
- yield return new JuiceStream
- {
- StartTime = obj.StartTime,
- Samples = obj.Samples,
- ControlPoints = curveData.ControlPoints,
- CurveType = curveData.CurveType,
- Distance = curveData.Distance,
- RepeatSamples = curveData.RepeatSamples,
- RepeatCount = curveData.RepeatCount,
- X = positionData.X / CatchPlayfield.BASE_WIDTH,
- NewCombo = comboData?.NewCombo ?? false
- };
-
- yield break;
- }
-
- if (endTime != null)
- {
- yield return new BananaShower
- {
- StartTime = obj.StartTime,
- Samples = obj.Samples,
- Duration = endTime.Duration,
- NewCombo = comboData?.NewCombo ?? false
- };
-
- yield break;
- }
-
- yield return new Fruit
- {
- StartTime = obj.StartTime,
- Samples = obj.Samples,
- NewCombo = comboData?.NewCombo ?? false,
- X = positionData.X / CatchPlayfield.BASE_WIDTH
- };
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using System.Collections.Generic;
+using System;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Rulesets.Catch.Beatmaps
+{
+ public class CatchBeatmapConverter : BeatmapConverter
+ {
+ protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
+
+ protected override IEnumerable ConvertHitObject(HitObject obj, Beatmap beatmap)
+ {
+ var curveData = obj as IHasCurve;
+ var positionData = obj as IHasXPosition;
+ var comboData = obj as IHasCombo;
+ var endTime = obj as IHasEndTime;
+
+ if (positionData == null)
+ yield break;
+
+ if (curveData != null)
+ {
+ yield return new JuiceStream
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
+ ControlPoints = curveData.ControlPoints,
+ CurveType = curveData.CurveType,
+ Distance = curveData.Distance,
+ RepeatSamples = curveData.RepeatSamples,
+ RepeatCount = curveData.RepeatCount,
+ X = positionData.X / CatchPlayfield.BASE_WIDTH,
+ NewCombo = comboData?.NewCombo ?? false
+ };
+
+ yield break;
+ }
+
+ if (endTime != null)
+ {
+ yield return new BananaShower
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
+ Duration = endTime.Duration,
+ NewCombo = comboData?.NewCombo ?? false
+ };
+
+ yield break;
+ }
+
+ yield return new Fruit
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
+ NewCombo = comboData?.NewCombo ?? false,
+ X = positionData.X / CatchPlayfield.BASE_WIDTH
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index 1bebe9dae0..dfd10e0df7 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -1,72 +1,72 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Objects.Types;
-using OpenTK;
-
-namespace osu.Game.Rulesets.Catch.Beatmaps
-{
- public class CatchBeatmapProcessor : BeatmapProcessor
- {
- public override void PostProcess(Beatmap beatmap)
- {
- initialiseHyperDash(beatmap.HitObjects);
-
- base.PostProcess(beatmap);
-
- int index = 0;
- foreach (var obj in beatmap.HitObjects)
- obj.IndexInBeatmap = index++;
- }
-
- private void initialiseHyperDash(List objects)
- {
- // todo: add difficulty adjust.
- double halfCatcherWidth = CatcherArea.CATCHER_SIZE * (objects.FirstOrDefault()?.Scale ?? 1) / CatchPlayfield.BASE_WIDTH / 2;
-
- int lastDirection = 0;
- double lastExcess = halfCatcherWidth;
-
- int objCount = objects.Count;
-
- for (int i = 0; i < objCount - 1; i++)
- {
- CatchHitObject currentObject = objects[i];
-
- // not needed?
- // if (currentObject is TinyDroplet) continue;
-
- CatchHitObject nextObject = objects[i + 1];
-
- // while (nextObject is TinyDroplet)
- // {
- // if (++i == objCount - 1) break;
- // nextObject = objects[i + 1];
- // }
-
- int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
- double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4;
- double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
-
- if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext)
- {
- currentObject.HyperDashTarget = nextObject;
- lastExcess = halfCatcherWidth;
- }
- else
- {
- //currentObject.DistanceToHyperDash = timeToNext - distanceToNext;
- lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, halfCatcherWidth);
- }
-
- lastDirection = thisDirection;
- }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects.Types;
+using OpenTK;
+
+namespace osu.Game.Rulesets.Catch.Beatmaps
+{
+ public class CatchBeatmapProcessor : BeatmapProcessor
+ {
+ public override void PostProcess(Beatmap beatmap)
+ {
+ initialiseHyperDash(beatmap.HitObjects);
+
+ base.PostProcess(beatmap);
+
+ int index = 0;
+ foreach (var obj in beatmap.HitObjects)
+ obj.IndexInBeatmap = index++;
+ }
+
+ private void initialiseHyperDash(List objects)
+ {
+ // todo: add difficulty adjust.
+ double halfCatcherWidth = CatcherArea.CATCHER_SIZE * (objects.FirstOrDefault()?.Scale ?? 1) / CatchPlayfield.BASE_WIDTH / 2;
+
+ int lastDirection = 0;
+ double lastExcess = halfCatcherWidth;
+
+ int objCount = objects.Count;
+
+ for (int i = 0; i < objCount - 1; i++)
+ {
+ CatchHitObject currentObject = objects[i];
+
+ // not needed?
+ // if (currentObject is TinyDroplet) continue;
+
+ CatchHitObject nextObject = objects[i + 1];
+
+ // while (nextObject is TinyDroplet)
+ // {
+ // if (++i == objCount - 1) break;
+ // nextObject = objects[i + 1];
+ // }
+
+ int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
+ double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4;
+ double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
+
+ if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext)
+ {
+ currentObject.HyperDashTarget = nextObject;
+ lastExcess = halfCatcherWidth;
+ }
+ else
+ {
+ //currentObject.DistanceToHyperDash = timeToNext - distanceToNext;
+ lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, halfCatcherWidth);
+ }
+
+ lastDirection = thisDirection;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs
index 917a076426..876b394da0 100644
--- a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs
@@ -1,21 +1,21 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using System.Collections.Generic;
-
-namespace osu.Game.Rulesets.Catch
-{
- public class CatchDifficultyCalculator : DifficultyCalculator
- {
- public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
- {
- }
-
- public override double Calculate(Dictionary categoryDifficulty = null) => 0;
-
- protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using System.Collections.Generic;
+
+namespace osu.Game.Rulesets.Catch
+{
+ public class CatchDifficultyCalculator : DifficultyCalculator
+ {
+ public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
+ {
+ }
+
+ public override double Calculate(Dictionary categoryDifficulty = null) => 0;
+
+ protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs
index fa8958687c..4f976bb7b2 100644
--- a/osu.Game.Rulesets.Catch/CatchInputManager.cs
+++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs
@@ -1,27 +1,27 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.ComponentModel;
-using osu.Framework.Input.Bindings;
-using osu.Game.Rulesets.UI;
-
-namespace osu.Game.Rulesets.Catch
-{
- public class CatchInputManager : RulesetInputManager
- {
- public CatchInputManager(RulesetInfo ruleset)
- : base(ruleset, 0, SimultaneousBindingMode.Unique)
- {
- }
- }
-
- public enum CatchAction
- {
- [Description("Move left")]
- MoveLeft,
- [Description("Move right")]
- MoveRight,
- [Description("Engage dash")]
- Dash,
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.ComponentModel;
+using osu.Framework.Input.Bindings;
+using osu.Game.Rulesets.UI;
+
+namespace osu.Game.Rulesets.Catch
+{
+ public class CatchInputManager : RulesetInputManager
+ {
+ public CatchInputManager(RulesetInfo ruleset)
+ : base(ruleset, 0, SimultaneousBindingMode.Unique)
+ {
+ }
+ }
+
+ public enum CatchAction
+ {
+ [Description("Move left")]
+ MoveLeft,
+ [Description("Move right")]
+ MoveRight,
+ [Description("Engage dash")]
+ Dash,
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index 4dbe65b3ce..cfe0fc5cec 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -1,113 +1,152 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Graphics;
-using osu.Game.Rulesets.Catch.Mods;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
-using System.Collections.Generic;
-using osu.Framework.Graphics;
-using osu.Framework.Input.Bindings;
-using osu.Game.Rulesets.Catch.Replays;
-using osu.Game.Rulesets.Replays.Types;
-
-namespace osu.Game.Rulesets.Catch
-{
- public class CatchRuleset : Ruleset
- {
- public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchRulesetContainer(this, beatmap, isForCurrentRuleset);
-
- public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[]
- {
- new KeyBinding(InputKey.Z, CatchAction.MoveLeft),
- new KeyBinding(InputKey.Left, CatchAction.MoveLeft),
- new KeyBinding(InputKey.X, CatchAction.MoveRight),
- new KeyBinding(InputKey.Right, CatchAction.MoveRight),
- new KeyBinding(InputKey.Shift, CatchAction.Dash),
- new KeyBinding(InputKey.Shift, CatchAction.Dash),
- };
-
- public override IEnumerable GetModsFor(ModType type)
- {
- switch (type)
- {
- case ModType.DifficultyReduction:
- return new Mod[]
- {
- new CatchModEasy(),
- new CatchModNoFail(),
- new MultiMod
- {
- Mods = new Mod[]
- {
- new CatchModHalfTime(),
- new CatchModDaycore(),
- },
- },
- };
-
- case ModType.DifficultyIncrease:
- return new Mod[]
- {
- new CatchModHardRock(),
- new MultiMod
- {
- Mods = new Mod[]
- {
- new CatchModSuddenDeath(),
- new CatchModPerfect(),
- },
- },
- new MultiMod
- {
- Mods = new Mod[]
- {
- new CatchModDoubleTime(),
- new CatchModNightcore(),
- },
- },
- new CatchModHidden(),
- new CatchModFlashlight(),
- };
-
- case ModType.Special:
- return new Mod[]
- {
- new CatchModRelax(),
- null,
- null,
- new MultiMod
- {
- Mods = new Mod[]
- {
- new CatchModAutoplay(),
- new ModCinema(),
- },
- },
- };
-
- default:
- return new Mod[] { };
- }
- }
-
- public override string Description => "osu!catch";
-
- public override string ShortName => "fruits";
-
- public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
-
- public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
-
- public override int? LegacyID => 2;
-
- public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
-
- public CatchRuleset(RulesetInfo rulesetInfo = null)
- : base(rulesetInfo)
- {
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Catch.Mods;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.UI;
+using System.Collections.Generic;
+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
+{
+ public class CatchRuleset : Ruleset
+ {
+ public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchRulesetContainer(this, beatmap, isForCurrentRuleset);
+
+ public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[]
+ {
+ new KeyBinding(InputKey.Z, CatchAction.MoveLeft),
+ new KeyBinding(InputKey.Left, CatchAction.MoveLeft),
+ new KeyBinding(InputKey.X, CatchAction.MoveRight),
+ new KeyBinding(InputKey.Right, CatchAction.MoveRight),
+ new KeyBinding(InputKey.Shift, CatchAction.Dash),
+ new KeyBinding(InputKey.Shift, CatchAction.Dash),
+ };
+
+ public override IEnumerable 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 GetModsFor(ModType type)
+ {
+ switch (type)
+ {
+ case ModType.DifficultyReduction:
+ return new Mod[]
+ {
+ new CatchModEasy(),
+ new CatchModNoFail(),
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new CatchModHalfTime(),
+ new CatchModDaycore(),
+ },
+ },
+ };
+
+ case ModType.DifficultyIncrease:
+ return new Mod[]
+ {
+ new CatchModHardRock(),
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new CatchModSuddenDeath(),
+ new CatchModPerfect(),
+ },
+ },
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new CatchModDoubleTime(),
+ new CatchModNightcore(),
+ },
+ },
+ new CatchModHidden(),
+ new CatchModFlashlight(),
+ };
+
+ case ModType.Special:
+ return new Mod[]
+ {
+ new CatchModRelax(),
+ null,
+ null,
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new CatchModAutoplay(),
+ new ModCinema(),
+ },
+ },
+ };
+
+ default:
+ return new Mod[] { };
+ }
+ }
+
+ public override string Description => "osu!catch";
+
+ public override string ShortName => "fruits";
+
+ public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
+
+ public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
+
+ public override int? LegacyID => 2;
+
+ public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
+
+ public CatchRuleset(RulesetInfo rulesetInfo = null)
+ : base(rulesetInfo)
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
index d0e22bb04e..bb2786f14f 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Judgements;
-
-namespace osu.Game.Rulesets.Catch.Judgements
-{
- public class CatchJudgement : Judgement
- {
- // todo: wangs
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Judgements;
+
+namespace osu.Game.Rulesets.Catch.Judgements
+{
+ public class CatchJudgement : Judgement
+ {
+ // todo: wangs
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
index 8ff08ab825..5ed563614a 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
@@ -1,24 +1,24 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Replays;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Users;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModAutoplay : ModAutoplay
- {
- protected override Score CreateReplayScore(Beatmap beatmap)
- {
- return new Score
- {
- User = new User { Username = "osu!salad!" },
- Replay = new CatchAutoGenerator(beatmap).Generate(),
- };
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.Replays;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Users;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModAutoplay : ModAutoplay
+ {
+ protected override Score CreateReplayScore(Beatmap beatmap)
+ {
+ return new Score
+ {
+ User = new User { Username = "osu!salad!" },
+ Replay = new CatchAutoGenerator(beatmap).Generate(),
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
index 8eb8fd8435..6d4caef8d2 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModDaycore : ModDaycore
- {
- public override double ScoreMultiplier => 0.3;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModDaycore : ModDaycore
+ {
+ public override double ScoreMultiplier => 0.3;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
index 7a7eeed719..dcf417c405 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModDoubleTime : ModDoubleTime
- {
- public override double ScoreMultiplier => 1.06;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModDoubleTime : ModDoubleTime
+ {
+ public override double ScoreMultiplier => 1.06;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
index 07bc8b825a..d20a2ec727 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModEasy : ModEasy
- {
- public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModEasy : ModEasy
+ {
+ public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
index 424f14ad02..21e09f991c 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModFlashlight : ModFlashlight
- {
- public override double ScoreMultiplier => 1.12;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModFlashlight : ModFlashlight
+ {
+ public override double ScoreMultiplier => 1.12;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
index 947990cce5..4e48de454f 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModHalfTime : ModHalfTime
- {
- public override double ScoreMultiplier => 0.3;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModHalfTime : ModHalfTime
+ {
+ public override double ScoreMultiplier => 0.3;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
index 1656a5c40b..df7578799f 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
@@ -1,88 +1,88 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// 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, IApplicableToHitObject
- {
- 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;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// 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, IApplicableToHitObject
+ {
+ 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;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
index 14291f744c..f2716f351e 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
@@ -1,13 +1,13 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModHidden : ModHidden
- {
- public override string Description => @"Play with fading fruits.";
- public override double ScoreMultiplier => 1.06;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModHidden : ModHidden
+ {
+ public override string Description => @"Play with fading fruits.";
+ public override double ScoreMultiplier => 1.06;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
index b53cac0d7c..687db172cf 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModNightcore : ModNightcore
- {
- public override double ScoreMultiplier => 1.06;
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModNightcore : ModNightcore
+ {
+ public override double ScoreMultiplier => 1.06;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
index afb2d83720..914419438d 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
@@ -1,11 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModNoFail : ModNoFail
- {
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModNoFail : ModNoFail
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
index bc0dd10f6c..de00ff31ce 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
@@ -1,11 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModPerfect : ModPerfect
- {
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModPerfect : ModPerfect
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
index de0b6bc614..8bf9f32572 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
@@ -1,12 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModRelax : ModRelax
- {
- public override string Description => @"Use the mouse to control the catcher.";
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModRelax : ModRelax
+ {
+ public override string Description => @"Use the mouse to control the catcher.";
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs b/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
index 1e778e5305..71461cfc40 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
@@ -1,11 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Mods;
-
-namespace osu.Game.Rulesets.Catch.Mods
-{
- public class CatchModSuddenDeath : ModSuddenDeath
- {
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModSuddenDeath : ModSuddenDeath
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 487345019b..a6aba42f03 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -1,48 +1,48 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.MathUtils;
-using osu.Game.Rulesets.Objects.Types;
-
-namespace osu.Game.Rulesets.Catch.Objects
-{
- public class BananaShower : CatchHitObject, IHasEndTime
- {
- public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
-
- public override bool LastInCombo => true;
-
- protected override void CreateNestedHitObjects()
- {
- base.CreateNestedHitObjects();
- createBananas();
- }
-
- private void createBananas()
- {
- double spacing = Duration;
- while (spacing > 100)
- spacing /= 2;
-
- if (spacing <= 0)
- return;
-
- for (double i = StartTime; i <= EndTime; i += spacing)
- AddNested(new Banana
- {
- Samples = Samples,
- StartTime = i,
- X = RNG.NextSingle()
- });
- }
-
- public double EndTime => StartTime + Duration;
-
- public double Duration { get; set; }
-
- public class Banana : Fruit
- {
- public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.MathUtils;
+using osu.Game.Rulesets.Objects.Types;
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public class BananaShower : CatchHitObject, IHasEndTime
+ {
+ public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
+
+ public override bool LastInCombo => true;
+
+ protected override void CreateNestedHitObjects()
+ {
+ base.CreateNestedHitObjects();
+ createBananas();
+ }
+
+ private void createBananas()
+ {
+ double spacing = Duration;
+ while (spacing > 100)
+ spacing /= 2;
+
+ if (spacing <= 0)
+ return;
+
+ for (double i = StartTime; i <= EndTime; i += spacing)
+ AddNested(new Banana
+ {
+ Samples = Samples,
+ StartTime = i,
+ X = RNG.NextSingle()
+ });
+ }
+
+ public double EndTime => StartTime + Duration;
+
+ public double Duration { get; set; }
+
+ public class Banana : Fruit
+ {
+ public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index 1a0ccc9b1e..95ffd41518 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -1,60 +1,60 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Rulesets.Objects;
-using osu.Game.Rulesets.Objects.Types;
-
-namespace osu.Game.Rulesets.Catch.Objects
-{
- public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboInformation
- {
- public const double OBJECT_RADIUS = 44;
-
- public float X { get; set; }
-
- public int IndexInBeatmap { get; set; }
-
- public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
-
- public virtual bool NewCombo { get; set; }
-
- public int IndexInCurrentCombo { get; set; }
-
- public int ComboIndex { get; set; }
-
- ///
- /// The next fruit starts a new combo. Used for explodey.
- ///
- public virtual bool LastInCombo { get; set; }
-
- public float Scale { get; set; } = 1;
-
- ///
- /// Whether this fruit can initiate a hyperdash.
- ///
- public bool HyperDash => HyperDashTarget != null;
-
- ///
- /// The target fruit if we are to initiate a hyperdash.
- ///
- public CatchHitObject HyperDashTarget;
-
- protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
- {
- base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
-
- Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
- }
- }
-
- public enum FruitVisualRepresentation
- {
- Pear,
- Grape,
- Raspberry,
- Pineapple,
- Banana // banananananannaanana
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboInformation
+ {
+ public const double OBJECT_RADIUS = 44;
+
+ public float X { get; set; }
+
+ public int IndexInBeatmap { get; set; }
+
+ public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
+
+ public virtual bool NewCombo { get; set; }
+
+ public int IndexInCurrentCombo { get; set; }
+
+ public int ComboIndex { get; set; }
+
+ ///
+ /// The next fruit starts a new combo. Used for explodey.
+ ///
+ public virtual bool LastInCombo { get; set; }
+
+ public float Scale { get; set; } = 1;
+
+ ///
+ /// Whether this fruit can initiate a hyperdash.
+ ///
+ public bool HyperDash => HyperDashTarget != null;
+
+ ///
+ /// The target fruit if we are to initiate a hyperdash.
+ ///
+ public CatchHitObject HyperDashTarget;
+
+ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
+ {
+ base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
+
+ Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
+ }
+ }
+
+ public enum FruitVisualRepresentation
+ {
+ Pear,
+ Grape,
+ Raspberry,
+ Pineapple,
+ Banana // banananananannaanana
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
index 3c6ec0703d..739cc6a59b 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
@@ -1,44 +1,44 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Linq;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Scoring;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableBananaShower : DrawableCatchHitObject
- {
- private readonly Container bananaContainer;
-
- public DrawableBananaShower(BananaShower s, Func> getVisualRepresentation = null)
- : base(s)
- {
- RelativeSizeAxes = Axes.X;
- Origin = Anchor.BottomLeft;
- X = 0;
-
- InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
-
- foreach (var b in s.NestedHitObjects.Cast())
- AddNested(getVisualRepresentation?.Invoke(b));
- }
-
- protected override void CheckForJudgements(bool userTriggered, double timeOffset)
- {
- if (timeOffset >= 0)
- AddJudgement(new Judgement { Result = NestedHitObjects.Cast().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
- }
-
- protected override void AddNested(DrawableHitObject h)
- {
- ((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
- bananaContainer.Add(h);
- base.AddNested(h);
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Linq;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+ public class DrawableBananaShower : DrawableCatchHitObject
+ {
+ private readonly Container bananaContainer;
+
+ public DrawableBananaShower(BananaShower s, Func> getVisualRepresentation = null)
+ : base(s)
+ {
+ RelativeSizeAxes = Axes.X;
+ Origin = Anchor.BottomLeft;
+ X = 0;
+
+ InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
+
+ foreach (var b in s.NestedHitObjects.Cast())
+ AddNested(getVisualRepresentation?.Invoke(b));
+ }
+
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
+ {
+ if (timeOffset >= 0)
+ AddJudgement(new Judgement { Result = NestedHitObjects.Cast().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
+ }
+
+ protected override void AddNested(DrawableHitObject h)
+ {
+ ((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
+ bananaContainer.Add(h);
+ base.AddNested(h);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index 582946ff00..3dbda708e5 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -1,93 +1,93 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using osu.Framework.Graphics;
-using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Objects.Types;
-using OpenTK;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Skinning;
-using OpenTK.Graphics;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public abstract class PalpableCatchHitObject : DrawableCatchHitObject
- where TObject : CatchHitObject
- {
- public override bool CanBePlated => true;
-
- protected PalpableCatchHitObject(TObject hitObject)
- : base(hitObject)
- {
- Scale = new Vector2(HitObject.Scale);
- }
- }
-
- public abstract class DrawableCatchHitObject : DrawableCatchHitObject
- where TObject : CatchHitObject
- {
- public new TObject HitObject;
-
- protected DrawableCatchHitObject(TObject hitObject)
- : base(hitObject)
- {
- HitObject = hitObject;
- Anchor = Anchor.BottomLeft;
- }
- }
-
- public abstract class DrawableCatchHitObject : DrawableHitObject
- {
- public virtual bool CanBePlated => false;
-
- protected DrawableCatchHitObject(CatchHitObject hitObject)
- : base(hitObject)
- {
- RelativePositionAxes = Axes.X;
- X = hitObject.X;
- }
-
- public Func CheckPosition;
-
- protected override void CheckForJudgements(bool userTriggered, double timeOffset)
- {
- if (CheckPosition == null) return;
-
- if (timeOffset >= 0)
- AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
- }
-
- protected override void SkinChanged(ISkinSource skin, bool allowFallback)
- {
- base.SkinChanged(skin, allowFallback);
-
- if (HitObject is IHasComboInformation combo)
- AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
- }
-
- private const float preempt = 1000;
-
- protected override void UpdateState(ArmedState state)
- {
- using (BeginAbsoluteSequence(HitObject.StartTime - preempt))
- this.FadeIn(200);
-
- var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
-
- using (BeginAbsoluteSequence(endTime, true))
- {
- switch (state)
- {
- case ArmedState.Miss:
- this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire();
- break;
- case ArmedState.Hit:
- this.FadeOut().Expire();
- break;
- }
- }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Types;
+using OpenTK;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Skinning;
+using OpenTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+ public abstract class PalpableCatchHitObject : DrawableCatchHitObject
+ where TObject : CatchHitObject
+ {
+ public override bool CanBePlated => true;
+
+ protected PalpableCatchHitObject(TObject hitObject)
+ : base(hitObject)
+ {
+ Scale = new Vector2(HitObject.Scale);
+ }
+ }
+
+ public abstract class DrawableCatchHitObject : DrawableCatchHitObject
+ where TObject : CatchHitObject
+ {
+ public new TObject HitObject;
+
+ protected DrawableCatchHitObject(TObject hitObject)
+ : base(hitObject)
+ {
+ HitObject = hitObject;
+ Anchor = Anchor.BottomLeft;
+ }
+ }
+
+ public abstract class DrawableCatchHitObject : DrawableHitObject
+ {
+ public virtual bool CanBePlated => false;
+
+ protected DrawableCatchHitObject(CatchHitObject hitObject)
+ : base(hitObject)
+ {
+ RelativePositionAxes = Axes.X;
+ X = hitObject.X;
+ }
+
+ public Func CheckPosition;
+
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
+ {
+ if (CheckPosition == null) return;
+
+ if (timeOffset >= 0)
+ AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
+ }
+
+ protected override void SkinChanged(ISkinSource skin, bool allowFallback)
+ {
+ base.SkinChanged(skin, allowFallback);
+
+ if (HitObject is IHasComboInformation combo)
+ AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
+ }
+
+ private const float preempt = 1000;
+
+ protected override void UpdateState(ArmedState state)
+ {
+ using (BeginAbsoluteSequence(HitObject.StartTime - preempt))
+ this.FadeIn(200);
+
+ var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
+
+ using (BeginAbsoluteSequence(endTime, true))
+ {
+ switch (state)
+ {
+ case ArmedState.Miss:
+ this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire();
+ break;
+ case ArmedState.Hit:
+ this.FadeOut().Expire();
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
index 719cf0a110..a19d67ebbe 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
@@ -1,43 +1,43 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
-using OpenTK;
-using OpenTK.Graphics;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableDroplet : PalpableCatchHitObject
- {
- private Pulp pulp;
-
- public DrawableDroplet(Droplet h)
- : base(h)
- {
- Origin = Anchor.Centre;
- Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4;
- Masking = false;
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- InternalChild = pulp = new Pulp
- {
- Size = Size
- };
- }
-
- public override Color4 AccentColour
- {
- get { return base.AccentColour; }
- set
- {
- base.AccentColour = value;
- pulp.AccentColour = AccentColour;
- }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+ public class DrawableDroplet : PalpableCatchHitObject
+ {
+ private Pulp pulp;
+
+ public DrawableDroplet(Droplet h)
+ : base(h)
+ {
+ Origin = Anchor.Centre;
+ Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4;
+ Masking = false;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChild = pulp = new Pulp
+ {
+ Size = Size
+ };
+ }
+
+ public override Color4 AccentColour
+ {
+ get { return base.AccentColour; }
+ set
+ {
+ base.AccentColour = value;
+ pulp.AccentColour = AccentColour;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index 03c2444d8c..41792b10a4 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -1,305 +1,305 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-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.Framework.MathUtils;
-using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
-using OpenTK;
-using OpenTK.Graphics;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableFruit : PalpableCatchHitObject
- {
- private Circle border;
-
- public DrawableFruit(Fruit h)
- : base(h)
- {
- Origin = Anchor.Centre;
-
- Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS);
- Masking = false;
-
- Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- // todo: this should come from the skin.
- AccentColour = colourForRrepesentation(HitObject.VisualRepresentation);
-
- InternalChildren = new[]
- {
- createPulp(HitObject.VisualRepresentation),
- border = new Circle
- {
- EdgeEffect = new EdgeEffectParameters
- {
- Hollow = !HitObject.HyperDash,
- Type = EdgeEffectType.Glow,
- Radius = 4,
- Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
- },
- Size = new Vector2(Height * 1.5f),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- BorderColour = Color4.White,
- BorderThickness = 4f,
- Children = new Framework.Graphics.Drawable[]
- {
- new Box
- {
- AlwaysPresent = true,
- Colour = AccentColour,
- Alpha = 0,
- RelativeSizeAxes = Axes.Both
- }
- }
- },
- };
-
- if (HitObject.HyperDash)
- {
- AddInternal(new Pulp
- {
- RelativePositionAxes = Axes.Both,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- AccentColour = Color4.Red,
- Blending = BlendingMode.Additive,
- Alpha = 0.5f,
- Scale = new Vector2(1.333f)
- });
- }
- }
-
- private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
- {
- const float large_pulp_3 = 13f;
- const float distance_from_centre_3 = 0.23f;
-
- const float large_pulp_4 = large_pulp_3 * 0.925f;
- const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
-
- const float small_pulp = large_pulp_3 / 2;
-
- Vector2 positionAt(float angle, float distance) => new Vector2(
- distance * (float)Math.Sin(angle * Math.PI / 180),
- distance * (float)Math.Cos(angle * Math.PI / 180));
-
- switch (representation)
- {
- default:
- return new Container();
- case FruitVisualRepresentation.Raspberry:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.BottomCentre,
- AccentColour = AccentColour,
- Size = new Vector2(small_pulp),
- Y = 0.05f,
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(0, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(90, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(180, distance_from_centre_4),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_4),
- AccentColour = AccentColour,
- Position = positionAt(270, distance_from_centre_4),
- },
- }
- };
- case FruitVisualRepresentation.Pineapple:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.BottomCentre,
- AccentColour = AccentColour,
- Size = new Vector2(small_pulp),
- Y = 0.1f,
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(45, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(135, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(225, distance_from_centre_4),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_4),
- AccentColour = AccentColour,
- Position = positionAt(315, distance_from_centre_4),
- },
- }
- };
- case FruitVisualRepresentation.Pear:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- AccentColour = AccentColour,
- Size = new Vector2(small_pulp),
- Y = -0.1f,
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(60, distance_from_centre_3),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(180, distance_from_centre_3),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_3),
- AccentColour = AccentColour,
- Position = positionAt(300, distance_from_centre_3),
- },
- }
- };
- case FruitVisualRepresentation.Grape:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- AccentColour = AccentColour,
- Size = new Vector2(small_pulp),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(0, distance_from_centre_3),
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(120, distance_from_centre_3),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_3),
- AccentColour = AccentColour,
- Position = positionAt(240, distance_from_centre_3),
- },
- }
- };
- case FruitVisualRepresentation.Banana:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- AccentColour = AccentColour,
- Size = new Vector2(small_pulp),
- Y = -0.15f
- },
- new Pulp
- {
- AccentColour = AccentColour,
- Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3),
- },
- }
- };
- }
- }
-
- protected override void Update()
- {
- base.Update();
-
- border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
- }
-
- private Color4 colourForRrepesentation(FruitVisualRepresentation representation)
- {
- switch (representation)
- {
- default:
- case FruitVisualRepresentation.Pear:
- return new Color4(17, 136, 170, 255);
- case FruitVisualRepresentation.Grape:
- return new Color4(204, 102, 0, 255);
- case FruitVisualRepresentation.Raspberry:
- return new Color4(121, 9, 13, 255);
- case FruitVisualRepresentation.Pineapple:
- return new Color4(102, 136, 0, 255);
- case FruitVisualRepresentation.Banana:
- switch (RNG.Next(0, 3))
- {
- default:
- return new Color4(255, 240, 0, 255);
- case 1:
- return new Color4(255, 192, 0, 255);
- case 2:
- return new Color4(214, 221, 28, 255);
- }
- }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+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.Framework.MathUtils;
+using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+ public class DrawableFruit : PalpableCatchHitObject
+ {
+ private Circle border;
+
+ public DrawableFruit(Fruit h)
+ : base(h)
+ {
+ Origin = Anchor.Centre;
+
+ Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS);
+ Masking = false;
+
+ Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ // todo: this should come from the skin.
+ AccentColour = colourForRrepesentation(HitObject.VisualRepresentation);
+
+ InternalChildren = new[]
+ {
+ createPulp(HitObject.VisualRepresentation),
+ border = new Circle
+ {
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Hollow = !HitObject.HyperDash,
+ Type = EdgeEffectType.Glow,
+ Radius = 4,
+ Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
+ },
+ Size = new Vector2(Height * 1.5f),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ BorderColour = Color4.White,
+ BorderThickness = 4f,
+ Children = new Framework.Graphics.Drawable[]
+ {
+ new Box
+ {
+ AlwaysPresent = true,
+ Colour = AccentColour,
+ Alpha = 0,
+ RelativeSizeAxes = Axes.Both
+ }
+ }
+ },
+ };
+
+ if (HitObject.HyperDash)
+ {
+ AddInternal(new Pulp
+ {
+ RelativePositionAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AccentColour = Color4.Red,
+ Blending = BlendingMode.Additive,
+ Alpha = 0.5f,
+ Scale = new Vector2(1.333f)
+ });
+ }
+ }
+
+ private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
+ {
+ const float large_pulp_3 = 13f;
+ const float distance_from_centre_3 = 0.23f;
+
+ const float large_pulp_4 = large_pulp_3 * 0.925f;
+ const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
+
+ const float small_pulp = large_pulp_3 / 2;
+
+ Vector2 positionAt(float angle, float distance) => new Vector2(
+ distance * (float)Math.Sin(angle * Math.PI / 180),
+ distance * (float)Math.Cos(angle * Math.PI / 180));
+
+ switch (representation)
+ {
+ default:
+ return new Container();
+ case FruitVisualRepresentation.Raspberry:
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Framework.Graphics.Drawable[]
+ {
+ new Pulp
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.BottomCentre,
+ AccentColour = AccentColour,
+ Size = new Vector2(small_pulp),
+ Y = 0.05f,
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4),
+ Position = positionAt(0, distance_from_centre_4),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4),
+ Position = positionAt(90, distance_from_centre_4),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4),
+ Position = positionAt(180, distance_from_centre_4),
+ },
+ new Pulp
+ {
+ Size = new Vector2(large_pulp_4),
+ AccentColour = AccentColour,
+ Position = positionAt(270, distance_from_centre_4),
+ },
+ }
+ };
+ case FruitVisualRepresentation.Pineapple:
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Framework.Graphics.Drawable[]
+ {
+ new Pulp
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.BottomCentre,
+ AccentColour = AccentColour,
+ Size = new Vector2(small_pulp),
+ Y = 0.1f,
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4),
+ Position = positionAt(45, distance_from_centre_4),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4),
+ Position = positionAt(135, distance_from_centre_4),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4),
+ Position = positionAt(225, distance_from_centre_4),
+ },
+ new Pulp
+ {
+ Size = new Vector2(large_pulp_4),
+ AccentColour = AccentColour,
+ Position = positionAt(315, distance_from_centre_4),
+ },
+ }
+ };
+ case FruitVisualRepresentation.Pear:
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Framework.Graphics.Drawable[]
+ {
+ new Pulp
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ AccentColour = AccentColour,
+ Size = new Vector2(small_pulp),
+ Y = -0.1f,
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_3),
+ Position = positionAt(60, distance_from_centre_3),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_3),
+ Position = positionAt(180, distance_from_centre_3),
+ },
+ new Pulp
+ {
+ Size = new Vector2(large_pulp_3),
+ AccentColour = AccentColour,
+ Position = positionAt(300, distance_from_centre_3),
+ },
+ }
+ };
+ case FruitVisualRepresentation.Grape:
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Framework.Graphics.Drawable[]
+ {
+ new Pulp
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ AccentColour = AccentColour,
+ Size = new Vector2(small_pulp),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_3),
+ Position = positionAt(0, distance_from_centre_3),
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_3),
+ Position = positionAt(120, distance_from_centre_3),
+ },
+ new Pulp
+ {
+ Size = new Vector2(large_pulp_3),
+ AccentColour = AccentColour,
+ Position = positionAt(240, distance_from_centre_3),
+ },
+ }
+ };
+ case FruitVisualRepresentation.Banana:
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Framework.Graphics.Drawable[]
+ {
+ new Pulp
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ AccentColour = AccentColour,
+ Size = new Vector2(small_pulp),
+ Y = -0.15f
+ },
+ new Pulp
+ {
+ AccentColour = AccentColour,
+ Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3),
+ },
+ }
+ };
+ }
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
+ }
+
+ private Color4 colourForRrepesentation(FruitVisualRepresentation representation)
+ {
+ switch (representation)
+ {
+ default:
+ case FruitVisualRepresentation.Pear:
+ return new Color4(17, 136, 170, 255);
+ case FruitVisualRepresentation.Grape:
+ return new Color4(204, 102, 0, 255);
+ case FruitVisualRepresentation.Raspberry:
+ return new Color4(121, 9, 13, 255);
+ case FruitVisualRepresentation.Pineapple:
+ return new Color4(102, 136, 0, 255);
+ case FruitVisualRepresentation.Banana:
+ switch (RNG.Next(0, 3))
+ {
+ default:
+ return new Color4(255, 240, 0, 255);
+ case 1:
+ return new Color4(255, 192, 0, 255);
+ case 2:
+ return new Color4(214, 221, 28, 255);
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
index b3532e2473..854b63edeb 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
@@ -1,41 +1,41 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Linq;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Objects.Drawables;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableJuiceStream : DrawableCatchHitObject
- {
- private readonly Container dropletContainer;
-
- public DrawableJuiceStream(JuiceStream s, Func> getVisualRepresentation = null)
- : base(s)
- {
- RelativeSizeAxes = Axes.Both;
- Origin = Anchor.BottomLeft;
- X = 0;
-
- InternalChild = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
-
- foreach (var o in s.NestedHitObjects.Cast())
- AddNested(getVisualRepresentation?.Invoke(o));
- }
-
- protected override bool ProvidesJudgement => false;
-
- protected override void AddNested(DrawableHitObject h)
- {
- var catchObject = (DrawableCatchHitObject)h;
-
- catchObject.CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
-
- dropletContainer.Add(h);
- base.AddNested(h);
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Linq;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+ public class DrawableJuiceStream : DrawableCatchHitObject
+ {
+ private readonly Container dropletContainer;
+
+ public DrawableJuiceStream(JuiceStream s, Func> getVisualRepresentation = null)
+ : base(s)
+ {
+ RelativeSizeAxes = Axes.Both;
+ Origin = Anchor.BottomLeft;
+ X = 0;
+
+ InternalChild = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
+
+ foreach (var o in s.NestedHitObjects.Cast())
+ AddNested(getVisualRepresentation?.Invoke(o));
+ }
+
+ protected override bool ProvidesJudgement => false;
+
+ protected override void AddNested(DrawableHitObject h)
+ {
+ var catchObject = (DrawableCatchHitObject)h;
+
+ catchObject.CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
+
+ dropletContainer.Add(h);
+ base.AddNested(h);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
index 80520ea846..d17a72a165 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
@@ -1,42 +1,42 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
-using OpenTK.Graphics;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
-{
- public class Pulp : Circle, IHasAccentColour
- {
- public Pulp()
- {
- RelativePositionAxes = Axes.Both;
- Anchor = Anchor.Centre;
- Origin = Anchor.Centre;
-
- Blending = BlendingMode.Additive;
- Colour = Color4.White.Opacity(0.9f);
- }
-
- private Color4 accentColour;
- public Color4 AccentColour
- {
- get { return accentColour; }
- set
- {
- accentColour = value;
-
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Glow,
- Radius = 8,
- Colour = accentColour.Darken(0.2f).Opacity(0.75f)
- };
- }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using OpenTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
+{
+ public class Pulp : Circle, IHasAccentColour
+ {
+ public Pulp()
+ {
+ RelativePositionAxes = Axes.Both;
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Blending = BlendingMode.Additive;
+ Colour = Color4.White.Opacity(0.9f);
+ }
+
+ private Color4 accentColour;
+ public Color4 AccentColour
+ {
+ get { return accentColour; }
+ set
+ {
+ accentColour = value;
+
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Radius = 8,
+ Colour = accentColour.Darken(0.2f).Opacity(0.75f)
+ };
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Droplet.cs b/osu.Game.Rulesets.Catch/Objects/Droplet.cs
index 4f9636e110..f91a70c506 100644
--- a/osu.Game.Rulesets.Catch/Objects/Droplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Droplet.cs
@@ -1,9 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Rulesets.Catch.Objects
-{
- public class Droplet : CatchHitObject
- {
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public class Droplet : CatchHitObject
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Fruit.cs b/osu.Game.Rulesets.Catch/Objects/Fruit.cs
index c738984667..fcbb339ffd 100644
--- a/osu.Game.Rulesets.Catch/Objects/Fruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Fruit.cs
@@ -1,9 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Rulesets.Catch.Objects
-{
- public class Fruit : CatchHitObject
- {
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public class Fruit : CatchHitObject
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index 29ad3c3956..ae799875a9 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -1,157 +1,157 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using osu.Game.Audio;
-using osu.Game.Beatmaps;
-using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Objects;
-using osu.Game.Rulesets.Objects.Types;
-using OpenTK;
-
-namespace osu.Game.Rulesets.Catch.Objects
-{
- public class JuiceStream : CatchHitObject, IHasCurve
- {
- ///
- /// Positional distance that results in a duration of one second, before any speed adjustments.
- ///
- private const float base_scoring_distance = 100;
-
- public int RepeatCount { get; set; }
-
- public double Velocity;
- public double TickDistance;
-
- protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
- {
- base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
-
- TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
- DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
-
- double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier;
-
- Velocity = scoringDistance / timingPoint.BeatLength;
- TickDistance = scoringDistance / difficulty.SliderTickRate;
- }
-
- protected override void CreateNestedHitObjects()
- {
- base.CreateNestedHitObjects();
-
- createTicks();
- }
-
- private void createTicks()
- {
- if (TickDistance == 0)
- return;
-
- var length = Curve.Distance;
- var tickDistance = Math.Min(TickDistance, length);
- var spanDuration = length / Velocity;
-
- var minDistanceFromEnd = Velocity * 0.01;
-
- AddNested(new Fruit
- {
- Samples = Samples,
- StartTime = StartTime,
- X = X
- });
-
- double lastDropletTime = StartTime;
-
- for (int span = 0; span < this.SpanCount(); span++)
- {
- var spanStartTime = StartTime + span * spanDuration;
- var reversed = span % 2 == 1;
-
- for (double d = 0; d <= length; d += tickDistance)
- {
- var timeProgress = d / length;
- var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
-
- double time = spanStartTime + timeProgress * spanDuration;
-
- double tinyTickInterval = time - lastDropletTime;
- while (tinyTickInterval > 100)
- tinyTickInterval /= 2;
-
- for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
- {
- double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
-
- AddNested(new TinyDroplet
- {
- StartTime = t,
- X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
- Samples = new List(Samples.Select(s => new SampleInfo
- {
- Bank = s.Bank,
- Name = @"slidertick",
- Volume = s.Volume
- }))
- });
- }
-
- if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd)
- {
- AddNested(new Droplet
- {
- StartTime = time,
- X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
- Samples = new List(Samples.Select(s => new SampleInfo
- {
- Bank = s.Bank,
- Name = @"slidertick",
- Volume = s.Volume
- }))
- });
- }
-
- lastDropletTime = time;
- }
-
- AddNested(new Fruit
- {
- Samples = Samples,
- StartTime = spanStartTime + spanDuration,
- X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
- });
- }
- }
-
- public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
-
- public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
-
- public double Duration => EndTime - StartTime;
-
- public double Distance
- {
- get { return Curve.Distance; }
- set { Curve.Distance = value; }
- }
-
- public SliderCurve Curve { get; } = new SliderCurve();
-
- public List ControlPoints
- {
- get { return Curve.ControlPoints; }
- set { Curve.ControlPoints = value; }
- }
-
- public List> RepeatSamples { get; set; } = new List>();
-
- public CurveType CurveType
- {
- get { return Curve.CurveType; }
- set { Curve.CurveType = value; }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Game.Audio;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using OpenTK;
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public class JuiceStream : CatchHitObject, IHasCurve
+ {
+ ///
+ /// Positional distance that results in a duration of one second, before any speed adjustments.
+ ///
+ private const float base_scoring_distance = 100;
+
+ public int RepeatCount { get; set; }
+
+ public double Velocity;
+ public double TickDistance;
+
+ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
+ {
+ base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
+
+ TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
+ DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
+
+ double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier;
+
+ Velocity = scoringDistance / timingPoint.BeatLength;
+ TickDistance = scoringDistance / difficulty.SliderTickRate;
+ }
+
+ protected override void CreateNestedHitObjects()
+ {
+ base.CreateNestedHitObjects();
+
+ createTicks();
+ }
+
+ private void createTicks()
+ {
+ if (TickDistance == 0)
+ return;
+
+ var length = Curve.Distance;
+ var tickDistance = Math.Min(TickDistance, length);
+ var spanDuration = length / Velocity;
+
+ var minDistanceFromEnd = Velocity * 0.01;
+
+ AddNested(new Fruit
+ {
+ Samples = Samples,
+ StartTime = StartTime,
+ X = X
+ });
+
+ double lastDropletTime = StartTime;
+
+ for (int span = 0; span < this.SpanCount(); span++)
+ {
+ var spanStartTime = StartTime + span * spanDuration;
+ var reversed = span % 2 == 1;
+
+ for (double d = 0; d <= length; d += tickDistance)
+ {
+ var timeProgress = d / length;
+ var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
+
+ double time = spanStartTime + timeProgress * spanDuration;
+
+ double tinyTickInterval = time - lastDropletTime;
+ while (tinyTickInterval > 100)
+ tinyTickInterval /= 2;
+
+ for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
+ {
+ double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
+
+ AddNested(new TinyDroplet
+ {
+ StartTime = t,
+ X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
+ Samples = new List(Samples.Select(s => new SampleInfo
+ {
+ Bank = s.Bank,
+ Name = @"slidertick",
+ Volume = s.Volume
+ }))
+ });
+ }
+
+ if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd)
+ {
+ AddNested(new Droplet
+ {
+ StartTime = time,
+ X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
+ Samples = new List(Samples.Select(s => new SampleInfo
+ {
+ Bank = s.Bank,
+ Name = @"slidertick",
+ Volume = s.Volume
+ }))
+ });
+ }
+
+ lastDropletTime = time;
+ }
+
+ AddNested(new Fruit
+ {
+ Samples = Samples,
+ StartTime = spanStartTime + spanDuration,
+ X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
+ });
+ }
+ }
+
+ public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
+
+ public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
+
+ public double Duration => EndTime - StartTime;
+
+ public double Distance
+ {
+ get { return Curve.Distance; }
+ set { Curve.Distance = value; }
+ }
+
+ public SliderCurve Curve { get; } = new SliderCurve();
+
+ public List ControlPoints
+ {
+ get { return Curve.ControlPoints; }
+ set { Curve.ControlPoints = value; }
+ }
+
+ public List> RepeatSamples { get; set; } = new List>();
+
+ public CurveType CurveType
+ {
+ get { return Curve.CurveType; }
+ set { Curve.CurveType = value; }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
index 23b8a7e02f..76cc8d9808 100644
--- a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
@@ -1,9 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Rulesets.Catch.Objects
-{
- public class TinyDroplet : Droplet
- {
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public class TinyDroplet : Droplet
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
index fed1013ae1..045d0824c6 100644
--- a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
@@ -1,11 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Runtime.CompilerServices;
-
-// We publish our internal attributes to other sub-projects of the framework.
-// Note, that we omit visual tests as they are meant to test the framework
-// behavior "in the wild".
-
-[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
-[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.Dynamic")]
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Runtime.CompilerServices;
+
+// We publish our internal attributes to other sub-projects of the framework.
+// Note, that we omit visual tests as they are meant to test the framework
+// behavior "in the wild".
+
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.Dynamic")]
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
index 244ab2b508..936ab6a9d3 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
@@ -1,121 +1,121 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Linq;
-using osu.Framework.MathUtils;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Replays;
-using osu.Game.Users;
-
-namespace osu.Game.Rulesets.Catch.Replays
-{
- internal class CatchAutoGenerator : AutoGenerator
- {
- public const double RELEASE_DELAY = 20;
-
- public CatchAutoGenerator(Beatmap beatmap)
- : base(beatmap)
- {
- Replay = new Replay { User = new User { Username = @"Autoplay" } };
- }
-
- protected Replay Replay;
-
- public override Replay Generate()
- {
- // todo: add support for HT DT
- const double dash_speed = CatcherArea.Catcher.BASE_SPEED;
- const double movement_speed = dash_speed / 2;
- float lastPosition = 0.5f;
- double lastTime = 0;
-
- // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
- Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition));
-
- void moveToNext(CatchHitObject h)
- {
- float positionChange = Math.Abs(lastPosition - h.X);
- double timeAvailable = h.StartTime - lastTime;
-
- //So we can either make it there without a dash or not.
- double speedRequired = positionChange / timeAvailable;
-
- bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
-
- // todo: get correct catcher size, based on difficulty CS.
- const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
-
- if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
- {
- //we are already in the correct range.
- lastTime = h.StartTime;
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition));
- return;
- }
-
- if (h is BananaShower.Banana)
- {
- // auto bananas unrealistically warp to catch 100% combo.
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
- }
- else if (h.HyperDash)
- {
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition));
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
- }
- else if (dashRequired)
- {
- //we do a movement in two parts - the dash part then the normal part...
- double timeAtNormalSpeed = positionChange / movement_speed;
- double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
- double timeAtDashSpeed = timeWeNeedToSave / 2;
-
- float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
-
- //dash movement
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, true));
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition));
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
- }
- else
- {
- double timeBefore = positionChange / movement_speed;
-
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition));
- Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
- }
-
- lastTime = h.StartTime;
- lastPosition = h.X;
- }
-
- foreach (var obj in Beatmap.HitObjects)
- {
- switch (obj)
- {
- case Fruit _:
- moveToNext(obj);
- break;
- }
-
- foreach (var nestedObj in obj.NestedHitObjects.Cast())
- {
- switch (nestedObj)
- {
- case BananaShower.Banana _:
- case TinyDroplet _:
- case Droplet _:
- case Fruit _:
- moveToNext(nestedObj);
- break;
- }
- }
- }
-
- return Replay;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Linq;
+using osu.Framework.MathUtils;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Users;
+
+namespace osu.Game.Rulesets.Catch.Replays
+{
+ internal class CatchAutoGenerator : AutoGenerator
+ {
+ public const double RELEASE_DELAY = 20;
+
+ public CatchAutoGenerator(Beatmap beatmap)
+ : base(beatmap)
+ {
+ Replay = new Replay { User = new User { Username = @"Autoplay" } };
+ }
+
+ protected Replay Replay;
+
+ public override Replay Generate()
+ {
+ // todo: add support for HT DT
+ const double dash_speed = CatcherArea.Catcher.BASE_SPEED;
+ const double movement_speed = dash_speed / 2;
+ float lastPosition = 0.5f;
+ double lastTime = 0;
+
+ // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
+ Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition));
+
+ void moveToNext(CatchHitObject h)
+ {
+ float positionChange = Math.Abs(lastPosition - h.X);
+ double timeAvailable = h.StartTime - lastTime;
+
+ //So we can either make it there without a dash or not.
+ double speedRequired = positionChange / timeAvailable;
+
+ bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
+
+ // todo: get correct catcher size, based on difficulty CS.
+ const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
+
+ if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
+ {
+ //we are already in the correct range.
+ lastTime = h.StartTime;
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition));
+ return;
+ }
+
+ if (h is BananaShower.Banana)
+ {
+ // auto bananas unrealistically warp to catch 100% combo.
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
+ }
+ else if (h.HyperDash)
+ {
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition));
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
+ }
+ else if (dashRequired)
+ {
+ //we do a movement in two parts - the dash part then the normal part...
+ double timeAtNormalSpeed = positionChange / movement_speed;
+ double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
+ double timeAtDashSpeed = timeWeNeedToSave / 2;
+
+ float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
+
+ //dash movement
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, true));
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition));
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
+ }
+ else
+ {
+ double timeBefore = positionChange / movement_speed;
+
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition));
+ Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
+ }
+
+ lastTime = h.StartTime;
+ lastPosition = h.X;
+ }
+
+ foreach (var obj in Beatmap.HitObjects)
+ {
+ switch (obj)
+ {
+ case Fruit _:
+ moveToNext(obj);
+ break;
+ }
+
+ foreach (var nestedObj in obj.NestedHitObjects.Cast())
+ {
+ switch (nestedObj)
+ {
+ case BananaShower.Banana _:
+ case TinyDroplet _:
+ case Droplet _:
+ case Fruit _:
+ moveToNext(nestedObj);
+ break;
+ }
+ }
+ }
+
+ return Replay;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
index 9c9b06fcea..6a9d1bdbc7 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
@@ -1,60 +1,60 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Collections.Generic;
-using osu.Framework.Input;
-using osu.Framework.MathUtils;
-using osu.Game.Rulesets.Replays;
-
-namespace osu.Game.Rulesets.Catch.Replays
-{
- public class CatchFramedReplayInputHandler : FramedReplayInputHandler
- {
- public CatchFramedReplayInputHandler(Replay replay)
- : base(replay)
- {
- }
-
- protected override bool IsImportant(CatchReplayFrame frame) => frame.Position > 0;
-
- protected float? Position
- {
- get
- {
- if (!HasFrames)
- return null;
-
- return Interpolation.ValueAt(CurrentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time);
- }
- }
-
- public override List GetPendingStates()
- {
- if (!Position.HasValue) return new List();
-
- var actions = new List();
-
- if (CurrentFrame.Dashing)
- actions.Add(CatchAction.Dash);
-
- if (Position.Value > CurrentFrame.Position)
- actions.Add(CatchAction.MoveRight);
- else if (Position.Value < CurrentFrame.Position)
- actions.Add(CatchAction.MoveLeft);
-
- return new List
- {
- new CatchReplayState
- {
- PressedActions = actions,
- CatcherX = Position.Value
- },
- };
- }
-
- public class CatchReplayState : ReplayState
- {
- public float? CatcherX { get; set; }
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using osu.Framework.Input;
+using osu.Framework.MathUtils;
+using osu.Game.Rulesets.Replays;
+
+namespace osu.Game.Rulesets.Catch.Replays
+{
+ public class CatchFramedReplayInputHandler : FramedReplayInputHandler
+ {
+ public CatchFramedReplayInputHandler(Replay replay)
+ : base(replay)
+ {
+ }
+
+ protected override bool IsImportant(CatchReplayFrame frame) => frame.Position > 0;
+
+ protected float? Position
+ {
+ get
+ {
+ if (!HasFrames)
+ return null;
+
+ return Interpolation.ValueAt(CurrentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time);
+ }
+ }
+
+ public override List GetPendingStates()
+ {
+ if (!Position.HasValue) return new List();
+
+ var actions = new List();
+
+ if (CurrentFrame.Dashing)
+ actions.Add(CatchAction.Dash);
+
+ if (Position.Value > CurrentFrame.Position)
+ actions.Add(CatchAction.MoveRight);
+ else if (Position.Value < CurrentFrame.Position)
+ actions.Add(CatchAction.MoveLeft);
+
+ return new List
+ {
+ new CatchReplayState
+ {
+ PressedActions = actions,
+ CatcherX = Position.Value
+ },
+ };
+ }
+
+ public class CatchReplayState : ReplayState
+ {
+ public float? CatcherX { get; set; }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs b/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
index b444b0d7ba..d63d1bd331 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
@@ -1,34 +1,34 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Replays;
-using osu.Game.Rulesets.Replays.Legacy;
-using osu.Game.Rulesets.Replays.Types;
-
-namespace osu.Game.Rulesets.Catch.Replays
-{
- public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame
- {
- public float Position;
- public bool Dashing;
-
- public CatchReplayFrame()
- {
- }
-
- public CatchReplayFrame(double time, float? position = null, bool dashing = false)
- : base(time)
- {
- Position = position ?? -1;
- Dashing = dashing;
- }
-
- public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
- {
- Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
- Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Rulesets.Replays.Legacy;
+using osu.Game.Rulesets.Replays.Types;
+
+namespace osu.Game.Rulesets.Catch.Replays
+{
+ public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame
+ {
+ public float Position;
+ public bool Dashing;
+
+ public CatchReplayFrame()
+ {
+ }
+
+ public CatchReplayFrame(double time, float? position = null, bool dashing = false)
+ : base(time)
+ {
+ Position = position ?? -1;
+ Dashing = dashing;
+ }
+
+ public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
+ {
+ Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
+ Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
index 0a8a53c6f1..ce1aee5c34 100644
--- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
@@ -1,44 +1,44 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Linq;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Judgements;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.UI;
-
-namespace osu.Game.Rulesets.Catch.Scoring
-{
- public class CatchScoreProcessor : ScoreProcessor
- {
- public CatchScoreProcessor(RulesetContainer rulesetContainer)
- : base(rulesetContainer)
- {
- }
-
- protected override void SimulateAutoplay(Beatmap beatmap)
- {
- foreach (var obj in beatmap.HitObjects)
- {
- switch (obj)
- {
- case JuiceStream stream:
- foreach (var _ in stream.NestedHitObjects.Cast())
- AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
- break;
- case BananaShower shower:
- foreach (var _ in shower.NestedHitObjects.Cast())
- AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
- AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
- break;
- case Fruit _:
- AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
- break;
- }
- }
-
- base.SimulateAutoplay(beatmap);
- }
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Judgements;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.UI;
+
+namespace osu.Game.Rulesets.Catch.Scoring
+{
+ public class CatchScoreProcessor : ScoreProcessor
+ {
+ public CatchScoreProcessor(RulesetContainer rulesetContainer)
+ : base(rulesetContainer)
+ {
+ }
+
+ protected override void SimulateAutoplay(Beatmap beatmap)
+ {
+ foreach (var obj in beatmap.HitObjects)
+ {
+ switch (obj)
+ {
+ case JuiceStream stream:
+ foreach (var _ in stream.NestedHitObjects.Cast())
+ AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+ break;
+ case BananaShower shower:
+ foreach (var _ in shower.NestedHitObjects.Cast())
+ AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+ AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+ break;
+ case Fruit _:
+ AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+ break;
+ }
+ }
+
+ base.SimulateAutoplay(beatmap);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 2b6a7c41f4..9eca8f6871 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -1,70 +1,70 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
-using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.UI.Scrolling;
-
-namespace osu.Game.Rulesets.Catch.UI
-{
- public class CatchPlayfield : ScrollingPlayfield
- {
- public const float BASE_WIDTH = 512;
-
- protected override Container Content => content;
- private readonly Container content;
-
- private readonly CatcherArea catcherArea;
-
- public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation)
- : base(ScrollingDirection.Down, BASE_WIDTH)
- {
- Container explodingFruitContainer;
-
- Anchor = Anchor.TopCentre;
- Origin = Anchor.TopCentre;
-
- base.Content.Anchor = Anchor.BottomLeft;
- base.Content.Origin = Anchor.BottomLeft;
-
- base.Content.AddRange(new Drawable[]
- {
- explodingFruitContainer = new Container
- {
- RelativeSizeAxes = Axes.Both,
- },
- catcherArea = new CatcherArea(difficulty)
- {
- GetVisualRepresentation = getVisualRepresentation,
- ExplodingFruitTarget = explodingFruitContainer,
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.TopLeft,
- },
- content = new Container
- {
- RelativeSizeAxes = Axes.Both,
- },
- });
- }
-
- public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj);
-
- public override void Add(DrawableHitObject h)
- {
- h.OnJudgement += onJudgement;
-
- base.Add(h);
-
- var fruit = (DrawableCatchHitObject)h;
- fruit.CheckPosition = CheckIfWeCanCatch;
- }
-
- private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) => catcherArea.OnJudgement((DrawableCatchHitObject)judgedObject, judgement);
- }
-}
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.UI.Scrolling;
+
+namespace osu.Game.Rulesets.Catch.UI
+{
+ public class CatchPlayfield : ScrollingPlayfield
+ {
+ public const float BASE_WIDTH = 512;
+
+ protected override Container Content => content;
+ private readonly Container content;
+
+ private readonly CatcherArea catcherArea;
+
+ public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation)
+ : base(ScrollingDirection.Down, BASE_WIDTH)
+ {
+ Container explodingFruitContainer;
+
+ Anchor = Anchor.TopCentre;
+ Origin = Anchor.TopCentre;
+
+ base.Content.Anchor = Anchor.BottomLeft;
+ base.Content.Origin = Anchor.BottomLeft;
+
+ base.Content.AddRange(new Drawable[]
+ {
+ explodingFruitContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ catcherArea = new CatcherArea(difficulty)
+ {
+ GetVisualRepresentation = getVisualRepresentation,
+ ExplodingFruitTarget = explodingFruitContainer,
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.TopLeft,
+ },
+ content = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ });
+ }
+
+ public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj);
+
+ public override void Add(DrawableHitObject h)
+ {
+ h.OnJudgement += onJudgement;
+
+ base.Add(h);
+
+ var fruit = (DrawableCatchHitObject)h;
+ fruit.CheckPosition = CheckIfWeCanCatch;
+ }
+
+ private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) => catcherArea.OnJudgement((DrawableCatchHitObject)judgedObject, judgement);
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
index 41dd7fdf4e..022a8a8b43 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
@@ -1,59 +1,59 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Input;
-using osu.Game.Beatmaps;
-using osu.Game.Input.Handlers;
-using osu.Game.Rulesets.Catch.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
-using osu.Game.Rulesets.Catch.Replays;
-using osu.Game.Rulesets.Catch.Scoring;
-using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Replays;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.UI;
-using osu.Game.Rulesets.UI.Scrolling;
-using OpenTK;
-
-namespace osu.Game.Rulesets.Catch.UI
-{
- public class CatchRulesetContainer : ScrollingRulesetContainer
- {
- public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
- : base(ruleset, beatmap, isForCurrentRuleset)
- {
- }
-
- public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
-
- protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
-
- protected override BeatmapProcessor CreateBeatmapProcessor() => new CatchBeatmapProcessor();
-
- protected override BeatmapConverter