diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net461_.xml b/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net461_.xml
new file mode 100644
index 0000000000..cf4bccfe60
--- /dev/null
+++ b/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net461_.xml
@@ -0,0 +1,18 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="VisualTests (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
+    <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
+    <option name="PASS_PARENT_ENVS" value="1" />
+    <envs />
+    <option name="USE_MONO" value="0" />
+    <option name="USE_EXTERNAL_CONSOLE" value="0" />
+    <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Tests/osu.Game.Tests.csproj" />
+    <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
+    <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
+    <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
+    <option name="PROJECT_KIND" value="DotNetCore" />
+    <option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
+    <method />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_0_.xml b/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_0_.xml
new file mode 100644
index 0000000000..08b4e38667
--- /dev/null
+++ b/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_0_.xml
@@ -0,0 +1,18 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="VisualTests (netcoreapp2.0)" type="DotNetProject" factoryName=".NET Project">
+    <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
+    <option name="PASS_PARENT_ENVS" value="1" />
+    <envs />
+    <option name="USE_MONO" value="0" />
+    <option name="USE_EXTERNAL_CONSOLE" value="0" />
+    <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Tests/osu.Game.Tests.csproj" />
+    <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
+    <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
+    <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
+    <option name="PROJECT_KIND" value="DotNetCore" />
+    <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.0" />
+    <method />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu___net461_.xml b/.idea/.idea.osu/.idea/runConfigurations/osu___net461_.xml
new file mode 100644
index 0000000000..971868a81b
--- /dev/null
+++ b/.idea/.idea.osu/.idea/runConfigurations/osu___net461_.xml
@@ -0,0 +1,18 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="osu! (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
+    <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net461/osu!.exe" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
+    <option name="PASS_PARENT_ENVS" value="1" />
+    <envs />
+    <option name="USE_MONO" value="0" />
+    <option name="USE_EXTERNAL_CONSOLE" value="0" />
+    <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
+    <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
+    <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
+    <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
+    <option name="PROJECT_KIND" value="DotNetCore" />
+    <option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
+    <method />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu___netcoreapp2_0_.xml b/.idea/.idea.osu/.idea/runConfigurations/osu___netcoreapp2_0_.xml
new file mode 100644
index 0000000000..2f5c137631
--- /dev/null
+++ b/.idea/.idea.osu/.idea/runConfigurations/osu___netcoreapp2_0_.xml
@@ -0,0 +1,18 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="osu! (netcoreapp2.0)" type="DotNetProject" factoryName=".NET Project">
+    <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
+    <option name="PASS_PARENT_ENVS" value="1" />
+    <envs />
+    <option name="USE_MONO" value="0" />
+    <option name="USE_EXTERNAL_CONSOLE" value="0" />
+    <option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
+    <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
+    <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
+    <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
+    <option name="PROJECT_KIND" value="DotNetCore" />
+    <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.0" />
+    <method />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 506915f462..624e584f10 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,64 +1,111 @@
 {
     "version": "0.2.0",
-    "configurations": [{
-            "name": "osu! VisualTests (Debug)",
+    "configurations": [
+        {
+            "name": "VisualTests (Debug, net461)",
             "windows": {
                 "type": "clr"
             },
             "type": "mono",
             "request": "launch",
-            "program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
+            "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "osu! (Debug, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/osu.Desktop/bin/Debug/net461/osu!.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "osu! (Release, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/osu.Desktop/bin/Release/net461/osu!.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Debug, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
             "args": [
-                "--tests"
+                "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
             ],
             "cwd": "${workspaceRoot}",
-            "preLaunchTask": "Build (Debug)",
-            "runtimeExecutable": null,
+            "preLaunchTask": "Build (Debug, dotnet)",
             "env": {},
             "console": "internalConsole"
         },
         {
-            "name": "osu! VisualTests (Release)",
-            "windows": {
-                "type": "clr"
-            },
-            "type": "mono",
+            "name": "VisualTests (Release, netcoreapp2.0)",
+            "type": "coreclr",
             "request": "launch",
-            "program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
+            "program": "dotnet",
             "args": [
-                "--tests"
+                "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
             ],
             "cwd": "${workspaceRoot}",
-            "preLaunchTask": "Build (Release)",
-            "runtimeExecutable": null,
+            "preLaunchTask": "Build (Release, dotnet)",
             "env": {},
             "console": "internalConsole"
         },
         {
-            "name": "osu! (Debug)",
-            "windows": {
-                "type": "clr"
-            },
-            "type": "mono",
+            "name": "osu! (Debug, netcoreapp2.0)",
+            "type": "coreclr",
             "request": "launch",
-            "program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
+            ],
             "cwd": "${workspaceRoot}",
-            "preLaunchTask": "Build (Debug)",
-            "runtimeExecutable": null,
+            "preLaunchTask": "Build (Debug, dotnet)",
             "env": {},
             "console": "internalConsole"
         },
         {
-            "name": "osu! (Release)",
-            "windows": {
-                "type": "clr"
-            },
-            "type": "mono",
+            "name": "osu! (Release, netcoreapp2.0)",
+            "type": "coreclr",
             "request": "launch",
-            "program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
+            ],
             "cwd": "${workspaceRoot}",
-            "preLaunchTask": "Build (Release)",
-            "runtimeExecutable": null,
+            "preLaunchTask": "Build (Release, dotnet)",
             "env": {},
             "console": "internalConsole"
         }
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 20af2f68a6..0000000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-// Place your settings in this file to overwrite default and user settings.
-{
-}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index f67d7a8c4e..b1d2c6b57d 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -2,70 +2,84 @@
     // See https://go.microsoft.com/fwlink/?LinkId=733558
     // for the documentation about the tasks.json format
     "version": "2.0.0",
-    "tasks": [{
-            "label": "Build (Debug)",
-            "type": "shell",
-            "command": "msbuild",
-            "args": [
-                "/p:GenerateFullPaths=true",
-                "/p:DebugType=portable",
-                "/m",
-                "/v:m"
-            ],
-            "group": {
-                "kind": "build",
-                "isDefault": true
-            },
-            "problemMatcher": "$msCompile"
-        },
+    "tasks": [
         {
-            "label": "Build (Release)",
+            "label": "Build (Debug, msbuild)",
             "type": "shell",
             "command": "msbuild",
             "args": [
-                "/p:Configuration=Release",
-                "/p:DebugType=portable",
+                "/p:TargetFramework=net461",
                 "/p:GenerateFullPaths=true",
                 "/m",
-                "/v:m"
+                "/verbosity:m"
             ],
             "group": "build",
             "problemMatcher": "$msCompile"
         },
         {
-            "label": "Clean (Debug)",
-            "type": "shell",
-            "command": "msbuild",
-            "args": [
-                "/p:DebugType=portable",
-                "/p:GenerateFullPaths=true",
-                "/m",
-                "/t:Clean",
-                "/v:m"
-            ],
-            "problemMatcher": "$msCompile"
-        },
-        {
-            "label": "Clean (Release)",
+            "label": "Build (Release, msbuild)",
             "type": "shell",
             "command": "msbuild",
             "args": [
                 "/p:Configuration=Release",
+                "/p:TargetFramework=net461",
                 "/p:GenerateFullPaths=true",
-                "/p:DebugType=portable",
                 "/m",
-                "/t:Clean",
-                "/v:m"
+                "/verbosity:m"
             ],
+            "group": "build",
             "problemMatcher": "$msCompile"
         },
         {
-            "label": "Clean All",
-            "dependsOn": [
-                "Clean (Debug)",
-                "Clean (Release)"
+            "label": "Build (Debug, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Desktop",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
             ],
+            "group": "build",
             "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Desktop",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:Configuration=Release",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Restore (net461)",
+            "type": "shell",
+            "command": "nuget",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        },
+        {
+            "label": "Restore (netcoreapp2.0)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
         }
     ]
 }
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index e63f6ea55c..4c4b70827f 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -16,14 +16,12 @@ install:
 before_build:
   - cmd: CodeFileSanity.exe
   - cmd: nuget restore -verbosity quiet
+environment:
+  TargetFramework: net461
 build:
   project: osu.sln
   parallel: true
   verbosity: minimal
-test:
-  assemblies:
-    only:
-      - 'osu.Desktop\**\*.dll'
 after_build:
   - cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
   - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
\ No newline at end of file
diff --git a/osu-framework b/osu-framework
index 99140d9d79..85b3494117 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 99140d9d79909d1a5474e01c60e54cbdc27f6b19
+Subproject commit 85b3494117ccef1b396b70957e1cffaba06e2b54
diff --git a/osu-resources b/osu-resources
index 6e145ed502..c3848d8b1c 160000
--- a/osu-resources
+++ b/osu-resources
@@ -1 +1 @@
-Subproject commit 6e145ed50274539ee827fdc3d1fda1e130b070fd
+Subproject commit c3848d8b1c84966abe851d915bcca878415614b4
diff --git a/osu.Desktop.Deploy/.vscode/launch.json b/osu.Desktop.Deploy/.vscode/launch.json
new file mode 100644
index 0000000000..82cd6b4c13
--- /dev/null
+++ b/osu.Desktop.Deploy/.vscode/launch.json
@@ -0,0 +1,29 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [{
+            "name": "Deploy (Debug)",
+            "request": "launch",
+            "type": "mono",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Desktop.Deploy.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "Deploy (Release)",
+            "request": "launch",
+            "type": "clr",
+            "program": "${workspaceRoot}/bin/Release/net461/osu.Desktop.Deploy.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/.vscode/tasks.json b/osu.Desktop.Deploy/.vscode/tasks.json
new file mode 100644
index 0000000000..35bf9e7a0e
--- /dev/null
+++ b/osu.Desktop.Deploy/.vscode/tasks.json
@@ -0,0 +1,64 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "command": "msbuild",
+    "type": "shell",
+    "suppressTaskName": true,
+    "args": [
+        "/property:GenerateFullPaths=true",
+        "/property:DebugType=portable",
+        "/verbosity:minimal",
+        "/m" //parallel compiling support.
+    ],
+    "tasks": [{
+            "taskName": "Build (Debug)",
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            },
+            "problemMatcher": [
+                "$msCompile"
+            ]
+        },
+        {
+            "taskName": "Build (Release)",
+            "group": "build",
+            "args": [
+                "/property:Configuration=Release"
+            ],
+            "problemMatcher": [
+                "$msCompile"
+            ]
+        },
+        {
+            "taskName": "Clean (Debug)",
+            "args": [
+                "/target:Clean"
+            ],
+            "problemMatcher": [
+                "$msCompile"
+            ]
+        },
+        {
+            "taskName": "Clean (Release)",
+            "args": [
+                "/target:Clean",
+                "/property:Configuration=Release"
+            ],
+            "problemMatcher": [
+                "$msCompile"
+            ]
+        },
+        {
+            "taskName": "Clean All",
+            "dependsOn": [
+                "Clean (Debug)",
+                "Clean (Release)"
+            ],
+            "problemMatcher": [
+                "$msCompile"
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/App.config b/osu.Desktop.Deploy/App.config
index 2b948f0a20..f6673fef1a 100644
--- a/osu.Desktop.Deploy/App.config
+++ b/osu.Desktop.Deploy/App.config
@@ -18,23 +18,4 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
     <add key="IconName" value="lazer.ico" />
     <add key="CodeSigningCertificate" value="" />
   </appSettings>
-  <startup>
-    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
-  </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="DeltaCompressionDotNet.MsDelta" publicKeyToken="46b2138a390abf55" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
 </configuration>
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/Program.cs b/osu.Desktop.Deploy/Program.cs
index 3a716468c9..3c1451d555 100644
--- a/osu.Desktop.Deploy/Program.cs
+++ b/osu.Desktop.Deploy/Program.cs
@@ -16,8 +16,9 @@ namespace osu.Desktop.Deploy
 {
     internal static class Program
     {
-        private const string nuget_path = @"packages\NuGet.CommandLine.4.3.0\tools\NuGet.exe";
-        private const string squirrel_path = @"packages\squirrel.windows.1.7.8\tools\Squirrel.exe";
+        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"];
@@ -92,18 +93,15 @@ namespace osu.Desktop.Deploy
                 codeSigningPassword = readLineMasked();
             }
 
-            write("Restoring NuGet packages...");
-            runCommand(nuget_path, "restore " + solutionPath);
-
             write("Updating AssemblyInfo...");
-            updateAssemblyInfo(version);
+            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(nuget_path, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");
+            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();
@@ -111,7 +109,7 @@ namespace osu.Desktop.Deploy
             checkReleaseFiles();
 
             write("Running squirrel build...");
-            runCommand(squirrel_path, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
+            runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
 
             //prune again to clean up before upload.
             pruneReleases();
@@ -123,7 +121,7 @@ namespace osu.Desktop.Deploy
             uploadBuild(version);
 
             //reset assemblyinfo.
-            updateAssemblyInfo("0.0.0");
+            updateCsprojVersion("0.0.0");
 
             write("Done!", ConsoleColor.White);
             Console.ReadLine();
@@ -305,20 +303,29 @@ namespace osu.Desktop.Deploy
             Directory.CreateDirectory(directory);
         }
 
-        private static void updateAssemblyInfo(string version)
+        private static void updateCsprojVersion(string version)
         {
-            string file = Path.Combine(ProjectName, "Properties", "AssemblyInfo.cs");
+            var toUpdate = new[] { "<Version>", "<FileVersion>" };
+            string file = Path.Combine(ProjectName, $"{ProjectName}.csproj");
 
             var l1 = File.ReadAllLines(file);
             List<string> l2 = new List<string>();
             foreach (var l in l1)
             {
-                if (l.StartsWith("[assembly: AssemblyVersion("))
-                    l2.Add($"[assembly: AssemblyVersion(\"{version}\")]");
-                else if (l.StartsWith("[assembly: AssemblyFileVersion("))
-                    l2.Add($"[assembly: AssemblyFileVersion(\"{version}\")]");
-                else
-                    l2.Add(l);
+                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);
@@ -335,8 +342,8 @@ namespace osu.Desktop.Deploy
                 path = Environment.CurrentDirectory;
 
             while (!File.Exists(Path.Combine(path, $"{SolutionName}.sln")))
-                path = path.Remove(path.LastIndexOf('\\'));
-            path += "\\";
+                path = path.Remove(path.LastIndexOf(Path.DirectorySeparatorChar));
+            path += Path.DirectorySeparatorChar;
 
             Environment.CurrentDirectory = path;
         }
diff --git a/osu.Desktop.Deploy/Properties/AssemblyInfo.cs b/osu.Desktop.Deploy/Properties/AssemblyInfo.cs
deleted file mode 100644
index 47e0e65180..0000000000
--- a/osu.Desktop.Deploy/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu.Desktop.Deploy")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("osu.Desktop.Deploy")]
-[assembly: AssemblyCopyright("Copyright ©  2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("baea2f74-0315-4667-84e0-acac0b4bf785")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
index 3bec56d322..a18db9477a 100644
--- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
+++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
@@ -1,123 +1,18 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Desktop.Deploy</RootNamespace>
-    <AssemblyName>osu.Desktop.Deploy</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup>
-    <StartupObject>osu.Desktop.Deploy.Program</StartupObject>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.1.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.1.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Configuration" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="GitHubObject.cs" />
-    <Compile Include="GitHubRelease.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
-      <Name>osu.Framework</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFrameworks>net461</TargetFrameworks>
+    <OutputType>Exe</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
+  </ItemGroup>
+  <ItemGroup Label="Package References">
+    <PackageReference Include="NuGet.CommandLine" Version="4.5.1" />
+    <PackageReference Include="NUnit" Version="3.8.1" />
+    <PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
+    <PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/packages.config b/osu.Desktop.Deploy/packages.config
deleted file mode 100644
index 371c4c9739..0000000000
--- a/osu.Desktop.Deploy/packages.config
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
--->
-<packages>
-  <package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net452" />
-  <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" />
-  <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
-  <package id="NuGet.CommandLine" version="4.3.0" targetFramework="net461" developmentDependency="true" />
-  <package id="SharpCompress" version="0.18.1" targetFramework="net461" />
-  <package id="Splat" version="2.0.0" targetFramework="net452" />
-  <package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Desktop/OpenTK.dll.config b/osu.Desktop/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Desktop/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 45ed66bad2..3704d2d5d8 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -2,17 +2,16 @@
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
 using System;
-using System.Drawing;
 using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Threading.Tasks;
-using Microsoft.Win32;
 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
 {
@@ -100,7 +99,7 @@ namespace osu.Desktop
             {
                 desktopWindow.CursorState |= CursorState.Hidden;
 
-                desktopWindow.Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
+                desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
                 desktopWindow.Title = Name;
 
                 desktopWindow.FileDrop += fileDrop;
@@ -109,7 +108,7 @@ namespace osu.Desktop
 
         private void fileDrop(object sender, FileDropEventArgs e)
         {
-            var filePaths = new [] { e.FileName };
+            var filePaths = new[] { e.FileName };
 
             var firstExtension = Path.GetExtension(filePaths.First());
 
diff --git a/osu.Desktop/Overlays/SquirrelUpdateManager.cs b/osu.Desktop/Overlays/SquirrelUpdateManager.cs
new file mode 100644
index 0000000000..61d8a75ae3
--- /dev/null
+++ b/osu.Desktop/Overlays/SquirrelUpdateManager.cs
@@ -0,0 +1,164 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// 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 090173f38d..b61603dcc5 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -1,17 +1,13 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using System;
 using System.Diagnostics;
 using osu.Framework.Allocation;
 using osu.Framework.Development;
 using osu.Framework.Graphics;
-using osu.Framework.Graphics.Colour;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Graphics.Textures;
-using osu.Framework.Logging;
 using osu.Game;
 using osu.Game.Configuration;
 using osu.Game.Graphics;
@@ -20,16 +16,14 @@ using osu.Game.Overlays;
 using osu.Game.Overlays.Notifications;
 using OpenTK;
 using OpenTK.Graphics;
-using Squirrel;
 
 namespace osu.Desktop.Overlays
 {
     public class VersionManager : OverlayContainer
     {
-        private UpdateManager updateManager;
-        private NotificationOverlay notificationOverlay;
         private OsuConfigManager config;
         private OsuGameBase game;
+        private NotificationOverlay notificationOverlay;
 
         public override bool HandleKeyboardInput => false;
         public override bool HandleMouseInput => false;
@@ -95,8 +89,9 @@ namespace osu.Desktop.Overlays
                 }
             };
 
-            if (game.IsDeployedBuild)
-                checkForUpdateAsync();
+#if NET_FRAMEWORK
+            Add(new SquirrelUpdateManager());
+#endif
         }
 
         protected override void LoadComplete()
@@ -135,85 +130,6 @@ namespace osu.Desktop.Overlays
             }
         }
 
-        protected override void Dispose(bool isDisposing)
-        {
-            base.Dispose(isDisposing);
-            updateManager?.Dispose();
-        }
-
-        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 { State = ProgressNotificationState.Active };
-                    Schedule(() => notificationOverlay.Post(notification));
-                }
-
-                Schedule(() =>
-                {
-                    notification.Progress = 0;
-                    notification.Text = @"Downloading update...";
-                });
-
-                try
-                {
-                    await updateManager.DownloadReleases(info.ReleasesToApply, p => Schedule(() => notification.Progress = p / 100f));
-
-                    Schedule(() =>
-                    {
-                        notification.Progress = 0;
-                        notification.Text = @"Installing update...";
-                    });
-
-                    await updateManager.ApplyReleases(info, p => Schedule(() => notification.Progress = p / 100f));
-
-                    Schedule(() => 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)
-                {
-                    //check again in 30 minutes.
-                    Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
-                    if (notification != null)
-                        notification.State = ProgressNotificationState.Cancelled;
-                }
-            }
-        }
-
         protected override void PopIn()
         {
             this.FadeIn(1000);
@@ -222,45 +138,5 @@ namespace osu.Desktop.Overlays
         protected override void PopOut()
         {
         }
-
-        private class UpdateProgressNotification : ProgressNotification
-        {
-            private OsuGame game;
-
-            protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification
-            {
-                Text = @"Update ready to install. Click to restart!",
-                Activated = () =>
-                {
-                    // Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
-                    UpdateManager.RestartAppWhenExited().Wait();
-                    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),
-                    }
-                });
-            }
-        }
     }
 }
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index d036a6822c..7258610f90 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -4,10 +4,12 @@
 using System;
 using System.IO;
 using System.Linq;
-using System.Runtime;
 using osu.Framework;
 using osu.Framework.Platform;
 using osu.Game.IPC;
+#if NET_FRAMEWORK
+using System.Runtime;
+#endif
 
 namespace osu.Desktop
 {
@@ -16,6 +18,8 @@ namespace osu.Desktop
         [STAThread]
         public static int Main(string[] args)
         {
+            // required to initialise native SQLite libraries on some platforms.
+
             if (!RuntimeInfo.IsMono)
                 useMulticoreJit();
 
@@ -40,9 +44,6 @@ namespace osu.Desktop
                 {
                     switch (args.FirstOrDefault() ?? string.Empty)
                     {
-                        case "--tests":
-                            host.Run(new OsuTestBrowser());
-                            break;
                         default:
                             host.Run(new OsuGameDesktop(args));
                             break;
@@ -55,9 +56,11 @@ namespace osu.Desktop
 
         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.Desktop/Properties/AssemblyInfo.cs b/osu.Desktop/Properties/AssemblyInfo.cs
deleted file mode 100644
index cee9797619..0000000000
--- a/osu.Desktop/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu!lazer")]
-[assembly: AssemblyDescription("click the circles. to the beat.")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ppy Pty Ltd")]
-[assembly: AssemblyProduct("osu!lazer")]
-[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("b0cb1d48-e4c2-4612-a347-beea7b1a71e7")]
-
-[assembly: AssemblyVersion("0.0.0")]
-[assembly: AssemblyFileVersion("0.0.0")]
diff --git a/osu.Desktop/Properties/app.manifest b/osu.Desktop/Properties/app.manifest
deleted file mode 100644
index 555db8513d..0000000000
--- a/osu.Desktop/Properties/app.manifest
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
-  <assemblyIdentity version="1.0.0.0" name="osu!" />
-  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
-    <security>
-      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
-        <!-- UAC Manifest Options
-            If you want to change the Windows User Account Control level replace the 
-            requestedExecutionLevel node with one of the following.
-
-        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
-        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
-        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />
-
-            If you want to utilize File and Registry Virtualization for backward 
-            compatibility then delete the requestedExecutionLevel node.
-        -->
-        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
-      </requestedPrivileges>
-      <applicationRequestMinimum>
-        <defaultAssemblyRequest permissionSetReference="Custom" />
-        <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
-      </applicationRequestMinimum>
-    </security>
-  </trustInfo>
-  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
-    <application>
-      <!-- Windows Vista -->
-      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
-      <!-- Windows 7 -->
-      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
-      <!-- Windows 8 -->
-      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
-      <!-- Windows 8.1 -->
-      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
-      <!-- Windows 10 -->
-      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
-    </application>
-  </compatibility>
-  <asmv3:application>
-    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
-      <dpiAware>true</dpiAware>
-    </asmv3:windowsSettings>
-  </asmv3:application>
-  <dependency>
-    <dependentAssembly>
-      <assemblyIdentity
-          type="win32"
-          name="Microsoft.Windows.Common-Controls"
-          version="6.0.0.0"
-          processorArchitecture="*"
-          publicKeyToken="6595b64144ccf1df"
-          language="*"
-        />
-    </dependentAssembly>
-  </dependency>
-</asmv1:assembly>
diff --git a/osu.Desktop/app.config b/osu.Desktop/app.config
deleted file mode 100644
index ea1576b3d8..0000000000
--- a/osu.Desktop/app.config
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index b0d9ea4e81..2ad7b67842 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -1,284 +1,39 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <ProjectGuid>{419659FD-72EA-4678-9EB8-B22A746CED70}</ProjectGuid>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <OutputType>WinExe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Desktop</RootNamespace>
-    <AssemblyName>osu!</AssemblyName>
-    <ManifestCertificateThumbprint>3CF060CD28877D0E3112948951A64B2A7CEEC909</ManifestCertificateThumbprint>
-    <ManifestKeyFile>codesigning.pfx</ManifestKeyFile>
-    <GenerateManifests>false</GenerateManifests>
-    <SignManifests>false</SignManifests>
-    <IsWebBootstrapper>false</IsWebBootstrapper>
-    <FileUpgradeFlags>
-    </FileUpgradeFlags>
-    <OldToolsVersion>3.5</OldToolsVersion>
-    <UpgradeBackupLocation>
-    </UpgradeBackupLocation>
-    <StartupObject>osu.Desktop.Program</StartupObject>
-    <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
-    <SignAssembly>false</SignAssembly>
-    <TargetZone>LocalIntranet</TargetZone>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-    <PublishUrl>publish\</PublishUrl>
-    <Install>true</Install>
-    <InstallFrom>Disk</InstallFrom>
-    <UpdateEnabled>false</UpdateEnabled>
-    <UpdateMode>Foreground</UpdateMode>
-    <UpdateInterval>7</UpdateInterval>
-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
-    <UpdatePeriodically>false</UpdatePeriodically>
-    <UpdateRequired>false</UpdateRequired>
-    <MapFileExtensions>true</MapFileExtensions>
-    <ApplicationRevision>2</ApplicationRevision>
-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
-    <UseApplicationTrust>false</UseApplicationTrust>
-    <BootstrapperEnabled>true</BootstrapperEnabled>
-    <ProductVersion>12.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <TargetFrameworkProfile>
-    </TargetFrameworkProfile>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>0</WarningLevel>
-    <NoStdLib>true</NoStdLib>
-    <UseVSHostingProcess>false</UseVSHostingProcess>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <RunCodeAnalysis>false</RunCodeAnalysis>
-    <Prefer32Bit>false</Prefer32Bit>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-    <Commandlineparameters>
-    </Commandlineparameters>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>CuttingEdge NoUpdate</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <NoStdLib>true</NoStdLib>
-    <UseVSHostingProcess>false</UseVSHostingProcess>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <Prefer32Bit>false</Prefer32Bit>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup>
-    <Win32Resource>
-    </Win32Resource>
-  </PropertyGroup>
-  <PropertyGroup>
-    <ApplicationIcon>lazer.ico</ApplicationIcon>
-  </PropertyGroup>
-  <PropertyGroup>
-    <ApplicationManifest>Properties\app.manifest</ApplicationManifest>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VisualTests|AnyCPU'">
-    <DebugSymbols>true</DebugSymbols>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG</DefineConstants>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <WarningLevel>0</WarningLevel>
-    <NoStdLib>true</NoStdLib>
-    <DebugType>full</DebugType>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <UseVSHostingProcess>false</UseVSHostingProcess>
-    <ErrorReport>prompt</ErrorReport>
-    <StartArguments>--tests</StartArguments>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.1.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.1.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="mscorlib" />
-    <Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-    </Reference>
-    <Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
-      <HintPath>$(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.Windows.Forms" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="OpenTK.dll.config" />
-    <None Include="osu!.res" />
-    <None Include="packages.config" />
-    <None Include="Properties\app.manifest" />
-  </ItemGroup>
-  <ItemGroup>
-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
-      <Install>true</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="OsuGameDesktop.cs" />
-    <Compile Include="OsuTestBrowser.cs" />
-    <Compile Include="Overlays\VersionManager.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="lazer.ico" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
-      <Name>osu.Framework</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
-      <Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
-      <Name>osu.Game.Resources</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
-      <Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
-      <Name>osu.Game.Rulesets.Catch</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
-      <Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
-      <Name>osu.Game.Rulesets.Mania</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
-      <Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
-      <Name>osu.Game.Rulesets.Osu</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
-      <Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
-      <Name>osu.Game.Rulesets.Taiko</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj">
-      <Project>{54377672-20b1-40af-8087-5cf73bf3953a}</Project>
-      <Name>osu.Game.Tests</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game\osu.Game.csproj">
-      <Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
-      <Name>osu.Game</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-  <ProjectExtensions>
-    <VisualStudio>
-    </VisualStudio>
-  </ProjectExtensions>
-  <PropertyGroup>
-    <PreBuildEvent>
-    </PreBuildEvent>
-  </PropertyGroup>
-  <PropertyGroup>
-    <PostBuildEvent>
-    </PostBuildEvent>
-  </PropertyGroup>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
-  </Target>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
+    <OutputType>WinExe</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <Description>click the circles. to the beat.</Description>
+    <AssemblyName>osu!</AssemblyName>
+    <Title>osu!lazer</Title>
+    <Product>osu!lazer</Product>
+    <ApplicationIcon>lazer.ico</ApplicationIcon>
+    <Version>0.0.0.0</Version>
+    <FileVersion>0.0.0.0</FileVersion>
+  </PropertyGroup>
+  <PropertyGroup Label="Defines">
+    <DefineConstants Condition="'$(TargetFramework)' == 'net461'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject>osu.Desktop.Program</StartupObject>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
+    <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
+    <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
+    <PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
+  </ItemGroup>
+  <ItemGroup Label="Package References">
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
+    <PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
+  </ItemGroup>
+  <ItemGroup Label="Resources">
+    <EmbeddedResource Include="lazer.ico" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config
deleted file mode 100644
index b5dc43267d..0000000000
--- a/osu.Desktop/packages.config
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
--->
-<packages>
-  <package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
-  <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="SharpCompress" version="0.18.1" targetFramework="net461" />
-  <package id="Splat" version="2.0.0" targetFramework="net45" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-  <package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
-  <package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json
new file mode 100644
index 0000000000..5098b78a42
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json
@@ -0,0 +1,59 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "VisualTests (Debug, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Debug, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Catch.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Catch.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json
new file mode 100644
index 0000000000..d21bb8a69a
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json
@@ -0,0 +1,87 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "Build (Debug, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Catch.Tests.csproj",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Catch.Tests.csproj",
+                "/p:Configuration=Release",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Debug, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Catch.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Catch.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:Configuration=Release",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Restore (net461)",
+            "type": "shell",
+            "command": "nuget",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        },
+        {
+            "label": "Restore (netcoreapp2.0)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs
rename to osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperdash.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCaseHyperdash.cs
diff --git a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs
similarity index 100%
rename from osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs
rename to osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs
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
new file mode 100644
index 0000000000..51c6d18f1f
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.TestProject.props" />
+  <PropertyGroup Label="Project">
+    <OutputType>WinExe</OutputType>
+    <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
index 9479c9d9b0..ed33bf7124 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
@@ -8,5 +8,6 @@ namespace osu.Game.Rulesets.Catch.Mods
     public class CatchModHardRock : ModHardRock
     {
         public override double ScoreMultiplier => 1.12;
+        public override bool Ranked => true;
     }
 }
diff --git a/osu.Game.Rulesets.Catch/OpenTK.dll.config b/osu.Game.Rulesets.Catch/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Game.Rulesets.Catch/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
index 4c2542c282..00fd8247d8 100644
--- a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
@@ -1,28 +1,12 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using System.Reflection;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using osu.Framework.Testing;
 
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu.Game.Rulesets.Catch")]
-[assembly: AssemblyDescription("catch the fruit. to the beat.")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ppy Pty Ltd")]
-[assembly: AssemblyProduct("osu.Game.Rulesets.Catch")]
-[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+// 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".
 
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("58f6c80c-1253-4a0e-a465-b8c85ebeadf3")]
-
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
+[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 39b7ffb387..8bb206543b 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -57,7 +57,6 @@ namespace osu.Game.Rulesets.Catch.UI
 
         public override void Add(DrawableHitObject h)
         {
-            h.Depth = (float)h.HitObject.StartTime;
             h.OnJudgement += onJudgement;
 
             base.Add(h);
diff --git a/osu.Game.Rulesets.Catch/app.config b/osu.Game.Rulesets.Catch/app.config
deleted file mode 100644
index c9d4e44b1a..0000000000
--- a/osu.Game.Rulesets.Catch/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
index 4e2cdd24c3..883cac67d1 100644
--- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
+++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
@@ -1,148 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Game.Rulesets.Catch</RootNamespace>
-    <AssemblyName>osu.Game.Rulesets.Catch</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Collections" />
-    <Reference Include="System.Core" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Beatmaps\CatchBeatmapConverter.cs" />
-    <Compile Include="Beatmaps\CatchBeatmapProcessor.cs" />
-    <Compile Include="CatchDifficultyCalculator.cs" />
-    <Compile Include="CatchInputManager.cs" />
-    <Compile Include="Mods\CatchModDaycore.cs" />
-    <Compile Include="Mods\CatchModDoubleTime.cs" />
-    <Compile Include="Mods\CatchModEasy.cs" />
-    <Compile Include="Mods\CatchModFlashlight.cs" />
-    <Compile Include="Mods\CatchModHalfTime.cs" />
-    <Compile Include="Mods\CatchModHardRock.cs" />
-    <Compile Include="Mods\CatchModHidden.cs" />
-    <Compile Include="Mods\CatchModNightcore.cs" />
-    <Compile Include="Mods\CatchModPerfect.cs" />
-    <Compile Include="Mods\CatchModRelax.cs" />
-    <Compile Include="Mods\CatchModSuddenDeath.cs" />
-    <Compile Include="Mods\CatchModAutoplay.cs" />
-    <Compile Include="Objects\BananaShower.cs" />
-    <Compile Include="Objects\Drawable\DrawableBananaShower.cs" />
-    <Compile Include="Objects\Drawable\DrawableCatchHitObject.cs" />
-    <Compile Include="Objects\Drawable\DrawableDroplet.cs" />
-    <Compile Include="Objects\Drawable\DrawableJuiceStream.cs" />
-    <Compile Include="Objects\Drawable\Pieces\Pulp.cs" />
-    <Compile Include="Objects\JuiceStream.cs" />
-    <Compile Include="Replays\CatchAutoGenerator.cs" />
-    <Compile Include="Replays\CatchFramedReplayInputHandler.cs" />
-    <Compile Include="Replays\CatchReplayFrame.cs" />
-    <Compile Include="Scoring\CatchScoreProcessor.cs" />
-    <Compile Include="Judgements\CatchJudgement.cs" />
-    <Compile Include="Objects\CatchHitObject.cs" />
-    <Compile Include="Objects\Drawable\DrawableFruit.cs" />
-    <Compile Include="Objects\Droplet.cs" />
-    <Compile Include="Objects\Fruit.cs" />
-    <Compile Include="Objects\TinyDroplet.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Tests\CatchBeatmapConversionTest.cs" />
-    <Compile Include="Tests\TestCaseBananaShower.cs" />
-    <Compile Include="Tests\TestCaseCatcherArea.cs" />
-    <Compile Include="Tests\TestCaseCatchStacker.cs" />
-    <Compile Include="Tests\TestCaseFruitObjects.cs" />
-    <Compile Include="Tests\TestCasePerformancePoints.cs" />
-    <Compile Include="Tests\TestCaseCatchPlayer.cs" />
-    <Compile Include="Tests\TestCaseHyperdash.cs" />
-    <Compile Include="UI\CatcherArea.cs" />
-    <Compile Include="UI\CatchRulesetContainer.cs" />
-    <Compile Include="UI\CatchPlayfield.cs" />
-    <Compile Include="CatchRuleset.cs" />
-    <Compile Include="Mods\CatchModNoFail.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="OpenTK.dll.config" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
-      <Name>osu.Framework</Name>
-      <Private>True</Private>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game\osu.Game.csproj">
-      <Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
-      <Name>osu.Game</Name>
-      <Private>True</Private>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
-  </Target>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <OutputType>Library</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <Description>catch the fruit. to the beat.</Description>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/packages.config b/osu.Game.Rulesets.Catch/packages.config
deleted file mode 100644
index 7a784f5293..0000000000
--- a/osu.Game.Rulesets.Catch/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
-  <package id="NUnit" version="3.8.1" targetFramework="net461" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json
new file mode 100644
index 0000000000..c71178059b
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json
@@ -0,0 +1,59 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "VisualTests (Debug, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Debug, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Mania.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Mania.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json
new file mode 100644
index 0000000000..781e89598f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json
@@ -0,0 +1,87 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "Build (Debug, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Mania.Tests.csproj",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Mania.Tests.csproj",
+                "/p:Configuration=Release",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Debug, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Mania.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Mania.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:Configuration=Release",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Restore (net461)",
+            "type": "shell",
+            "command": "nuget",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        },
+        {
+            "label": "Restore (netcoreapp2.0)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
similarity index 100%
rename from osu.Game.Rulesets.Mania/Tests/ManiaBeatmapConversionTest.cs
rename to osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseAutoGeneration.cs
similarity index 100%
rename from osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs
rename to osu.Game.Rulesets.Mania.Tests/TestCaseAutoGeneration.cs
diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseManiaHitObjects.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseManiaHitObjects.cs
similarity index 100%
rename from osu.Game.Rulesets.Mania/Tests/TestCaseManiaHitObjects.cs
rename to osu.Game.Rulesets.Mania.Tests/TestCaseManiaHitObjects.cs
diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs
similarity index 100%
rename from osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs
rename to osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs
diff --git a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs
similarity index 100%
rename from osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs
rename to osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
new file mode 100644
index 0000000000..187d5e47b9
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.TestProject.props" />
+  <PropertyGroup Label="Project">
+    <OutputType>WinExe</OutputType>
+    <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/OpenTK.dll.config b/osu.Game.Rulesets.Mania/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Game.Rulesets.Mania/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
index d1aeb53aa8..c2c65433ec 100644
--- a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
@@ -1,28 +1,12 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using System.Reflection;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using osu.Framework.Testing;
 
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu.Game.Rulesets.Mania")]
-[assembly: AssemblyDescription("smash the keys. to the beat.")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ppy Pty Ltd")]
-[assembly: AssemblyProduct("osu.Game.Rulesets.Mania")]
-[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+// 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".
 
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("48f4582b-7687-4621-9cbe-5c24197cb536")]
-
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests")]
+[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index 21f00c003b..15c9a83b78 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -205,7 +205,6 @@ namespace osu.Game.Rulesets.Mania.UI
         /// <param name="hitObject">The DrawableHitObject to add.</param>
         public override void Add(DrawableHitObject hitObject)
         {
-            hitObject.Depth = (float)hitObject.HitObject.StartTime;
             hitObject.AccentColour = AccentColour;
             hitObject.OnJudgement += OnJudgement;
 
@@ -263,21 +262,13 @@ namespace osu.Game.Rulesets.Mania.UI
 
         public bool OnPressed(ManiaAction action)
         {
-            // Play the sounds of the next hitobject
-            if (HitObjects.AliveObjects.Any())
-            {
-                // If there are alive hitobjects, we can abuse the fact that AliveObjects are sorted by time (see: Add())
-                HitObjects.AliveObjects.First().PlaySamples();
-            }
-            else
-            {
-                // If not, we do a slow search - we might want to do a BinarySearch here if this becomes problematic
-                // We fallback to LastOrDefault() if we're beyond the last note in the map
-                var hitObject = HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.LastOrDefault();
-                hitObject?.PlaySamples();
-            }
+            if (action != Action)
+                return false;
 
-            return false;
+            var hitObject = HitObjects.Objects.LastOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.FirstOrDefault();
+            hitObject?.PlaySamples();
+
+            return true;
         }
 
         public bool OnReleased(ManiaAction action) => false;
diff --git a/osu.Game.Rulesets.Mania/app.config b/osu.Game.Rulesets.Mania/app.config
deleted file mode 100644
index c9d4e44b1a..0000000000
--- a/osu.Game.Rulesets.Mania/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
index 39b856b67b..a086da0565 100644
--- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
+++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
@@ -1,181 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{48F4582B-7687-4621-9CBE-5C24197CB536}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Game.Rulesets.Mania</RootNamespace>
-    <AssemblyName>osu.Game.Rulesets.Mania</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Beatmaps\StageDefinition.cs" />
-    <Compile Include="Beatmaps\ManiaBeatmap.cs" />
-    <Compile Include="Beatmaps\Patterns\Legacy\EndTimeObjectPatternGenerator.cs" />
-    <Compile Include="Beatmaps\Patterns\Legacy\DistanceObjectPatternGenerator.cs" />
-    <Compile Include="Beatmaps\Patterns\Legacy\PatternGenerator.cs" />
-    <Compile Include="Beatmaps\Patterns\PatternGenerator.cs" />
-    <Compile Include="Beatmaps\Patterns\Legacy\HitObjectPatternGenerator.cs" />
-    <Compile Include="Beatmaps\Patterns\Legacy\PatternType.cs" />
-    <Compile Include="Beatmaps\ManiaBeatmapConverter.cs" />
-    <Compile Include="Beatmaps\Patterns\Pattern.cs" />
-    <Compile Include="Configuration\ManiaConfigManager.cs" />
-    <Compile Include="MathUtils\FastRandom.cs" />
-    <Compile Include="Judgements\HoldNoteTailJudgement.cs" />
-    <Compile Include="Judgements\HoldNoteTickJudgement.cs" />
-    <Compile Include="Judgements\ManiaJudgement.cs" />
-    <Compile Include="ManiaDifficultyCalculator.cs" />
-    <Compile Include="Mods\IPlayfieldTypeMod.cs" />
-    <Compile Include="Mods\ManiaModMirror.cs" />
-    <Compile Include="Mods\ManiaKeyMod.cs" />
-    <Compile Include="Mods\ManiaModAutoplay.cs" />
-    <Compile Include="Mods\ManiaModDaycore.cs" />
-    <Compile Include="Mods\ManiaModDoubleTime.cs" />
-    <Compile Include="Mods\ManiaModEasy.cs" />
-    <Compile Include="Mods\ManiaModFadeIn.cs" />
-    <Compile Include="Mods\ManiaModFlashlight.cs" />
-    <Compile Include="Mods\ManiaModHalfTime.cs" />
-    <Compile Include="Mods\ManiaModHardRock.cs" />
-    <Compile Include="Mods\ManiaModHidden.cs" />
-    <Compile Include="Mods\ManiaModKey1.cs" />
-    <Compile Include="Mods\ManiaModKey2.cs" />
-    <Compile Include="Mods\ManiaModKey3.cs" />
-    <Compile Include="Mods\ManiaModKey4.cs" />
-    <Compile Include="Mods\ManiaModKey5.cs" />
-    <Compile Include="Mods\ManiaModKey6.cs" />
-    <Compile Include="Mods\ManiaModKey7.cs" />
-    <Compile Include="Mods\ManiaModKey8.cs" />
-    <Compile Include="Mods\ManiaModKey9.cs" />
-    <Compile Include="Mods\ManiaModDualStages.cs" />
-    <Compile Include="Mods\ManiaModNightcore.cs" />
-    <Compile Include="Mods\ManiaModPerfect.cs" />
-    <Compile Include="Mods\ManiaModRandom.cs" />
-    <Compile Include="Mods\ManiaModSuddenDeath.cs" />
-    <Compile Include="Objects\Drawables\DrawableBarLine.cs" />
-    <Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
-    <Compile Include="Objects\Drawables\DrawableHoldNoteTick.cs" />
-    <Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
-    <Compile Include="Objects\Drawables\DrawableNote.cs" />
-    <Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\LaneGlowPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\NotePiece.cs" />
-    <Compile Include="Objects\ManiaHitObjectDifficulty.cs" />
-    <Compile Include="Objects\Types\IHasColumn.cs" />
-    <Compile Include="Replays\ManiaAutoGenerator.cs" />
-    <Compile Include="Replays\ManiaFramedReplayInputHandler.cs" />
-    <Compile Include="Replays\ManiaReplayFrame.cs" />
-    <Compile Include="Scoring\ManiaScoreProcessor.cs" />
-    <Compile Include="Objects\BarLine.cs" />
-    <Compile Include="Objects\HoldNote.cs" />
-    <Compile Include="Objects\HoldNoteTick.cs" />
-    <Compile Include="Objects\ManiaHitObject.cs" />
-    <Compile Include="Objects\Note.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="ManiaInputManager.cs" />
-    <Compile Include="Tests\ManiaBeatmapConversionTest.cs" />
-    <Compile Include="Tests\TestCaseAutoGeneration.cs" />
-    <Compile Include="Tests\TestCaseManiaHitObjects.cs" />
-    <Compile Include="Tests\TestCaseManiaPlayfield.cs" />
-    <Compile Include="Tests\TestCasePerformancePoints.cs" />
-    <Compile Include="UI\Column.cs" />
-    <Compile Include="UI\DrawableManiaJudgement.cs" />
-    <Compile Include="UI\ManiaStage.cs" />
-    <Compile Include="UI\HitExplosion.cs" />
-    <Compile Include="UI\ManiaRulesetContainer.cs" />
-    <Compile Include="UI\ManiaPlayfield.cs" />
-    <Compile Include="ManiaRuleset.cs" />
-    <Compile Include="Mods\ManiaModNoFail.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="OpenTK.dll.config" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
-      <Name>osu.Framework</Name>
-      <Private>True</Private>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game\osu.Game.csproj">
-      <Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
-      <Name>osu.Game</Name>
-      <Private>True</Private>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
-  </Target>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <OutputType>Library</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <Description>smash the keys. to the beat.</Description>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/packages.config b/osu.Game.Rulesets.Mania/packages.config
deleted file mode 100644
index 7a784f5293..0000000000
--- a/osu.Game.Rulesets.Mania/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
-  <package id="NUnit" version="3.8.1" targetFramework="net461" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json
new file mode 100644
index 0000000000..24431eb8de
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json
@@ -0,0 +1,59 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "VisualTests (Debug, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Debug, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Osu.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Osu.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json
new file mode 100644
index 0000000000..734e15353b
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json
@@ -0,0 +1,87 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "Build (Debug, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Osu.Tests.csproj",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Osu.Tests.csproj",
+                "/p:Configuration=Release",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Debug, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Osu.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Osu.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:Configuration=Release",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Restore (net461)",
+            "type": "shell",
+            "command": "nuget",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        },
+        {
+            "label": "Restore (netcoreapp2.0)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu/Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/OsuBeatmapConversionTest.cs
rename to osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseEditor.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseEditor.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseGameplayCursor.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircleHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleHidden.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseHitCircleHidden.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleHidden.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSliderHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderHidden.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseSliderHidden.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseSliderHidden.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs
diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinnerHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerHidden.cs
similarity index 100%
rename from osu.Game.Rulesets.Osu/Tests/TestCaseSpinnerHidden.cs
rename to osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerHidden.cs
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
new file mode 100644
index 0000000000..b2b524a71c
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.TestProject.props" />
+  <PropertyGroup Label="Project">
+    <OutputType>WinExe</OutputType>
+    <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs
index 74c3585d3d..29bf3e248d 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs
@@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Osu.Mods
     public class OsuModHardRock : ModHardRock, IApplicableToHitObject<OsuHitObject>
     {
         public override double ScoreMultiplier => 1.06;
+        public override bool Ranked => true;
 
         public void ApplyToHitObject(OsuHitObject hitObject)
         {
diff --git a/osu.Game.Rulesets.Osu/OpenTK.dll.config b/osu.Game.Rulesets.Osu/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Game.Rulesets.Osu/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs
index 18b3a007c1..7532646a32 100644
--- a/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs
@@ -1,28 +1,12 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using System.Reflection;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using osu.Framework.Testing;
 
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu.Game.Mode.Osu")]
-[assembly: AssemblyDescription("click the circles. to the beat.")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ppy Pty Ltd")]
-[assembly: AssemblyProduct("osu.Game.Mode.Osu")]
-[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+// 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".
 
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("c92a607b-1fdd-4954-9f92-03ff547d9080")]
-
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests")]
+[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
index dedfa28b7b..3203df16e2 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
@@ -131,6 +131,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
             {
                 Trace.Assert(lastPosition.HasValue);
 
+                // ReSharper disable once PossibleInvalidOperationException
                 Vector2 pos1 = lastPosition.Value;
                 Vector2 diff = pos2 - pos1;
                 float distance = diff.Length;
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 98a8096678..0c5d757474 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -55,8 +55,6 @@ namespace osu.Game.Rulesets.Osu.UI
 
         public override void Add(DrawableHitObject h)
         {
-            h.Depth = (float)h.HitObject.StartTime;
-
             h.OnJudgement += onJudgement;
 
             var c = h as IDrawableHitObjectWithProxiedApproach;
diff --git a/osu.Game.Rulesets.Osu/app.config b/osu.Game.Rulesets.Osu/app.config
deleted file mode 100644
index c9d4e44b1a..0000000000
--- a/osu.Game.Rulesets.Osu/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
index 8b7383b6b7..b0ca314551 100644
--- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
+++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
@@ -1,198 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{C92A607B-1FDD-4954-9F92-03FF547D9080}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Game.Rulesets.Osu</RootNamespace>
-    <AssemblyName>osu.Game.Rulesets.Osu</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <TargetFrameworkProfile />
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Drawing" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Beatmaps\OsuBeatmapConverter.cs" />
-    <Compile Include="Beatmaps\OsuBeatmapProcessor.cs" />
-    <Compile Include="Edit\Layers\Selection\Overlays\HitCircleMask.cs" />
-    <Compile Include="Edit\Layers\Selection\Overlays\SliderCircleMask.cs" />
-    <Compile Include="Edit\Layers\Selection\Overlays\SliderMask.cs" />
-    <Compile Include="Edit\OsuEditPlayfield.cs" />
-    <Compile Include="Edit\OsuEditRulesetContainer.cs" />
-    <Compile Include="Edit\OsuHitObjectComposer.cs" />
-    <Compile Include="Judgements\OsuSliderTailJudgement.cs" />
-    <Compile Include="Mods\OsuModAutopilot.cs" />
-    <Compile Include="Mods\OsuModAutoplay.cs" />
-    <Compile Include="Mods\OsuModDaycore.cs" />
-    <Compile Include="Mods\OsuModDoubleTime.cs" />
-    <Compile Include="Mods\OsuModEasy.cs" />
-    <Compile Include="Mods\OsuModFlashlight.cs" />
-    <Compile Include="Mods\OsuModHalfTime.cs" />
-    <Compile Include="Mods\OsuModHardRock.cs" />
-    <Compile Include="Mods\OsuModHidden.cs" />
-    <Compile Include="Mods\OsuModNightcore.cs" />
-    <Compile Include="Mods\OsuModPerfect.cs" />
-    <Compile Include="Mods\OsuModRelax.cs" />
-    <Compile Include="Mods\OsuModSpunOut.cs" />
-    <Compile Include="Mods\OsuModSuddenDeath.cs" />
-    <Compile Include="Mods\OsuModTarget.cs" />
-    <Compile Include="Objects\Drawables\DrawableSliderHead.cs" />
-    <Compile Include="Objects\Drawables\DrawableOsuHitObject.cs" />
-    <Compile Include="Objects\Drawables\Connections\ConnectionRenderer.cs" />
-    <Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
-    <Compile Include="Judgements\OsuJudgement.cs" />
-    <Compile Include="Objects\Drawables\DrawableRepeatPoint.cs" />
-    <Compile Include="Objects\Drawables\DrawableSliderTail.cs" />
-    <Compile Include="Objects\Drawables\IRequireTracking.cs" />
-    <Compile Include="Objects\Drawables\ITrackSnaking.cs" />
-    <Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
-    <Compile Include="Objects\Drawables\Pieces\DefaultCirclePiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
-    <Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
-    <Compile Include="Objects\Drawables\DrawableSlider.cs" />
-    <Compile Include="Objects\Drawables\Connections\FollowPoint.cs" />
-    <Compile Include="Objects\Drawables\DrawableSpinner.cs" />
-    <Compile Include="Objects\Drawables\Pieces\ExplodePiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\FlashPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" />
-    <Compile Include="Objects\Drawables\DrawableOsuJudgement.cs" />
-    <Compile Include="Objects\Drawables\Pieces\NumberPiece.cs" />
-    <Compile Include="Objects\Drawables\DrawableSliderTick.cs" />
-    <Compile Include="Objects\Drawables\Pieces\RingPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SpinnerDisc.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SpinnerSpmCounter.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SpinnerTicks.cs" />
-    <Compile Include="Objects\Drawables\Pieces\TrianglesPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SliderBall.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SliderBody.cs" />
-    <Compile Include="Objects\ISliderProgress.cs" />
-    <Compile Include="Objects\RepeatPoint.cs" />
-    <Compile Include="Objects\SliderCircle.cs" />
-    <Compile Include="Objects\SliderTick.cs" />
-    <Compile Include="OsuDifficulty\OsuDifficultyCalculator.cs" />
-    <Compile Include="OsuDifficulty\Preprocessing\OsuDifficultyBeatmap.cs" />
-    <Compile Include="OsuDifficulty\Preprocessing\OsuDifficultyHitObject.cs" />
-    <Compile Include="OsuDifficulty\Skills\Aim.cs" />
-    <Compile Include="OsuDifficulty\Skills\Skill.cs" />
-    <Compile Include="OsuDifficulty\Skills\Speed.cs" />
-    <Compile Include="OsuDifficulty\Utils\History.cs" />
-    <Compile Include="OsuInputManager.cs" />
-    <Compile Include="Replays\OsuReplayFrame.cs" />
-    <Compile Include="Replays\OsuReplayInputHandler.cs" />
-    <Compile Include="Tests\OsuBeatmapConversionTest.cs" />
-    <Compile Include="Tests\TestCaseEditor.cs" />
-    <Compile Include="Tests\TestCaseGameplayCursor.cs" />
-    <Compile Include="Tests\TestCaseHitCircle.cs" />
-    <Compile Include="Tests\TestCaseHitCircleHidden.cs" />
-    <Compile Include="Tests\TestCasePerformancePoints.cs" />
-    <Compile Include="Tests\TestCaseSlider.cs" />
-    <Compile Include="Tests\TestCaseSliderHidden.cs" />
-    <Compile Include="Tests\TestCaseSpinner.cs" />
-    <Compile Include="Tests\TestCaseSpinnerHidden.cs" />
-    <Compile Include="UI\Cursor\CursorTrail.cs" />
-    <Compile Include="UI\Cursor\GameplayCursor.cs" />
-    <Compile Include="UI\OsuSettings.cs" />
-    <Compile Include="Scoring\OsuPerformanceCalculator.cs" />
-    <Compile Include="Scoring\OsuScoreProcessor.cs" />
-    <Compile Include="UI\OsuRulesetContainer.cs" />
-    <Compile Include="UI\OsuPlayfield.cs" />
-    <Compile Include="OsuRuleset.cs" />
-    <Compile Include="Objects\HitCircle.cs" />
-    <Compile Include="Objects\Drawables\DrawableHitCircle.cs" />
-    <Compile Include="Objects\OsuHitObject.cs" />
-    <Compile Include="Objects\Slider.cs" />
-    <Compile Include="Objects\Spinner.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Mods\OsuModNoFail.cs" />
-    <Compile Include="Replays\OsuAutoGenerator.cs" />
-    <Compile Include="Replays\OsuAutoGeneratorBase.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="OpenTK.dll.config" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
-      <Name>osu.Framework</Name>
-      <Private>True</Private>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game\osu.Game.csproj">
-      <Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
-      <Name>osu.Game</Name>
-      <Private>True</Private>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\colinear-perfect-curve-expected-conversion.json" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\colinear-perfect-curve.osu" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
-  </Target>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <OutputType>Library</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <Description>click the circles. to the beat.</Description>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu/packages.config b/osu.Game.Rulesets.Osu/packages.config
deleted file mode 100644
index 7a784f5293..0000000000
--- a/osu.Game.Rulesets.Osu/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
-  <package id="NUnit" version="3.8.1" targetFramework="net461" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json b/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json
new file mode 100644
index 0000000000..caa90c32ce
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json
@@ -0,0 +1,59 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "VisualTests (Debug, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, net461)",
+            "windows": {
+                "type": "clr"
+            },
+            "type": "mono",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe",
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, msbuild)",
+            "runtimeExecutable": null,
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Debug, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Taiko.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Debug, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        },
+        {
+            "name": "VisualTests (Release, netcoreapp2.0)",
+            "type": "coreclr",
+            "request": "launch",
+            "program": "dotnet",
+            "args": [
+                "${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Taiko.Tests.dll"
+            ],
+            "cwd": "${workspaceRoot}",
+            "preLaunchTask": "Build (Release, dotnet)",
+            "env": {},
+            "console": "internalConsole"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json
new file mode 100644
index 0000000000..13044e1ccb
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json
@@ -0,0 +1,87 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "Build (Debug, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Taiko.Tests.csproj",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, msbuild)",
+            "type": "shell",
+            "command": "msbuild",
+            "args": [
+                "osu.Game.Rulesets.Taiko.Tests.csproj",
+                "/p:Configuration=Release",
+                "/p:TargetFramework=net461",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Debug, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Taiko.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Build (Release, dotnet)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "--no-restore",
+                "osu.Game.Rulesets.Taiko.Tests.csproj",
+                "/p:TargetFramework=netcoreapp2.0",
+                "/p:Configuration=Release",
+                "/p:GenerateFullPaths=true",
+                "/m",
+                "/verbosity:m"
+            ],
+            "group": "build",
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "Restore (net461)",
+            "type": "shell",
+            "command": "nuget",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        },
+        {
+            "label": "Restore (netcoreapp2.0)",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "restore"
+            ],
+            "problemMatcher": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs
similarity index 100%
rename from osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs
rename to osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs
diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/TestCaseInputDrum.cs
similarity index 100%
rename from osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs
rename to osu.Game.Rulesets.Taiko.Tests/TestCaseInputDrum.cs
diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs
similarity index 100%
rename from osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs
rename to osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs
diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestCaseTaikoPlayfield.cs
similarity index 100%
rename from osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs
rename to osu.Game.Rulesets.Taiko.Tests/TestCaseTaikoPlayfield.cs
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
new file mode 100644
index 0000000000..df73fa61cb
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.TestProject.props" />
+  <PropertyGroup Label="Project">
+    <OutputType>WinExe</OutputType>
+    <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs
index 435a0c1613..ba304c41d8 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs
@@ -8,5 +8,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
     public class TaikoModHardRock : ModHardRock
     {
         public override double ScoreMultiplier => 1.06;
+        public override bool Ranked => true;
     }
 }
diff --git a/osu.Game.Rulesets.Taiko/OpenTK.dll.config b/osu.Game.Rulesets.Taiko/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Game.Rulesets.Taiko/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs
index 9a7d5618c1..b7ed9f86b0 100644
--- a/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs
@@ -1,28 +1,12 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using System.Reflection;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using osu.Framework.Testing;
 
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu.Game.Rulesets.Taiko")]
-[assembly: AssemblyDescription("bash the drum. to the beat.")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ppy Pty Ltd")]
-[assembly: AssemblyProduct("osu.Game.Rulesets.Taiko")]
-[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+// 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".
 
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("f167e17a-7de6-4af5-b920-a5112296c695")]
-
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Taiko.Tests")]
+[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index 75aaceaecb..effb9eb54f 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -208,8 +208,6 @@ namespace osu.Game.Rulesets.Taiko.UI
 
         public override void Add(DrawableHitObject h)
         {
-            h.Depth = (float)h.HitObject.StartTime;
-
             h.OnJudgement += OnJudgement;
 
             base.Add(h);
diff --git a/osu.Game.Rulesets.Taiko/app.config b/osu.Game.Rulesets.Taiko/app.config
deleted file mode 100644
index c9d4e44b1a..0000000000
--- a/osu.Game.Rulesets.Taiko/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index 8f0aa88e62..002d6a7e8d 100644
--- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
+++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
@@ -1,167 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{F167E17A-7DE6-4AF5-B920-A5112296C695}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Game.Rulesets.Taiko</RootNamespace>
-    <AssemblyName>osu.Game.Rulesets.Taiko</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Audio\DrumSampleMapping.cs" />
-    <Compile Include="Beatmaps\TaikoBeatmapConverter.cs" />
-    <Compile Include="Judgements\TaikoDrumRollTickJudgement.cs" />
-    <Compile Include="Judgements\TaikoStrongHitJudgement.cs" />
-    <Compile Include="Judgements\TaikoJudgement.cs" />
-    <Compile Include="Mods\TaikoModAutoplay.cs" />
-    <Compile Include="Mods\TaikoModDaycore.cs" />
-    <Compile Include="Mods\TaikoModDoubleTime.cs" />
-    <Compile Include="Mods\TaikoModEasy.cs" />
-    <Compile Include="Mods\TaikoModFlashlight.cs" />
-    <Compile Include="Mods\TaikoModHalfTime.cs" />
-    <Compile Include="Mods\TaikoModHardRock.cs" />
-    <Compile Include="Mods\TaikoModHidden.cs" />
-    <Compile Include="Mods\TaikoModNightcore.cs" />
-    <Compile Include="Mods\TaikoModPerfect.cs" />
-    <Compile Include="Mods\TaikoModRelax.cs" />
-    <Compile Include="Mods\TaikoModSuddenDeath.cs" />
-    <Compile Include="Objects\BarLine.cs" />
-    <Compile Include="Objects\Drawables\DrawableBarLine.cs" />
-    <Compile Include="Objects\Drawables\DrawableBarLineMajor.cs" />
-    <Compile Include="Objects\CentreHit.cs" />
-    <Compile Include="Objects\Drawables\DrawableRimHit.cs" />
-    <Compile Include="Objects\Drawables\DrawableRimHitStrong.cs" />
-    <Compile Include="Objects\Drawables\DrawableCentreHit.cs" />
-    <Compile Include="Objects\Drawables\DrawableHit.cs" />
-    <Compile Include="Objects\Drawables\DrawableCentreHitStrong.cs" />
-    <Compile Include="Objects\Drawables\DrawableHitStrong.cs" />
-    <Compile Include="Objects\Drawables\Pieces\ElongatedCirclePiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\CentreHitSymbolPiece.cs" />
-    <Compile Include="Objects\Drawables\DrawableDrumRoll.cs" />
-    <Compile Include="Objects\Drawables\DrawableDrumRollTick.cs" />
-    <Compile Include="Objects\Drawables\DrawableSwell.cs" />
-    <Compile Include="Objects\Drawables\DrawableTaikoHitObject.cs" />
-    <Compile Include="Objects\Drawables\Pieces\RimHitSymbolPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\SwellSymbolPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\TaikoPiece.cs" />
-    <Compile Include="Objects\Drawables\Pieces\TickPiece.cs" />
-    <Compile Include="Objects\DrumRoll.cs" />
-    <Compile Include="Objects\DrumRollTick.cs" />
-    <Compile Include="Objects\Hit.cs" />
-    <Compile Include="Objects\RimHit.cs" />
-    <Compile Include="Objects\Swell.cs" />
-    <Compile Include="Replays\TaikoFramedReplayInputHandler.cs" />
-    <Compile Include="Replays\TaikoAutoGenerator.cs" />
-    <Compile Include="Objects\TaikoHitObject.cs" />
-    <Compile Include="Objects\TaikoHitObjectDifficulty.cs" />
-    <Compile Include="Replays\TaikoReplayFrame.cs" />
-    <Compile Include="TaikoDifficultyCalculator.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Scoring\TaikoScoreProcessor.cs" />
-    <Compile Include="TaikoInputManager.cs" />
-    <Compile Include="Tests\TaikoBeatmapConversionTest.cs" />
-    <Compile Include="Tests\TestCaseInputDrum.cs" />
-    <Compile Include="Tests\TestCasePerformancePoints.cs" />
-    <Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
-    <Compile Include="UI\HitTarget.cs" />
-    <Compile Include="UI\InputDrum.cs" />
-    <Compile Include="UI\KiaiHitExplosion.cs" />
-    <Compile Include="UI\DrawableTaikoJudgement.cs" />
-    <Compile Include="UI\HitExplosion.cs" />
-    <Compile Include="UI\TaikoRulesetContainer.cs" />
-    <Compile Include="UI\TaikoPlayfield.cs" />
-    <Compile Include="TaikoRuleset.cs" />
-    <Compile Include="Mods\TaikoModNoFail.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="OpenTK.dll.config" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
-      <Name>osu.Framework</Name>
-      <Private>True</Private>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game\osu.Game.csproj">
-      <Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
-      <Name>osu.Game</Name>
-      <Private>True</Private>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\slider-generating-drumroll-expected-conversion.json" />
-    <EmbeddedResource Include="Resources\Testing\Beatmaps\slider-generating-drumroll.osu" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
-  </Target>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <OutputType>Library</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <Description>bash the drum. to the beat.</Description>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/packages.config b/osu.Game.Rulesets.Taiko/packages.config
deleted file mode 100644
index 7a784f5293..0000000000
--- a/osu.Game.Rulesets.Taiko/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
-  <package id="NUnit" version="3.8.1" targetFramework="net461" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 6428881b54..4f5eae85c8 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Tests.Beatmaps.IO
     [TestFixture]
     public class ImportBeatmapTest
     {
-        private const string osz_path = @"../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
+        private const string osz_path = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
 
         [Test]
         public void TestImportWhenClosed()
diff --git a/osu.Game.Tests/OpenTK.dll.config b/osu.Game.Tests/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Game.Tests/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs
index d9aedb7a5f..6605c61026 100644
--- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs
+++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs
@@ -52,6 +52,7 @@ namespace osu.Game.Tests.Visual
                         FavouriteCount = 356,
                         Submitted = new DateTime(2016, 2, 10),
                         Ranked = new DateTime(2016, 6, 19),
+                        Status = BeatmapSetOnlineStatus.Ranked,
                         BPM = 236,
                         HasVideo = true,
                         Covers = new BeatmapSetOnlineCovers
@@ -222,6 +223,7 @@ namespace osu.Game.Tests.Visual
                         FavouriteCount = 58,
                         Submitted = new DateTime(2016, 6, 11),
                         Ranked = new DateTime(2016, 7, 12),
+                        Status = BeatmapSetOnlineStatus.Pending,
                         BPM = 160,
                         HasVideo = false,
                         Covers = new BeatmapSetOnlineCovers
diff --git a/osu.Game.Tests/app.config b/osu.Game.Tests/app.config
deleted file mode 100644
index 2f5b13a89d..0000000000
--- a/osu.Game.Tests/app.config
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index e85bbd6f10..2646e953cf 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -1,200 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{54377672-20B1-40AF-8087-5CF73BF3953A}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <RootNamespace>osu.Game.Tests</RootNamespace>
-    <AssemblyName>osu.Game.Tests</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="DeepEqual, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null">
-      <HintPath>$(SolutionDir)\packages\DeepEqual.1.6.0.0\lib\net40\DeepEqual.dll</HintPath>
-    </Reference>
-    <Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
-      <HintPath>$(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="packages.config" />
-    <None Include="OpenTK.dll.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
-      <Name>osu.Framework</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
-      <Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
-      <Name>osu.Game.Rulesets.Osu</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
-      <Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
-      <Name>osu.Game.Rulesets.Catch</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
-      <Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
-      <Name>osu.Game.Rulesets.Mania</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
-      <Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
-      <Name>osu.Game.Rulesets.Taiko</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu.Game\osu.Game.csproj">
-      <Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
-      <Name>osu.Game</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
-      <Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
-      <Name>osu.Game.Resources</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Beatmaps\Formats\OsuJsonDecoderTest.cs" />
-    <Compile Include="Beatmaps\Formats\LegacyStoryboardDecoderTest.cs" />
-    <Compile Include="Beatmaps\IO\OszArchiveReaderTest.cs" />
-    <Compile Include="Beatmaps\IO\ImportBeatmapTest.cs" />
-    <Compile Include="Chat\MessageFormatterTests.cs" />
-    <Compile Include="Resources\Resource.cs" />
-    <Compile Include="Beatmaps\Formats\LegacyBeatmapDecoderTest.cs" />
-    <Compile Include="Visual\TestCaseBeatmapCarousel.cs" />
-    <Compile Include="Visual\TestCaseBeatmapDetailArea.cs" />
-    <Compile Include="Visual\TestCaseBeatmapDetails.cs" />
-    <Compile Include="Visual\TestCaseBeatmapInfoWedge.cs" />
-    <Compile Include="Visual\TestCaseBeatmapOptionsOverlay.cs" />
-    <Compile Include="Visual\TestCaseBeatmapScoresContainer.cs" />
-    <Compile Include="Visual\TestCaseBeatmapSetOverlay.cs" />
-    <Compile Include="Visual\TestCaseBeatDivisorControl.cs" />
-    <Compile Include="Visual\TestCaseBeatSyncedContainer.cs" />
-    <Compile Include="Visual\TestCaseBreadcrumbs.cs" />
-    <Compile Include="Visual\TestCaseBreakOverlay.cs" />
-    <Compile Include="Visual\TestCaseChatDisplay.cs" />
-    <Compile Include="Visual\TestCaseContextMenu.cs" />
-    <Compile Include="Visual\TestCaseCursors.cs" />
-    <Compile Include="Visual\TestCaseDialogOverlay.cs" />
-    <Compile Include="Visual\TestCaseDirect.cs" />
-    <Compile Include="Visual\TestCaseDrawableRoom.cs" />
-    <Compile Include="Visual\TestCaseDrawings.cs" />
-    <Compile Include="Visual\TestCaseEditorCompose.cs" />
-    <Compile Include="Visual\TestCaseEditorComposeRadioButtons.cs" />
-    <Compile Include="Visual\TestCaseEditorComposeTimeline.cs" />
-    <Compile Include="Visual\TestCaseEditorMenuBar.cs" />
-    <Compile Include="Visual\TestCaseEditorSeekSnapping.cs" />
-    <Compile Include="Visual\TestCaseEditorSummaryTimeline.cs" />
-    <Compile Include="Visual\TestCaseEditorSelectionLayer.cs" />
-    <Compile Include="Visual\TestCaseGamefield.cs" />
-    <Compile Include="Visual\TestCaseGraph.cs" />
-    <Compile Include="Visual\TestCaseHistoricalSection.cs" />
-    <Compile Include="Visual\TestCaseIconButton.cs" />
-    <Compile Include="Visual\TestCaseIntroSequence.cs" />
-    <Compile Include="Visual\TestCaseKeyConfiguration.cs" />
-    <Compile Include="Visual\TestCaseKeyCounter.cs" />
-    <Compile Include="Visual\TestCaseLeaderboard.cs" />
-    <Compile Include="Visual\TestCaseMedalOverlay.cs" />
-    <Compile Include="Visual\TestCaseButtonSystem.cs" />
-    <Compile Include="Visual\TestCaseGameplayMenuOverlay.cs" />
-    <Compile Include="Visual\TestCaseMods.cs" />
-    <Compile Include="Visual\TestCaseMusicController.cs" />
-    <Compile Include="Visual\TestCaseNotificationOverlay.cs" />
-    <Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
-    <Compile Include="Visual\TestCaseAllPlayers.cs" />
-    <Compile Include="Visual\TestCaseOsuGame.cs" />
-    <Compile Include="Visual\TestCaseChatLink.cs" />
-    <Compile Include="Visual\TestCasePlaybackControl.cs" />
-    <Compile Include="Visual\TestCasePlaySongSelect.cs" />
-    <Compile Include="Visual\TestCasePopupDialog.cs" />
-    <Compile Include="Visual\TestCaseRankGraph.cs" />
-    <Compile Include="Visual\TestCaseAutoplay.cs" />
-    <Compile Include="Visual\TestCaseReplay.cs" />
-    <Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
-    <Compile Include="Visual\TestCaseResults.cs" />
-    <Compile Include="Visual\TestCaseRoomInspector.cs" />
-    <Compile Include="Visual\TestCaseScoreCounter.cs" />
-    <Compile Include="Visual\TestCaseScrollingHitObjects.cs" />
-    <Compile Include="Visual\TestCaseSettings.cs" />
-    <Compile Include="Visual\TestCaseSkipButton.cs" />
-    <Compile Include="Visual\TestCaseSocial.cs" />
-    <Compile Include="Visual\TestCaseSongProgress.cs" />
-    <Compile Include="Visual\TestCaseStoryboard.cs" />
-    <Compile Include="Visual\TestCaseTabControl.cs" />
-    <Compile Include="Visual\TestCaseTextAwesome.cs" />
-    <Compile Include="Visual\TestCaseToolbar.cs" />
-    <Compile Include="Visual\TestCaseTwoLayerButton.cs" />
-    <Compile Include="Visual\TestCaseUserPanel.cs" />
-    <Compile Include="Visual\TestCaseUserProfile.cs" />
-    <Compile Include="Visual\TestCaseUserProfileRecentSection.cs" />
-    <Compile Include="Visual\TestCaseUserRanks.cs" />
-    <Compile Include="Visual\TestCaseVolumePieces.cs" />
-    <Compile Include="Visual\TestCaseWaveform.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources\Soleily - Renatus %28Gamu%29 [Insane].osu" />
-    <EmbeddedResource Include="Resources\Himeringo - Yotsuya-san ni Yoroshiku %28RLC%29 [Winber1%27s Extreme].osu" />
-    <EmbeddedResource Include="Resources\Within Temptation - The Unforgiving %28Armin%29 [Marathon].osu" />
-    <EmbeddedResource Include="Resources\Kozato snow - Rengetsu Ouka %28_Kiva%29 [Yuki YukI].osu" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
-    <Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
-  </Target>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.TestProject.props" />
+  <PropertyGroup Label="Project">
+    <OutputType>WinExe</OutputType>
+    <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
+  </PropertyGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
+    <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config
deleted file mode 100644
index a3b983e3ef..0000000000
--- a/osu.Game.Tests/packages.config
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
--->
-<packages>
-  <package id="DeepEqual" version="1.6.0.0" targetFramework="net461" />
-  <package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
-  <package id="NUnit" version="3.8.1" targetFramework="net461" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-  <package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.Game.props b/osu.Game.props
index 60a5e97944..87edafb97f 100644
--- a/osu.Game.props
+++ b/osu.Game.props
@@ -1,7 +1,5 @@
 <!-- Contains required properties for osu!framework projects. -->
-<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(SolutionDir)\packages\Microsoft.Net.Compilers.2.3.2\build\Microsoft.Net.Compilers.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Net.Compilers.2.3.2\build\Microsoft.Net.Compilers.props')" />
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project>
   <PropertyGroup Label="C#">
     <LangVersion>7</LangVersion>
   </PropertyGroup>
@@ -10,4 +8,14 @@
       <Link>osu.licenseheader</Link>
     </None>
   </ItemGroup>
+  <ItemGroup Label="Resources">
+    <EmbeddedResource Include="Resources\**\*.*" />
+  </ItemGroup>
+  <PropertyGroup Label="Project">
+    <Company>ppy Pty Ltd</Company>
+    <Copyright>ppy Pty Ltd 2007-2018</Copyright>
+    <!-- DeepEqual is not netstandard-compatible. This is fine since we run tests with .NET Framework anyway.
+    This is required due to https://github.com/NuGet/Home/issues/5740 -->
+    <NoWarn>NU1701</NoWarn>
+  </PropertyGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
index be3107c7b9..f7221a6ac3 100644
--- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
@@ -26,6 +26,11 @@ namespace osu.Game.Beatmaps
         /// </summary>
         public DateTimeOffset? LastUpdated { get; set; }
 
+        /// <summary>
+        /// The status of this beatmap set.
+        /// </summary>
+        public BeatmapSetOnlineStatus Status { get; set; }
+
         /// <summary>
         /// Whether or not this beatmap set has a background video.
         /// </summary>
diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs b/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs
new file mode 100644
index 0000000000..c7f767d3b2
--- /dev/null
+++ b/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs
@@ -0,0 +1,17 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Beatmaps
+{
+    public enum BeatmapSetOnlineStatus
+    {
+        None = -3,
+        Graveyard = -2,
+        WIP = -1,
+        Pending = 0,
+        Ranked = 1,
+        Approved = 2,
+        Qualified = 3,
+        Loved = 4,
+    }
+}
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs
new file mode 100644
index 0000000000..8ea7a538f9
--- /dev/null
+++ b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs
@@ -0,0 +1,54 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.Sprites;
+using OpenTK.Graphics;
+
+namespace osu.Game.Beatmaps.Drawables
+{
+    public class BeatmapSetOnlineStatusPill : CircularContainer
+    {
+        private readonly OsuSpriteText statusText;
+
+        private BeatmapSetOnlineStatus status = BeatmapSetOnlineStatus.None;
+        public BeatmapSetOnlineStatus Status
+        {
+            get { return status; }
+            set
+            {
+                if (value == status) return;
+                status = value;
+
+                statusText.Text = Enum.GetName(typeof(BeatmapSetOnlineStatus), Status)?.ToUpper();
+            }
+        }
+
+        public BeatmapSetOnlineStatusPill(float textSize, MarginPadding textPadding)
+        {
+            AutoSizeAxes = Axes.Both;
+            Masking = true;
+
+            Children = new Drawable[]
+            {
+                new Box
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Colour = Color4.Black,
+                    Alpha = 0.5f,
+                },
+                statusText = new OsuSpriteText
+                {
+                    Anchor = Anchor.Centre,
+                    Origin = Anchor.Centre,
+                    Font = @"Exo2.0-Bold",
+                    TextSize = textSize,
+                    Padding = textPadding,
+                },
+            };
+        }
+    }
+}
diff --git a/osu.Game/Beatmaps/IBeatmapConverter.cs b/osu.Game/Beatmaps/IBeatmapConverter.cs
index ebd900b97e..096ba345a1 100644
--- a/osu.Game/Beatmaps/IBeatmapConverter.cs
+++ b/osu.Game/Beatmaps/IBeatmapConverter.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps
         /// <summary>
         /// Converts a Beatmap using this Beatmap Converter.
         /// </summary>
-        /// <param name="original">The un-converted Beatmap.</param>
+        /// <param name="beatmap">The un-converted Beatmap.</param>
         void Convert(Beatmap beatmap);
     }
 }
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index f0e67a7185..7050e34712 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -5,7 +5,6 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using Ionic.Zip;
 using Microsoft.EntityFrameworkCore;
 using osu.Framework.Logging;
 using osu.Framework.Platform;
@@ -13,6 +12,7 @@ using osu.Game.IO;
 using osu.Game.IO.Archives;
 using osu.Game.IPC;
 using osu.Game.Overlays.Notifications;
+using osu.Game.Utils;
 using SharpCompress.Common;
 using FileInfo = osu.Game.IO.FileInfo;
 
@@ -336,7 +336,7 @@ namespace osu.Game.Database
         /// <returns>A reader giving access to the archive's content.</returns>
         private ArchiveReader getReaderFrom(string path)
         {
-            if (ZipFile.IsZipFile(path))
+            if (ZipUtils.IsZipArchive(path))
                 return new ZipArchiveReader(Files.Storage.GetStream(path), Path.GetFileName(path));
             if (Directory.Exists(path))
                 return new LegacyFilesystemReader(path);
diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs
index 0fafb77339..4b582bdfea 100644
--- a/osu.Game/Database/DatabaseBackedStore.cs
+++ b/osu.Game/Database/DatabaseBackedStore.cs
@@ -11,9 +11,6 @@ namespace osu.Game.Database
     {
         protected readonly Storage Storage;
 
-        /// <summary>
-        /// Create a new <see cref="OsuDbContext"/> instance (separate from the shared context via <see cref="GetContext"/> for performing isolated operations.
-        /// </summary>
         protected readonly IDatabaseContextFactory ContextFactory;
 
         /// <summary>
diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs
index 712ed2d0cc..06737e61eb 100644
--- a/osu.Game/Database/DatabaseContextFactory.cs
+++ b/osu.Game/Database/DatabaseContextFactory.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Database
         private readonly object writeLock = new object();
 
         private bool currentWriteDidWrite;
-        private volatile int currentWriteUsages;
+        private int currentWriteUsages;
 
         public DatabaseContextFactory(GameHost host)
         {
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 0de6279b2e..bdee7d289d 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -33,6 +33,7 @@ namespace osu.Game.Graphics.Cursor
 
                 // don't start rotating until we're moved a minimum distance away from the mouse down location,
                 // else it can have an annoying effect.
+                // ReSharper disable once PossibleInvalidOperationException
                 startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30;
 
                 if (startRotation)
diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs
index a912f989e0..d2a7250aaa 100644
--- a/osu.Game/Graphics/DrawableDate.cs
+++ b/osu.Game/Graphics/DrawableDate.cs
@@ -6,7 +6,6 @@ using Humanizer;
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Cursor;
-using osu.Framework.Threading;
 using osu.Game.Graphics.Sprites;
 
 namespace osu.Game.Graphics
@@ -14,7 +13,6 @@ namespace osu.Game.Graphics
     public class DrawableDate : OsuSpriteText, IHasTooltip
     {
         private readonly DateTimeOffset date;
-        private ScheduledDelegate updateTask;
 
         public DrawableDate(DateTimeOffset date)
         {
@@ -61,6 +59,7 @@ namespace osu.Game.Graphics
         public override bool HandleMouseInput => true;
 
         private void updateTime() => Text = date.Humanize();
+
         public string TooltipText => date.ToString();
     }
 }
diff --git a/osu.Game/IO/Archives/ZipArchiveReader.cs b/osu.Game/IO/Archives/ZipArchiveReader.cs
index a772382b5e..dbf236e835 100644
--- a/osu.Game/IO/Archives/ZipArchiveReader.cs
+++ b/osu.Game/IO/Archives/ZipArchiveReader.cs
@@ -4,32 +4,32 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using Ionic.Zip;
+using SharpCompress.Archives.Zip;
 
 namespace osu.Game.IO.Archives
 {
     public sealed class ZipArchiveReader : ArchiveReader
     {
         private readonly Stream archiveStream;
-        private readonly ZipFile archive;
+        private readonly ZipArchive archive;
 
         public ZipArchiveReader(Stream archiveStream, string name = null)
             : base(name)
         {
             this.archiveStream = archiveStream;
-            archive = ZipFile.Read(archiveStream);
+            archive = ZipArchive.Open(archiveStream);
         }
 
         public override Stream GetStream(string name)
         {
-            ZipEntry entry = archive.Entries.SingleOrDefault(e => e.FileName == name);
+            ZipArchiveEntry entry = archive.Entries.SingleOrDefault(e => e.Key == name);
             if (entry == null)
                 throw new FileNotFoundException();
 
             // allow seeking
             MemoryStream copy = new MemoryStream();
 
-            using (Stream s = entry.OpenReader())
+            using (Stream s = entry.OpenEntryStream())
                 s.CopyTo(copy);
 
             copy.Position = 0;
@@ -43,7 +43,7 @@ namespace osu.Game.IO.Archives
             archiveStream.Dispose();
         }
 
-        public override IEnumerable<string> Filenames => archive.Entries.Select(e => e.FileName).ToArray();
+        public override IEnumerable<string> Filenames => archive.Entries.Select(e => e.Key).ToArray();
 
         public override Stream GetUnderlyingStream() => archiveStream;
     }
diff --git a/osu.Game/IO/Legacy/SerializationReader.cs b/osu.Game/IO/Legacy/SerializationReader.cs
index aaea22d31b..75cbef80a5 100644
--- a/osu.Game/IO/Legacy/SerializationReader.cs
+++ b/osu.Game/IO/Legacy/SerializationReader.cs
@@ -7,7 +7,6 @@ using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 using System.Runtime.Serialization;
-using System.Runtime.Serialization.Formatters;
 using System.Runtime.Serialization.Formatters.Binary;
 using System.Text;
 
@@ -175,7 +174,7 @@ namespace osu.Game.IO.Legacy
                 versionBinder = new VersionConfigToNamespaceAssemblyObjectBinder();
                 formatter = new BinaryFormatter
                 {
-                    AssemblyFormat = FormatterAssemblyStyle.Simple,
+//                    AssemblyFormat = FormatterAssemblyStyle.Simple,
                     Binder = versionBinder
                 };
             }
@@ -187,6 +186,7 @@ namespace osu.Game.IO.Legacy
 
                 Debug.Assert(formatter != null, "formatter != null");
 
+                // ReSharper disable once PossibleNullReferenceException
                 return formatter.Deserialize(stream);
             }
 
diff --git a/osu.Game/IO/Legacy/SerializationWriter.cs b/osu.Game/IO/Legacy/SerializationWriter.cs
index 5c2d00dca6..f972796383 100644
--- a/osu.Game/IO/Legacy/SerializationWriter.cs
+++ b/osu.Game/IO/Legacy/SerializationWriter.cs
@@ -219,7 +219,7 @@ namespace osu.Game.IO.Legacy
                         Write((byte)ObjType.otherType);
                         BinaryFormatter b = new BinaryFormatter
                         {
-                            AssemblyFormat = FormatterAssemblyStyle.Simple,
+//                            AssemblyFormat = FormatterAssemblyStyle.Simple,
                             TypeFormat = FormatterTypeStyle.TypesWhenNeeded
                         };
                         b.Serialize(BaseStream, obj);
diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.cs b/osu.Game/Migrations/20171019041408_InitialCreate.cs
index 23e5b6f8bb..922aa85f18 100644
--- a/osu.Game/Migrations/20171019041408_InitialCreate.cs
+++ b/osu.Game/Migrations/20171019041408_InitialCreate.cs
@@ -1,6 +1,4 @@
 using Microsoft.EntityFrameworkCore.Migrations;
-using System;
-using System.Collections.Generic;
 
 namespace osu.Game.Migrations
 {
diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs
index a20652eedc..ad8884a4bf 100644
--- a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs
+++ b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs
@@ -1,6 +1,4 @@
 using Microsoft.EntityFrameworkCore.Migrations;
-using System;
-using System.Collections.Generic;
 
 namespace osu.Game.Migrations
 {
diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
index 1627627790..b16b9fdefa 100644
--- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
+++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
@@ -1,11 +1,7 @@
 // <auto-generated />
 using Microsoft.EntityFrameworkCore;
 using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage;
 using osu.Game.Database;
-using System;
 
 namespace osu.Game.Migrations
 {
diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs
index 957aeac3cd..798ed1b9b3 100644
--- a/osu.Game/Online/API/APIAccess.cs
+++ b/osu.Game/Online/API/APIAccess.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Online.API
 
         private readonly List<IOnlineComponent> components = new List<IOnlineComponent>();
 
-        internal void Schedule(Action action) => base.Schedule(action);
+        internal new void Schedule(Action action) => base.Schedule(action);
 
         public void Register(IOnlineComponent component)
         {
diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs
index a59875809e..df8af7b8dc 100644
--- a/osu.Game/Online/API/OAuth.cs
+++ b/osu.Game/Online/API/OAuth.cs
@@ -96,6 +96,7 @@ namespace osu.Game.Online.API
 
                 // if not, let's try using our refresh token to request a new access token.
                 if (!string.IsNullOrEmpty(Token?.RefreshToken))
+                    // ReSharper disable once PossibleNullReferenceException
                     AuthenticateWithRefresh(Token.RefreshToken);
 
                 return accessTokenValid;
diff --git a/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs b/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs
index 8f011b4df7..28376a1b4f 100644
--- a/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs
@@ -30,6 +30,9 @@ namespace osu.Game.Online.API.Requests
         [JsonProperty(@"video")]
         private bool hasVideo { get; set; }
 
+        [JsonProperty(@"status")]
+        private BeatmapSetOnlineStatus status { get; set; }
+
         [JsonProperty(@"submitted_date")]
         private DateTimeOffset submitted { get; set; }
 
@@ -60,6 +63,7 @@ namespace osu.Game.Online.API.Requests
                     PlayCount = playCount,
                     FavouriteCount = favouriteCount,
                     BPM = bpm,
+                    Status = status,
                     HasVideo = hasVideo,
                     Submitted = submitted,
                     Ranked = ranked,
diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs
index 2e24b1eea4..70468c557a 100644
--- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs
@@ -19,6 +19,7 @@ namespace osu.Game.Online.API.Requests
             this.type = type;
         }
 
+        // ReSharper disable once ImpureMethodCallOnReadonlyValueField
         protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}";
     }
 
diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs
index 65d50bc88a..7bdd1a94b9 100644
--- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs
@@ -18,6 +18,7 @@ namespace osu.Game.Online.API.Requests
             this.offset = offset;
         }
 
+        // ReSharper disable once ImpureMethodCallOnReadonlyValueField
         protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLower()}?offset={offset}";
     }
 
diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs
index d674bcde8e..c54d0ea556 100644
--- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs
+++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs
@@ -27,6 +27,7 @@ namespace osu.Game.Online.API.Requests
             this.direction = direction;
         }
 
+        // ReSharper disable once ImpureMethodCallOnReadonlyValueField
         protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={(int)rankStatus}&sort={sortCriteria.ToString().ToLower()}_{directionString}";
     }
 }
diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs
index 99735c4d65..df3753da6a 100644
--- a/osu.Game/Online/Chat/Message.cs
+++ b/osu.Game/Online/Chat/Message.cs
@@ -69,6 +69,7 @@ namespace osu.Game.Online.Chat
 
         public virtual bool Equals(Message other) => Id == other?.Id;
 
+        // ReSharper disable once ImpureMethodCallOnReadonlyValueField
         public override int GetHashCode() => Id.GetHashCode();
     }
 
diff --git a/osu.Game/OpenTK.dll.config b/osu.Game/OpenTK.dll.config
deleted file mode 100644
index 5620e3d9e2..0000000000
--- a/osu.Game/OpenTK.dll.config
+++ /dev/null
@@ -1,25 +0,0 @@
-<configuration>
-  <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
-  <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
-  <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
-  <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
-  <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
-  <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
-  <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
-  <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
-  <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
-  <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
-  <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
-  <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
-  <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
-  <!-- XQuartz compatibility (X11 on Mac) -->
-  <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
-  <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
-  <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
-  <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
-  <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
-  <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
-</configuration>
diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs
index 3ce0dfee31..b9a35ec1f0 100644
--- a/osu.Game/Overlays/BeatmapSet/Header.cs
+++ b/osu.Game/Overlays/BeatmapSet/Header.cs
@@ -30,6 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet
         private readonly FillFlowContainer videoButtons;
         private readonly AuthorInfo author;
         private readonly Container downloadButtonsContainer;
+        private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
         public Details Details;
 
         private BeatmapManager beatmaps;
@@ -50,6 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet
                 Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet;
                 title.Text = BeatmapSet.Metadata.Title;
                 artist.Text = BeatmapSet.Metadata.Artist;
+                onlineStatusPill.Status = BeatmapSet.OnlineInfo.Status;
 
                 downloadButtonsContainer.FadeIn();
                 noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration);
@@ -204,11 +206,23 @@ namespace osu.Game.Overlays.BeatmapSet
                                 },
                             },
                         },
-                        Details = new Details
+                        new FillFlowContainer
                         {
                             Anchor = Anchor.BottomRight,
                             Origin = Anchor.BottomRight,
+                            AutoSizeAxes = Axes.Both,
                             Margin = new MarginPadding { Right = BeatmapSetOverlay.X_PADDING },
+                            Direction = FillDirection.Vertical,
+                            Spacing = new Vector2(10),
+                            Children = new Drawable[]
+                            {
+                                onlineStatusPill = new BeatmapSetOnlineStatusPill(14, new MarginPadding { Horizontal = 25, Vertical = 8 })
+                                {
+                                    Anchor = Anchor.TopRight,
+                                    Origin = Anchor.TopRight,
+                                },
+                                Details = new Details(),
+                            },
                         },
                     },
                 },
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index 7c6e563c5b..210f5ce01e 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -210,6 +210,7 @@ namespace osu.Game.Overlays
             {
                 Trace.Assert(state.Mouse.PositionMouseDown != null);
 
+                // ReSharper disable once PossibleInvalidOperationException
                 double targetChatHeight = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
 
                 // If the channel selection screen is shown, mind its minimum height
@@ -383,6 +384,7 @@ namespace osu.Game.Overlays
         {
             if (channel == null) return;
 
+            // ReSharper disable once AccessToModifiedClosure
             var existing = careChannels.Find(c => c.Id == channel.Id);
 
             if (existing != null)
diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs
index 2cc51f9e4c..d893c027c7 100644
--- a/osu.Game/Overlays/Direct/DirectGridPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs
@@ -11,7 +11,9 @@ using osu.Framework.Localisation;
 using osu.Game.Graphics;
 using osu.Game.Graphics.Sprites;
 using osu.Framework.Graphics.Shapes;
+using osu.Framework.Input;
 using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Drawables;
 
 namespace osu.Game.Overlays.Direct
 {
@@ -20,7 +22,7 @@ namespace osu.Game.Overlays.Direct
         private const float horizontal_padding = 10;
         private const float vertical_padding = 5;
 
-        private FillFlowContainer bottomPanel;
+        private FillFlowContainer bottomPanel, statusContainer;
         private PlayButton playButton;
         private Box progressBar;
 
@@ -199,7 +201,37 @@ namespace osu.Game.Overlays.Direct
                     Size = new Vector2(30),
                     Alpha = 0,
                 },
+                statusContainer = new FillFlowContainer
+                {
+                    AutoSizeAxes = Axes.Both,
+                    Margin = new MarginPadding { Top = 5, Left = 5 },
+                    Spacing = new Vector2(5),
+                },
             });
+
+            if (SetInfo.OnlineInfo?.HasVideo ?? false)
+            {
+                statusContainer.Add(new IconPill(FontAwesome.fa_film));
+            }
+
+            statusContainer.Add(new BeatmapSetOnlineStatusPill(12, new MarginPadding { Horizontal = 10, Vertical = 5 })
+            {
+                Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None,
+            });
+        }
+
+        protected override bool OnHover(InputState state)
+        {
+            statusContainer.FadeOut(120, Easing.InOutQuint);
+
+            return base.OnHover(state);
+        }
+
+        protected override void OnHoverLost(InputState state)
+        {
+            base.OnHoverLost(state);
+
+            statusContainer.FadeIn(120, Easing.InOutQuint);
         }
     }
 }
diff --git a/osu.Game/Overlays/Direct/IconPill.cs b/osu.Game/Overlays/Direct/IconPill.cs
new file mode 100644
index 0000000000..33b67bdf13
--- /dev/null
+++ b/osu.Game/Overlays/Direct/IconPill.cs
@@ -0,0 +1,43 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Overlays.Direct
+{
+    public class IconPill : CircularContainer
+    {
+        public IconPill(FontAwesome icon)
+        {
+            AutoSizeAxes = Axes.Both;
+            Masking = true;
+
+            Children = new Drawable[]
+            {
+                new Box
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Colour = Color4.Black,
+                    Alpha = 0.5f,
+                },
+                new Container
+                {
+                    AutoSizeAxes = Axes.Both,
+                    Margin = new MarginPadding(5),
+                    Child = new SpriteIcon
+                    {
+                        Anchor = Anchor.Centre,
+                        Origin = Anchor.Centre,
+                        Icon = icon,
+                        Size = new Vector2(12),
+                    },
+                },
+            };
+        }
+    }
+}
diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs
index f71dc30de4..896ffc33f6 100644
--- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs
+++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs
@@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
         {
             private readonly OsuSpriteText valueText;
 
-            public int Count
+            public new int Count
             {
                 set { valueText.Text = value.ToString(); }
             }
diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
index 4a4fc7363e..2d07704853 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
@@ -5,7 +5,6 @@ using System;
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Primitives;
 using osu.Framework.Graphics.UserInterface;
 using osu.Game.Configuration;
 using osu.Game.Graphics.Sprites;
@@ -18,7 +17,7 @@ using System.ComponentModel;
 using osu.Game.Graphics;
 using OpenTK.Graphics;
 using osu.Framework.Extensions.Color4Extensions;
-
+using RectangleF = osu.Framework.Graphics.Primitives.RectangleF;
 using Container = osu.Framework.Graphics.Containers.Container;
 
 namespace osu.Game.Overlays.Settings.Sections.General
diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs
index 7cbf0ea559..a4c35204f4 100644
--- a/osu.Game/Overlays/Settings/SidebarButton.cs
+++ b/osu.Game/Overlays/Settings/SidebarButton.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Settings
         private readonly SpriteText headerText;
         private readonly Box selectionIndicator;
         private readonly Container text;
-        public Action<SettingsSection> Action;
+        public new Action<SettingsSection> Action;
 
         private SettingsSection section;
         public SettingsSection Section
diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs b/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs
index 158912e7fe..ba015119a0 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs
@@ -4,8 +4,8 @@
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Primitives;
 using OpenTK;
+using RectangleF = osu.Framework.Graphics.Primitives.RectangleF;
 
 namespace osu.Game.Overlays.Toolbar
 {
diff --git a/osu.Game/Properties/AssemblyInfo.cs b/osu.Game/Properties/AssemblyInfo.cs
deleted file mode 100644
index 56558044f8..0000000000
--- a/osu.Game/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("osu.Game")]
-[assembly: AssemblyDescription("click the circles. to the beat.")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ppy Pty Ltd")]
-[assembly: AssemblyProduct("osu.Game")]
-[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")]
-
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs
index 0f0c43bc88..ca203e1cdb 100644
--- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs
+++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs
@@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Judgements
         /// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
         /// </summary>
         /// <param name="judgement">The judgement to visualise.</param>
+        /// <param name="judgedObject">The object which was judged.</param>
         public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject)
         {
             Judgement = judgement;
diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs
index c998bc123f..c4c0f38faf 100644
--- a/osu.Game/Rulesets/Mods/ModHardRock.cs
+++ b/osu.Game/Rulesets/Mods/ModHardRock.cs
@@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Mods
         public override FontAwesome Icon => FontAwesome.fa_osu_mod_hardrock;
         public override ModType Type => ModType.DifficultyIncrease;
         public override string Description => "Everything just got a bit harder...";
-        public override bool Ranked => true;
         public override Type[] IncompatibleMods => new[] { typeof(ModEasy) };
 
         public void ApplyToDifficulty(BeatmapDifficulty difficulty)
diff --git a/osu.Game/Rulesets/Replays/Types/IConvertibleReplayFrame.cs b/osu.Game/Rulesets/Replays/Types/IConvertibleReplayFrame.cs
index ac1e5e29ec..892f5ca2fe 100644
--- a/osu.Game/Rulesets/Replays/Types/IConvertibleReplayFrame.cs
+++ b/osu.Game/Rulesets/Replays/Types/IConvertibleReplayFrame.cs
@@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Replays.Types
         /// Populates this <see cref="ReplayFrame"/> using values from a <see cref="LegacyReplayFrame"/>.
         /// </summary>
         /// <param name="legacyFrame">The <see cref="LegacyReplayFrame"/> to extract values from.</param>
-        /// <param name="score">The score.</param>
         /// <param name="beatmap">The beatmap.</param>
         void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap);
     }
diff --git a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs
index 6c37a9e9a6..450b5da7b8 100644
--- a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs
+++ b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs
@@ -60,6 +60,7 @@ namespace osu.Game.Rulesets.Timing
             DifficultyPoint = other.DifficultyPoint;
         }
 
+        // ReSharper disable once ImpureMethodCallOnReadonlyValueField
         public int CompareTo(MultiplierControlPoint other) => StartTime.CompareTo(other?.StartTime);
     }
 }
diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs
index c26a6cdff0..ecb10dfba2 100644
--- a/osu.Game/Rulesets/UI/HitObjectContainer.cs
+++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs
@@ -3,6 +3,7 @@
 
 using System.Collections.Generic;
 using System.Linq;
+using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Game.Rulesets.Objects.Drawables;
 
@@ -15,5 +16,15 @@ namespace osu.Game.Rulesets.UI
 
         public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject);
         public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject);
+
+        protected override int Compare(Drawable x, Drawable y)
+        {
+            if (!(x is DrawableHitObject xObj) || !(y is DrawableHitObject yObj))
+                return base.Compare(x, y);
+
+            // Put earlier hitobjects towards the end of the list, so they handle input first
+            int i = yObj.HitObject.StartTime.CompareTo(xObj.HitObject.StartTime);
+            return i == 0 ? CompareReverseChildID(x, y) : i;
+        }
     }
 }
diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs
index 780bc5c86b..2201b6963f 100644
--- a/osu.Game/Rulesets/UI/RulesetContainer.cs
+++ b/osu.Game/Rulesets/UI/RulesetContainer.cs
@@ -214,6 +214,7 @@ namespace osu.Game.Rulesets.UI
 
             WorkingBeatmap = workingBeatmap;
             IsForCurrentRuleset = isForCurrentRuleset;
+            // ReSharper disable once PossibleNullReferenceException
             Mods = workingBeatmap.Mods.Value;
 
             RelativeSizeAxes = Axes.Both;
diff --git a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs
index a7be3c1eb5..0b30aeef8d 100644
--- a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs
+++ b/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs
@@ -24,7 +24,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose
     public class BeatDivisorControl : CompositeDrawable
     {
         private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
-        private int currentDivisorIndex;
 
         public BeatDivisorControl(BindableBeatDivisor beatDivisor)
         {
diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionLayer.cs
index 8c66007bb7..ab51385980 100644
--- a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionLayer.cs
+++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionLayer.cs
@@ -14,6 +14,7 @@ using osu.Game.Rulesets.Objects.Drawables;
 using osu.Game.Rulesets.UI;
 using OpenTK;
 using OpenTK.Graphics;
+using RectangleF = osu.Framework.Graphics.Primitives.RectangleF;
 
 namespace osu.Game.Screens.Edit.Screens.Compose.Layers
 {
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index b0472f0e0d..93b36e48b9 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -83,12 +83,19 @@ namespace osu.Game.Screens.Play
         private void load(AudioManager audio, APIAccess api, OsuConfigManager config)
         {
             this.api = api;
+
+            WorkingBeatmap working = Beatmap.Value;
+            if (working is DummyWorkingBeatmap)
+            {
+                Exit();
+                return;
+            }
+
             sampleRestart = audio.Sample.Get(@"Gameplay/restart");
 
             mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
             userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
 
-            WorkingBeatmap working = Beatmap.Value;
             Beatmap beatmap;
 
             try
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index aed8fb110f..15f4d5cf96 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -547,6 +547,7 @@ namespace osu.Game.Screens.Select
 
                             float? setY = null;
                             if (!d.IsLoaded || beatmap.Alpha == 0) // can't use IsPresent due to DrawableCarouselItem override.
+                                // ReSharper disable once PossibleNullReferenceException (resharper broken?)
                                 setY = lastSet.Y + lastSet.DrawHeight + 5;
 
                             if (d.IsLoaded)
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index 7476df4955..8e045b9fb7 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -268,6 +268,7 @@ namespace osu.Game.Screens.Select
                     new OsuSpriteText
                     {
                         Font = @"Exo2.0-Bold",
+                        // ReSharper disable once PossibleNullReferenceException (resharper broken?)
                         Text = metadata.Author.Username,
                         TextSize = 15,
                     }
diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
index ac3d5df533..de01b846c2 100644
--- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
@@ -68,6 +68,7 @@ namespace osu.Game.Screens.Select.Leaderboards
                             Origin = Anchor.CentreLeft,
                             Font = @"Exo2.0-MediumItalic",
                             TextSize = 22,
+                            // ReSharper disable once ImpureMethodCallOnReadonlyValueField
                             Text = RankPosition.ToString(),
                         },
                     },
diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs
index 09524d2eac..d5a91e1a6b 100644
--- a/osu.Game/Screens/Select/PlaySongSelect.cs
+++ b/osu.Game/Screens/Select/PlaySongSelect.cs
@@ -3,6 +3,7 @@
 
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading.Tasks;
 using OpenTK.Input;
 using osu.Framework.Allocation;
 using osu.Framework.Audio;
@@ -75,7 +76,8 @@ namespace osu.Game.Screens.Select
                 {
                     // if we have no beatmaps but osu-stable is found, let's prompt the user to import.
                     if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable)
-                        dialogOverlay.Push(new ImportFromStablePopup(() => beatmaps.ImportFromStable()));
+                        dialogOverlay.Push(new ImportFromStablePopup(() =>
+                            Task.Factory.StartNew(beatmaps.ImportFromStable, TaskCreationOptions.LongRunning)));
                 });
             }
         }
diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs
index 498dd7de6f..201c02ca05 100644
--- a/osu.Game/Screens/Tournament/Drawings.cs
+++ b/osu.Game/Screens/Tournament/Drawings.cs
@@ -326,6 +326,7 @@ namespace osu.Game.Screens.Tournament
                             if (line.ToUpper().StartsWith("GROUP"))
                                 continue;
 
+                            // ReSharper disable once AccessToModifiedClosure
                             DrawingsTeam teamToAdd = allTeams.FirstOrDefault(t => t.FullName == line);
 
                             if (teamToAdd == null)
diff --git a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
index 4c97ab47b4..008e4d759f 100644
--- a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
+++ b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
@@ -13,9 +13,9 @@ using osu.Framework.Graphics.Shapes;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Graphics.Textures;
 using osu.Framework.Threading;
+using osu.Game.Screens.Tournament.Teams;
 using OpenTK;
 using OpenTK.Graphics;
-using osu.Game.Screens.Tournament.Teams;
 
 namespace osu.Game.Screens.Tournament
 {
@@ -118,16 +118,18 @@ namespace osu.Game.Screens.Tournament
                         if (!Children.Any())
                             break;
 
-                        Drawable closest = null;
+                        ScrollingTeam closest = null;
 
                         foreach (var c in Children)
                         {
-                            if (!(c is ScrollingTeam))
+                            var stc = c as ScrollingTeam;
+
+                            if (stc == null)
                                 continue;
 
                             if (closest == null)
                             {
-                                closest = c;
+                                closest = stc;
                                 continue;
                             }
 
@@ -135,14 +137,15 @@ namespace osu.Game.Screens.Tournament
                             float lastOffset = Math.Abs(closest.Position.X + closest.DrawWidth / 2f - DrawWidth / 2f);
 
                             if (o < lastOffset)
-                                closest = c;
+                                closest = stc;
                         }
 
                         Trace.Assert(closest != null, "closest != null");
 
+                        // ReSharper disable once PossibleNullReferenceException
                         offset += DrawWidth / 2f - (closest.Position.X + closest.DrawWidth / 2f);
 
-                        ScrollingTeam st = closest as ScrollingTeam;
+                        ScrollingTeam st = closest;
 
                         availableTeams.RemoveAll(at => at == st.Team);
 
diff --git a/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs b/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs
index 5510111a2f..943e7d8cae 100644
--- a/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs
+++ b/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs
@@ -38,6 +38,7 @@ namespace osu.Game.Screens.Tournament.Teams
                             if (string.IsNullOrEmpty(line))
                                 continue;
 
+                            // ReSharper disable once PossibleNullReferenceException
                             string[] split = line.Split(':');
 
                             if (split.Length < 2)
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index 1b52507688..63d2543bc3 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -92,7 +92,7 @@ namespace osu.Game.Skinning
                 string lastPiece = filename.Split('/').Last();
 
                 var file = source.Files.FirstOrDefault(f =>
-                    string.Equals(hasExtension ? f.Filename : Path.GetFileNameWithoutExtension(f.Filename), lastPiece, StringComparison.InvariantCultureIgnoreCase));
+                    string.Equals(hasExtension ? f.Filename : Path.ChangeExtension(f.Filename, null), lastPiece, StringComparison.InvariantCultureIgnoreCase));
                 return file?.FileInfo.StoragePath;
             }
 
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index f965a77cce..24d7155b53 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -80,8 +80,6 @@ namespace osu.Game.Skinning
             return new LegacySkin(skinInfo, Files.Store, audio);
         }
 
-        private SkinStore store;
-
         public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio)
             : base(storage, contextFactory, new SkinStore(contextFactory, storage), importHost)
         {
diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs
index 36f33e746a..5007a9d325 100644
--- a/osu.Game/Skinning/SkinReloadableDrawable.cs
+++ b/osu.Game/Skinning/SkinReloadableDrawable.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Skinning
         /// <summary>
         /// Create a new <see cref="SkinReloadableDrawable"/>
         /// </summary>
-        /// <param name="fallback">Whether fallback to default skin should be allowed if the custom skin is missing this resource.</param>
+        /// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
         protected SkinReloadableDrawable(Func<ISkinSource, bool> allowFallback = null)
         {
             this.allowFallback = allowFallback;
diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs
index 09d2e6a3ed..7ed796d433 100644
--- a/osu.Game/Skinning/SkinnableDrawable.cs
+++ b/osu.Game/Skinning/SkinnableDrawable.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Skinning
         /// </summary>
         /// <param name="name">The namespace-complete resource name for this skinnable element.</param>
         /// <param name="defaultImplementation">A function to create the default skin implementation of this element.</param>
-        /// <param name="fallback">Whther to fallback to the default implementation when a custom skin is specified but not implementation is present.</param>
+        /// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
         /// <param name="restrictSize">Whether a user-skin drawable should be limited to the size of our parent.</param>
         public SkinnableDrawable(string name, Func<string, T> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true) : base(allowFallback)
         {
diff --git a/osu.Desktop/OsuTestBrowser.cs b/osu.Game/Tests/OsuTestBrowser.cs
similarity index 87%
rename from osu.Desktop/OsuTestBrowser.cs
rename to osu.Game/Tests/OsuTestBrowser.cs
index 7aae2604af..6d9b28b5a7 100644
--- a/osu.Desktop/OsuTestBrowser.cs
+++ b/osu.Game/Tests/OsuTestBrowser.cs
@@ -3,12 +3,11 @@
 
 using osu.Framework.Platform;
 using osu.Framework.Testing;
-using osu.Game;
 using osu.Game.Screens.Backgrounds;
 
-namespace osu.Desktop
+namespace osu.Game.Tests
 {
-    internal class OsuTestBrowser : OsuGameBase
+    public class OsuTestBrowser : OsuGameBase
     {
         protected override void LoadComplete()
         {
diff --git a/osu.Game/Tests/VisualTestRunner.cs b/osu.Game/Tests/VisualTestRunner.cs
new file mode 100644
index 0000000000..d8a4143368
--- /dev/null
+++ b/osu.Game/Tests/VisualTestRunner.cs
@@ -0,0 +1,22 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Framework;
+using osu.Framework.Platform;
+
+namespace osu.Game.Tests
+{
+    public static class VisualTestRunner
+    {
+        [STAThread]
+        public static int Main(string[] args)
+        {
+            using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+            {
+                host.Run(new OsuTestBrowser());
+                return 0;
+            }
+        }
+    }
+}
diff --git a/osu.Game/Utils/ZipUtils.cs b/osu.Game/Utils/ZipUtils.cs
new file mode 100644
index 0000000000..ad22359c20
--- /dev/null
+++ b/osu.Game/Utils/ZipUtils.cs
@@ -0,0 +1,33 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using SharpCompress.Archives.Zip;
+
+namespace osu.Game.Utils
+{
+    public static class ZipUtils
+    {
+        public static bool IsZipArchive(string path)
+        {
+            try
+            {
+                using (var arc = ZipArchive.Open(path))
+                {
+                    foreach (var entry in arc.Entries)
+                    {
+                        using (entry.OpenEntryStream())
+                        {
+                        }
+                    }
+                }
+
+                return true;
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+        }
+    }
+}
diff --git a/osu.Game/app.config b/osu.Game/app.config
deleted file mode 100644
index 7f2ad68041..0000000000
--- a/osu.Game/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index ab058d90d9..367c3490d6 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -1,970 +1,26 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
-  <Import Project="..\osu.Game.props" />
-  <PropertyGroup>
-    <ProjectGuid>{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}</ProjectGuid>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>osu.Game</RootNamespace>
-    <AssemblyName>osu.Game</AssemblyName>
-    <ManifestCertificateThumbprint>3CF060CD28877D0E3112948951A64B2A7CEEC909</ManifestCertificateThumbprint>
-    <ManifestKeyFile>codesigning.pfx</ManifestKeyFile>
-    <GenerateManifests>false</GenerateManifests>
-    <SignManifests>false</SignManifests>
-    <IsWebBootstrapper>false</IsWebBootstrapper>
-    <FileUpgradeFlags>
-    </FileUpgradeFlags>
-    <OldToolsVersion>3.5</OldToolsVersion>
-    <UpgradeBackupLocation>
-    </UpgradeBackupLocation>
-    <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
-    <SignAssembly>false</SignAssembly>
-    <TargetZone>LocalIntranet</TargetZone>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-    <PublishUrl>publish\</PublishUrl>
-    <Install>true</Install>
-    <InstallFrom>Disk</InstallFrom>
-    <UpdateEnabled>false</UpdateEnabled>
-    <UpdateMode>Foreground</UpdateMode>
-    <UpdateInterval>7</UpdateInterval>
-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
-    <UpdatePeriodically>false</UpdatePeriodically>
-    <UpdateRequired>false</UpdateRequired>
-    <MapFileExtensions>true</MapFileExtensions>
-    <ApplicationRevision>2</ApplicationRevision>
-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
-    <UseApplicationTrust>false</UseApplicationTrust>
-    <BootstrapperEnabled>true</BootstrapperEnabled>
-    <ProductVersion>12.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <TargetFrameworkProfile>
-    </TargetFrameworkProfile>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>0</WarningLevel>
-    <NoStdLib>true</NoStdLib>
-    <UseVSHostingProcess>false</UseVSHostingProcess>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <RunCodeAnalysis>false</RunCodeAnalysis>
-    <Prefer32Bit>false</Prefer32Bit>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-    <Commandlineparameters>
-    </Commandlineparameters>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>
-    </DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <NoStdLib>true</NoStdLib>
-    <UseVSHostingProcess>false</UseVSHostingProcess>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <Prefer32Bit>false</Prefer32Bit>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-  </PropertyGroup>
-  <PropertyGroup>
-    <Win32Resource>
-    </Win32Resource>
-  </PropertyGroup>
-  <PropertyGroup />
-  <ItemGroup>
-    <Reference Include="DotNetZip, Version=1.10.1.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Humanizer, Version=2.2.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll</HintPath>
-    </Reference>
-    <Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Data.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.EntityFrameworkCore.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore.Design">
-      <HintPath>$(SolutionDir)\packages\Microsoft.EntityFrameworkCore.Design.2.0.0\lib\net461\Microsoft.EntityFrameworkCore.Design.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore.Relational, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.EntityFrameworkCore.Relational.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Caching.Abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Caching.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Caching.Memory, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Caching.Memory.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Configuration.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.DependencyInjection.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Logging.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Logging.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Options, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Options.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Primitives, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
-    </Reference>
-    <Reference Include="mscorlib" />
-    <Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
-    <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
-      <HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Remotion.Linq, Version=2.1.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\Remotion.Linq.2.1.2\lib\net45\Remotion.Linq.dll</HintPath>
-    </Reference>
-    <Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Collections.Immutable, Version=1.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ComponentModel.Composition" />
-    <Reference Include="System.ComponentModel.DataAnnotations" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.2.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Interactive.Async, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>$(SolutionDir)\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
-      <HintPath>$(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="OpenTK.dll.config" />
-    <None Include="osu!.res" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
-      <Install>true</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
-      <Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
-      <Name>osu.Framework</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
-      <Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
-      <Name>osu.Game.Resources</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Audio\SampleInfo.cs" />
-    <Compile Include="Beatmaps\Beatmap.cs" />
-    <Compile Include="Beatmaps\BeatmapConverter.cs" />
-    <Compile Include="Beatmaps\BeatmapDifficulty.cs" />
-    <Compile Include="Beatmaps\BeatmapInfo.cs" />
-    <Compile Include="Beatmaps\BeatmapManager.cs" />
-    <Compile Include="Beatmaps\BeatmapManager_WorkingBeatmap.cs" />
-    <Compile Include="Beatmaps\BeatmapMetadata.cs" />
-    <Compile Include="Beatmaps\BeatmapMetrics.cs" />
-    <Compile Include="Beatmaps\BeatmapOnlineInfo.cs" />
-    <Compile Include="Beatmaps\BeatmapProcessor.cs" />
-    <Compile Include="Beatmaps\BeatmapSetFileInfo.cs" />
-    <Compile Include="Beatmaps\BeatmapSetInfo.cs" />
-    <Compile Include="Beatmaps\BeatmapSetOnlineInfo.cs" />
-    <Compile Include="Beatmaps\BeatmapStatistic.cs" />
-    <Compile Include="Beatmaps\BeatmapStore.cs" />
-    <Compile Include="Beatmaps\ControlPoints\ControlPoint.cs" />
-    <Compile Include="Beatmaps\ControlPoints\ControlPointInfo.cs" />
-    <Compile Include="Beatmaps\ControlPoints\DifficultyControlPoint.cs" />
-    <Compile Include="Beatmaps\ControlPoints\EffectControlPoint.cs" />
-    <Compile Include="Beatmaps\ControlPoints\SampleControlPoint.cs" />
-    <Compile Include="Beatmaps\ControlPoints\TimingControlPoint.cs" />
-    <Compile Include="Beatmaps\DifficultyCalculator.cs" />
-    <Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
-    <Compile Include="Beatmaps\Drawables\BeatmapSetCover.cs" />
-    <Compile Include="Beatmaps\Formats\IHasComboColours.cs" />
-    <Compile Include="Beatmaps\Formats\IHasCustomColours.cs" />
-    <Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" />
-    <Compile Include="Beatmaps\Formats\LegacyDecoder.cs" />
-    <Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
-    <Compile Include="Beatmaps\IBeatmapConverter.cs" />
-    <Compile Include="Configuration\DatabasedSetting.cs" />
-    <Compile Include="Configuration\SettingsStore.cs" />
-    <Compile Include="Configuration\DatabasedConfigManager.cs" />
-    <Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
-    <Compile Include="Database\ArchiveModelManager.cs" />
-    <Compile Include="Database\DatabaseContextFactory.cs" />
-    <Compile Include="Database\DatabaseWriteUsage.cs" />
-    <Compile Include="Database\ICanAcceptFiles.cs" />
-    <Compile Include="Database\IDatabaseContextFactory.cs" />
-    <Compile Include="Database\IHasFiles.cs" />
-    <Compile Include="Database\IHasPrimaryKey.cs" />
-    <Compile Include="Database\INamedFileInfo.cs" />
-    <Compile Include="Database\ISoftDelete.cs" />
-    <Compile Include="Database\MutableDatabaseBackedStore.cs" />
-    <Compile Include="Database\SingletonContextFactory.cs" />
-    <Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
-    <Compile Include="Graphics\DrawableDate.cs" />
-    <Compile Include="Graphics\ScreenshotManager.cs" />
-    <Compile Include="Graphics\Textures\LargeTextureStore.cs" />
-    <Compile Include="IO\Archives\ArchiveReader.cs" />
-    <Compile Include="IO\Archives\LegacyFilesystemReader.cs" />
-    <Compile Include="IO\Archives\ZipArchiveReader.cs" />
-    <Compile Include="Online\API\DummyAPIAccess.cs" />
-    <Compile Include="Online\API\IAPIProvider.cs" />
-    <Compile Include="Online\API\APIDownloadRequest.cs" />
-    <Compile Include="Online\API\Requests\GetUserRecentActivitiesRequest.cs" />
-    <Compile Include="Online\API\Requests\GetUserRequest.cs" />
-    <Compile Include="Migrations\20180125143340_Settings.cs" />
-    <Compile Include="Migrations\20180125143340_Settings.Designer.cs">
-      <DependentUpon>20180125143340_Settings.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Migrations\20180131154205_AddMuteBinding.cs" />
-    <Compile Include="Overlays\Profile\Sections\Recent\DrawableRecentActivity.cs" />
-    <Compile Include="Overlays\Profile\Sections\Recent\MedalIcon.cs" />
-    <Compile Include="Overlays\Profile\Sections\Recent\PaginatedRecentActivityContainer.cs" />
-    <Compile Include="Overlays\Profile\SupporterIcon.cs" />
-    <Compile Include="Online\API\Requests\GetFriendsRequest.cs" />
-    <Compile Include="Overlays\Settings\DangerousSettingsButton.cs" />
-    <Compile Include="Graphics\UserInterface\HoverClickSounds.cs" />
-    <Compile Include="Graphics\UserInterface\HoverSounds.cs" />
-    <Compile Include="Graphics\UserInterface\OsuButton.cs" />
-    <Compile Include="IO\Serialization\KeyContractResolver.cs" />
-    <Compile Include="Migrations\20171019041408_InitialCreate.cs" />
-    <Compile Include="Migrations\20171019041408_InitialCreate.Designer.cs">
-      <DependentUpon>20171019041408_InitialCreate.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Migrations\20171025071459_AddMissingIndexRules.cs" />
-    <Compile Include="Migrations\20171025071459_AddMissingIndexRules.Designer.cs">
-      <DependentUpon>20171025071459_AddMissingIndexRules.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Migrations\20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs" />
-    <Compile Include="Migrations\20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs">
-      <DependentUpon>20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Migrations\20171209034410_AddRulesetInfoShortName.cs" />
-    <Compile Include="Migrations\20171209034410_AddRulesetInfoShortName.Designer.cs">
-      <DependentUpon>20171209034410_AddRulesetInfoShortName.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Migrations\20180219060912_AddSkins.cs" />
-    <Compile Include="Migrations\20180219060912_AddSkins.Designer.cs">
-      <DependentUpon>20180219060912_AddSkins.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Migrations\OsuDbContextModelSnapshot.cs" />
-    <Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" />
-    <Compile Include="Online\Chat\DrawableLinkCompiler.cs" />
-    <Compile Include="Online\Chat\MessageFormatter.cs" />
-    <Compile Include="Online\API\Requests\APIResponseBeatmapSet.cs" />
-    <Compile Include="Online\API\Requests\GetUserMostPlayedBeatmapsRequest.cs" />
-    <Compile Include="Overlays\BeatmapSet\Scores\ClickableUsername.cs" />
-    <Compile Include="Overlays\BeatmapSet\Scores\DrawableScore.cs" />
-    <Compile Include="Overlays\BeatmapSet\Scores\DrawableTopScore.cs" />
-    <Compile Include="Overlays\BeatmapSet\Scores\ScoresContainer.cs" />
-    <Compile Include="Online\API\Requests\GetUserBeatmapsRequest.cs" />
-    <Compile Include="Overlays\Profile\Sections\BeatmapMetadataContainer.cs" />
-    <Compile Include="Overlays\Profile\Sections\Beatmaps\PaginatedBeatmapContainer.cs" />
-    <Compile Include="Overlays\Profile\Sections\DrawableProfileRow.cs" />
-    <Compile Include="Overlays\Profile\Sections\Historical\DrawableMostPlayedRow.cs" />
-    <Compile Include="Overlays\Profile\Sections\Historical\PaginatedMostPlayedBeatmapContainer.cs" />
-    <Compile Include="Overlays\Profile\Sections\Kudosu\KudosuInfo.cs" />
-    <Compile Include="Overlays\Profile\Sections\PaginatedContainer.cs" />
-    <Compile Include="Overlays\Profile\Sections\Ranks\DrawablePerformanceScore.cs" />
-    <Compile Include="Overlays\Profile\Sections\Ranks\PaginatedScoreContainer.cs" />
-    <Compile Include="Overlays\Profile\Sections\Ranks\DrawableTotalScore.cs" />
-    <Compile Include="Overlays\Profile\Sections\Ranks\ScoreModsContainer.cs" />
-    <Compile Include="Overlays\Settings\Sections\Gameplay\ScrollingSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Maintenance\DeleteAllBeatmapsDialog.cs" />
-    <Compile Include="Overlays\VolumeOverlay.cs" />
-    <Compile Include="Overlays\Volume\MuteButton.cs" />
-    <Compile Include="Overlays\Volume\VolumeControlReceptor.cs" />
-    <Compile Include="Overlays\Volume\VolumeMeter.cs" />
-    <Compile Include="Rulesets\Configuration\IRulesetConfigManager.cs" />
-    <Compile Include="Rulesets\Configuration\RulesetConfigManager.cs" />
-    <Compile Include="Rulesets\Edit\HitObjectMask.cs" />
-    <Compile Include="Rulesets\Edit\Types\IHasEditablePosition.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableFailOverride.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableMod.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToBeatmapConverter.cs" />
-    <Compile Include="Overlays\Social\SocialGridPanel.cs" />
-    <Compile Include="Overlays\Social\SocialListPanel.cs" />
-    <Compile Include="Overlays\Social\SocialPanel.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToDrawableHitObject.cs" />
-    <Compile Include="Rulesets\Objects\HitWindows.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasComboInformation.cs" />
-    <Compile Include="Rulesets\Replays\Legacy\LegacyReplayFrame.cs" />
-    <Compile Include="Rulesets\Replays\Legacy\ReplayButtonState.cs" />
-    <Compile Include="Rulesets\Replays\ReplayFrame.cs" />
-    <Compile Include="Rulesets\Replays\Types\IConvertibleReplayFrame.cs" />
-    <Compile Include="Rulesets\Scoring\Legacy\LegacyScoreParser.cs" />
-    <Compile Include="Rulesets\UI\JudgementContainer.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\BindableBeatDivisor.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\BeatDivisorControl.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Layers\BorderLayer.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Layers\HitObjectMaskLayer.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Layers\SelectionBox.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Layers\SelectionLayer.cs" />
-    <Compile Include="Screens\Play\ScreenWithBeatmapBackground.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\VisualSettings.cs" />
-    <Compile Include="Rulesets\Objects\CatmullApproximator.cs" />
-    <Compile Include="Rulesets\UI\HitObjectContainer.cs" />
-    <Compile Include="Rulesets\UI\ScalableContainer.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\Visualisers\SequentialSpeedChangeVisualiser.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\Visualisers\ISpeedChangeVisualiser.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\Visualisers\OverlappingSpeedChangeVisualiser.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\ScrollingDirection.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\ScrollingHitObjectContainer.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\ScrollingPlayfield.cs" />
-    <Compile Include="Rulesets\UI\Scrolling\ScrollingRulesetContainer.cs" />
-    <Compile Include="Screens\Select\ImportFromStablePopup.cs" />
-    <Compile Include="Overlays\Settings\SettingsButton.cs" />
-    <Compile Include="Screens\Edit\Components\BottomBarContainer.cs" />
-    <Compile Include="Screens\Edit\Components\PlaybackControl.cs" />
-    <Compile Include="Screens\Edit\Components\TimeInfoContainer.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToScoreProcessor.cs" />
-    <Compile Include="Beatmaps\Drawables\DifficultyColouredContainer.cs" />
-    <Compile Include="Beatmaps\Drawables\DifficultyIcon.cs" />
-    <Compile Include="Beatmaps\DummyWorkingBeatmap.cs" />
-    <Compile Include="Beatmaps\Formats\Decoder.cs" />
-    <Compile Include="Beatmaps\Formats\LegacyBeatmapDecoder.cs" />
-    <Compile Include="Online\API\Requests\GetUserScoresRequest.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\RadioButtons\DrawableRadioButton.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\RadioButtons\RadioButton.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\RadioButtons\RadioButtonCollection.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Timeline\BeatmapWaveformGraph.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Timeline\TimelineButton.cs" />
-    <Compile Include="Screens\Play\Break\BreakArrows.cs" />
-    <Compile Include="Screens\Play\Break\BlurredIcon.cs" />
-    <Compile Include="Screens\Play\BreakOverlay.cs" />
-    <Compile Include="Screens\Play\Break\GlowIcon.cs" />
-    <Compile Include="Screens\Play\Break\BreakInfo.cs" />
-    <Compile Include="Screens\Play\Break\BreakInfoLine.cs" />
-    <Compile Include="Screens\Play\Break\LetterboxOverlay.cs" />
-    <Compile Include="Screens\Play\Break\RemainingTimeCounter.cs" />
-    <Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
-    <Compile Include="Beatmaps\RankStatus.cs" />
-    <Compile Include="Beatmaps\Timing\BreakPeriod.cs" />
-    <Compile Include="Beatmaps\Timing\TimeSignatures.cs" />
-    <Compile Include="Beatmaps\WorkingBeatmap.cs" />
-    <Compile Include="Configuration\OsuConfigManager.cs" />
-    <Compile Include="Configuration\RankingType.cs" />
-    <Compile Include="Configuration\ReleaseStream.cs" />
-    <Compile Include="Configuration\ScoreMeterType.cs" />
-    <Compile Include="Configuration\ScreenshotFormat.cs" />
-    <Compile Include="Configuration\RandomSelectAlgorithm.cs" />
-    <Compile Include="Database\DatabaseBackedStore.cs" />
-    <Compile Include="Database\OsuDbContext.cs" />
-    <Compile Include="Graphics\Backgrounds\Background.cs" />
-    <Compile Include="Graphics\Backgrounds\Triangles.cs" />
-    <Compile Include="Graphics\Containers\BeatSyncedContainer.cs" />
-    <Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" />
-    <Compile Include="Graphics\Containers\OsuClickableContainer.cs" />
-    <Compile Include="Graphics\Containers\OsuFocusedOverlayContainer.cs" />
-    <Compile Include="Graphics\Containers\OsuHoverContainer.cs" />
-    <Compile Include="Graphics\Containers\OsuScrollContainer.cs" />
-    <Compile Include="Graphics\Containers\OsuTextFlowContainer.cs" />
-    <Compile Include="Graphics\Containers\ParallaxContainer.cs" />
-    <Compile Include="Graphics\Containers\ReverseChildIDFillFlowContainer.cs" />
-    <Compile Include="Graphics\Containers\SectionsContainer.cs" />
-    <Compile Include="Graphics\Cursor\IProvideCursor.cs" />
-    <Compile Include="Graphics\Cursor\MenuCursor.cs" />
-    <Compile Include="Graphics\Cursor\OsuContextMenuContainer.cs" />
-    <Compile Include="Graphics\Cursor\CursorOverrideContainer.cs" />
-    <Compile Include="Graphics\Cursor\OsuTooltipContainer.cs" />
-    <Compile Include="Graphics\IHasAccentColour.cs" />
-    <Compile Include="Graphics\OsuColour.cs" />
-    <Compile Include="Graphics\SpriteIcon.cs" />
-    <Compile Include="Graphics\Sprites\OsuSpriteText.cs" />
-    <Compile Include="Graphics\UserInterface\BackButton.cs" />
-    <Compile Include="Graphics\UserInterface\Bar.cs" />
-    <Compile Include="Graphics\UserInterface\BarGraph.cs" />
-    <Compile Include="Graphics\UserInterface\BreadcrumbControl.cs" />
-    <Compile Include="Graphics\UserInterface\DialogButton.cs" />
-    <Compile Include="Graphics\UserInterface\FocusedTextBox.cs" />
-    <Compile Include="Graphics\UserInterface\IconButton.cs" />
-    <Compile Include="Graphics\UserInterface\LineGraph.cs" />
-    <Compile Include="Graphics\UserInterface\LoadingAnimation.cs" />
-    <Compile Include="Graphics\UserInterface\MenuItemType.cs" />
-    <Compile Include="Graphics\UserInterface\Nub.cs" />
-    <Compile Include="Graphics\UserInterface\TriangleButton.cs" />
-    <Compile Include="Graphics\UserInterface\OsuCheckbox.cs" />
-    <Compile Include="Graphics\UserInterface\OsuContextMenu.cs" />
-    <Compile Include="Graphics\UserInterface\OsuDropdown.cs" />
-    <Compile Include="Graphics\UserInterface\OsuEnumDropdown.cs" />
-    <Compile Include="Graphics\UserInterface\OsuMenu.cs" />
-    <Compile Include="Graphics\UserInterface\OsuMenuItem.cs" />
-    <Compile Include="Graphics\UserInterface\OsuPasswordTextBox.cs" />
-    <Compile Include="Graphics\UserInterface\OsuSliderBar.cs" />
-    <Compile Include="Graphics\UserInterface\OsuTabControl.cs" />
-    <Compile Include="Graphics\UserInterface\OsuTabControlCheckbox.cs" />
-    <Compile Include="Graphics\UserInterface\OsuTextBox.cs" />
-    <Compile Include="Graphics\UserInterface\PageTabControl.cs" />
-    <Compile Include="Graphics\UserInterface\PercentageCounter.cs" />
-    <Compile Include="Graphics\UserInterface\ProgressBar.cs" />
-    <Compile Include="Graphics\UserInterface\RollingCounter.cs" />
-    <Compile Include="Graphics\UserInterface\ScoreCounter.cs" />
-    <Compile Include="Graphics\UserInterface\SearchTextBox.cs" />
-    <Compile Include="Graphics\UserInterface\SimpleComboCounter.cs" />
-    <Compile Include="Graphics\UserInterface\StarCounter.cs" />
-    <Compile Include="Graphics\UserInterface\TwoLayerButton.cs" />
-    <Compile Include="Input\Bindings\DatabasedKeyBinding.cs" />
-    <Compile Include="Input\Bindings\DatabasedKeyBindingContainer.cs" />
-    <Compile Include="Input\Bindings\GlobalActionContainer.cs" />
-    <Compile Include="Input\Handlers\ReplayInputHandler.cs" />
-    <Compile Include="Input\KeyBindingStore.cs" />
-    <Compile Include="IO\FileInfo.cs" />
-    <Compile Include="IO\FileStore.cs" />
-    <Compile Include="IO\Legacy\ILegacySerializable.cs" />
-    <Compile Include="IO\Legacy\SerializationReader.cs" />
-    <Compile Include="IO\Legacy\SerializationWriter.cs" />
-    <Compile Include="IO\Serialization\Converters\TypedListConverter.cs" />
-    <Compile Include="IO\Serialization\Converters\Vector2Converter.cs" />
-    <Compile Include="IO\Serialization\IJsonSerializable.cs" />
-    <Compile Include="IPC\ArchiveImportIPCChannel.cs" />
-    <Compile Include="IPC\ScoreIPCChannel.cs" />
-    <Compile Include="Online\API\APIAccess.cs" />
-    <Compile Include="Online\API\APIRequest.cs" />
-    <Compile Include="Online\API\IOnlineComponent.cs" />
-    <Compile Include="Online\API\OAuth.cs" />
-    <Compile Include="Online\API\OAuthToken.cs" />
-    <Compile Include="Online\API\Requests\DownloadBeatmapSetRequest.cs" />
-    <Compile Include="Online\API\Requests\GetBeatmapDetailsRequest.cs" />
-    <Compile Include="Online\API\Requests\SearchBeatmapSetsRequest.cs" />
-    <Compile Include="Online\API\Requests\GetMessagesRequest.cs" />
-    <Compile Include="Online\API\Requests\GetScoresRequest.cs" />
-    <Compile Include="Online\API\Requests\GetUsersRequest.cs" />
-    <Compile Include="Online\API\Requests\ListChannelsRequest.cs" />
-    <Compile Include="Online\API\Requests\PostMessageRequest.cs" />
-    <Compile Include="Online\Chat\Channel.cs" />
-    <Compile Include="Online\Chat\ErrorMessage.cs" />
-    <Compile Include="Online\Chat\InfoMessage.cs" />
-    <Compile Include="Online\Chat\LocalEchoMessage.cs" />
-    <Compile Include="Online\Chat\Message.cs" />
-    <Compile Include="Online\Multiplayer\GameType.cs" />
-    <Compile Include="Online\Multiplayer\Room.cs" />
-    <Compile Include="Online\Multiplayer\RoomStatus.cs" />
-    <Compile Include="OsuGame.cs" />
-    <Compile Include="OsuGameBase.cs" />
-    <Compile Include="Overlays\ChatOverlay.cs" />
-    <Compile Include="Overlays\Chat\ChannelListItem.cs" />
-    <Compile Include="Overlays\Chat\ChannelSection.cs" />
-    <Compile Include="Overlays\Chat\ChannelSelectionOverlay.cs" />
-    <Compile Include="Overlays\Chat\ChatLine.cs" />
-    <Compile Include="Overlays\Chat\ChatTabControl.cs" />
-    <Compile Include="Overlays\Direct\PlayButton.cs" />
-    <Compile Include="Overlays\Chat\DrawableChannel.cs" />
-    <Compile Include="Overlays\DialogOverlay.cs" />
-    <Compile Include="Overlays\Dialog\PopupDialog.cs" />
-    <Compile Include="Overlays\Dialog\PopupDialogButton.cs" />
-    <Compile Include="Overlays\Dialog\PopupDialogCancelButton.cs" />
-    <Compile Include="Overlays\Dialog\PopupDialogOkButton.cs" />
-    <Compile Include="Overlays\DirectOverlay.cs" />
-    <Compile Include="Overlays\Direct\DirectGridPanel.cs" />
-    <Compile Include="Overlays\Direct\DirectListPanel.cs" />
-    <Compile Include="Overlays\Direct\DirectPanel.cs" />
-    <Compile Include="Overlays\Direct\DownloadButton.cs" />
-    <Compile Include="Overlays\Direct\FilterControl.cs" />
-    <Compile Include="Overlays\Direct\Header.cs" />
-    <Compile Include="Overlays\KeyBindingOverlay.cs" />
-    <Compile Include="Overlays\KeyBinding\GlobalKeyBindingsSection.cs" />
-    <Compile Include="Overlays\KeyBinding\KeyBindingRow.cs" />
-    <Compile Include="Overlays\KeyBinding\KeyBindingsSubsection.cs" />
-    <Compile Include="Overlays\KeyBinding\RulesetBindingsSection.cs" />
-    <Compile Include="Overlays\KeyBinding\VariantBindingsSubsection.cs" />
-    <Compile Include="Overlays\LoginOverlay.cs" />
-    <Compile Include="Overlays\MainSettings.cs" />
-    <Compile Include="Overlays\MedalOverlay.cs" />
-    <Compile Include="Overlays\MedalSplash\DrawableMedal.cs" />
-    <Compile Include="Overlays\Mods\SpecialSection.cs" />
-    <Compile Include="Overlays\Mods\DifficultyIncreaseSection.cs" />
-    <Compile Include="Overlays\Mods\DifficultyReductionSection.cs" />
-    <Compile Include="Overlays\Mods\ModButton.cs" />
-    <Compile Include="Overlays\Mods\ModButtonEmpty.cs" />
-    <Compile Include="Overlays\Mods\ModSection.cs" />
-    <Compile Include="Overlays\Mods\ModSelectOverlay.cs" />
-    <Compile Include="Overlays\MusicController.cs" />
-    <Compile Include="Overlays\Music\CollectionsDropdown.cs" />
-    <Compile Include="Overlays\Music\FilterControl.cs" />
-    <Compile Include="Overlays\Music\PlaylistItem.cs" />
-    <Compile Include="Overlays\Music\PlaylistList.cs" />
-    <Compile Include="Overlays\Music\PlaylistOverlay.cs" />
-    <Compile Include="Overlays\NotificationOverlay.cs" />
-    <Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
-    <Compile Include="Overlays\Notifications\Notification.cs" />
-    <Compile Include="Overlays\Notifications\NotificationSection.cs" />
-    <Compile Include="Overlays\Notifications\ProgressCompletionNotification.cs" />
-    <Compile Include="Overlays\Notifications\ProgressNotification.cs" />
-    <Compile Include="Overlays\Notifications\SimpleNotification.cs" />
-    <Compile Include="Overlays\OnScreenDisplay.cs" />
-    <Compile Include="Overlays\Profile\Sections\Ranks\DrawableProfileScore.cs" />
-    <Compile Include="Overlays\Profile\ProfileHeader.cs" />
-    <Compile Include="Overlays\Profile\ProfileSection.cs" />
-    <Compile Include="Overlays\Profile\RankGraph.cs" />
-    <Compile Include="Overlays\Profile\Sections\AboutSection.cs" />
-    <Compile Include="Overlays\Profile\Sections\BeatmapsSection.cs" />
-    <Compile Include="Overlays\Profile\Sections\HistoricalSection.cs" />
-    <Compile Include="Overlays\Profile\Sections\KudosuSection.cs" />
-    <Compile Include="Overlays\Profile\Sections\MedalsSection.cs" />
-    <Compile Include="Overlays\Profile\Sections\RanksSection.cs" />
-    <Compile Include="Overlays\Profile\Sections\RecentSection.cs" />
-    <Compile Include="Overlays\SearchableList\DisplayStyleControl.cs" />
-    <Compile Include="Overlays\SearchableList\HeaderTabControl.cs" />
-    <Compile Include="Overlays\SearchableList\SearchableListFilterControl.cs" />
-    <Compile Include="Overlays\SearchableList\SearchableListHeader.cs" />
-    <Compile Include="Overlays\SearchableList\SearchableListOverlay.cs" />
-    <Compile Include="Overlays\SearchableList\SlimEnumDropdown.cs" />
-    <Compile Include="Overlays\SettingsOverlay.cs" />
-    <Compile Include="Overlays\Settings\Sections\AudioSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\Audio\AudioDevicesSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Audio\MainMenuSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Audio\OffsetSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Audio\VolumeSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\DebugSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\Debug\GCSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Debug\GeneralSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\GameplaySection.cs" />
-    <Compile Include="Overlays\Settings\Sections\Gameplay\GeneralSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Gameplay\SongSelectSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\GeneralSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\General\LanguageSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\General\LoginSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\General\UpdateSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\GraphicsSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\Graphics\DetailSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Graphics\LayoutSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Graphics\MainMenuSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Graphics\RendererSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\InputSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\Input\KeyboardSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\Input\MouseSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\MaintenanceSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\Maintenance\GeneralSettings.cs" />
-    <Compile Include="Overlays\Settings\Sections\OnlineSection.cs" />
-    <Compile Include="Overlays\Settings\Sections\SkinSection.cs" />
-    <Compile Include="Overlays\Settings\SettingsCheckbox.cs" />
-    <Compile Include="Overlays\Settings\SettingsDropdown.cs" />
-    <Compile Include="Overlays\Settings\SettingsEnumDropdown.cs" />
-    <Compile Include="Overlays\Settings\SettingsFooter.cs" />
-    <Compile Include="Overlays\Settings\SettingsHeader.cs" />
-    <Compile Include="Overlays\Settings\SettingsItem.cs" />
-    <Compile Include="Overlays\Settings\SettingsLabel.cs" />
-    <Compile Include="Overlays\Settings\SettingsSection.cs" />
-    <Compile Include="Overlays\Settings\SettingsSlider.cs" />
-    <Compile Include="Overlays\Settings\SettingsSubsection.cs" />
-    <Compile Include="Overlays\Settings\SettingsTextBox.cs" />
-    <Compile Include="Overlays\Settings\Sidebar.cs" />
-    <Compile Include="Overlays\Settings\SidebarButton.cs" />
-    <Compile Include="Overlays\SocialOverlay.cs" />
-    <Compile Include="Overlays\Social\FilterControl.cs" />
-    <Compile Include="Overlays\Social\Header.cs" />
-    <Compile Include="Overlays\Toolbar\Toolbar.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarDirectButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarHomeButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarModeButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarModeSelector.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarMusicButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarNotificationButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarOverlayToggleButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarSettingsButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarSocialButton.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarUserArea.cs" />
-    <Compile Include="Overlays\Toolbar\ToolbarUserButton.cs" />
-    <Compile Include="Overlays\UserProfileOverlay.cs" />
-    <Compile Include="Overlays\WaveOverlayContainer.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Rulesets\Edit\Tools\HitObjectCompositionTool.cs" />
-    <Compile Include="Rulesets\Edit\Tools\ICompositionTool.cs" />
-    <Compile Include="Rulesets\Edit\HitObjectComposer.cs" />
-    <Compile Include="Rulesets\Edit\ToolboxGroup.cs" />
-    <Compile Include="Rulesets\Judgements\DrawableJudgement.cs" />
-    <Compile Include="Rulesets\Judgements\Judgement.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToClock.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToHitObject.cs" />
-    <Compile Include="Rulesets\Mods\IApplicableToRulesetContainer.cs" />
-    <Compile Include="Rulesets\Mods\Mod.cs" />
-    <Compile Include="Rulesets\Mods\ModAutoplay.cs" />
-    <Compile Include="Rulesets\Mods\ModCinema.cs" />
-    <Compile Include="Rulesets\Mods\ModDaycore.cs" />
-    <Compile Include="Rulesets\Mods\ModDoubleTime.cs" />
-    <Compile Include="Rulesets\Mods\ModEasy.cs" />
-    <Compile Include="Rulesets\Mods\ModFlashlight.cs" />
-    <Compile Include="Rulesets\Mods\ModHalfTime.cs" />
-    <Compile Include="Rulesets\Mods\ModHardRock.cs" />
-    <Compile Include="Rulesets\Mods\ModHidden.cs" />
-    <Compile Include="Rulesets\Mods\ModNightcore.cs" />
-    <Compile Include="Rulesets\Mods\ModNoFail.cs" />
-    <Compile Include="Rulesets\Mods\ModPerfect.cs" />
-    <Compile Include="Rulesets\Mods\ModRelax.cs" />
-    <Compile Include="Rulesets\Mods\ModSuddenDeath.cs" />
-    <Compile Include="Rulesets\Mods\ModType.cs" />
-    <Compile Include="Rulesets\Mods\MultiMod.cs" />
-    <Compile Include="Rulesets\Objects\BezierApproximator.cs" />
-    <Compile Include="Rulesets\Objects\CircularArcApproximator.cs" />
-    <Compile Include="Rulesets\Objects\Drawables\ArmedState.cs" />
-    <Compile Include="Rulesets\Objects\Drawables\DrawableHitObject.cs" />
-    <Compile Include="Rulesets\Scoring\HitResult.cs" />
-    <Compile Include="Rulesets\Objects\Drawables\IDrawableHitObjectWithProxiedApproach.cs" />
-    <Compile Include="Rulesets\Objects\Drawables\IScrollingHitObject.cs" />
-    <Compile Include="Rulesets\Objects\HitObject.cs" />
-    <Compile Include="Rulesets\Objects\HitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Catch\ConvertHit.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Catch\ConvertHitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Catch\ConvertSlider.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Catch\ConvertSpinner.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\ConvertHitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\ConvertHitObjectType.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\ConvertSlider.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Mania\ConvertHit.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Mania\ConvertHitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Mania\ConvertHold.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Mania\ConvertSlider.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Mania\ConvertSpinner.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Osu\ConvertHit.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Osu\ConvertHitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Osu\ConvertSlider.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Osu\ConvertSpinner.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertHit.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertHitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertSlider.cs" />
-    <Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertSpinner.cs" />
-    <Compile Include="Rulesets\Objects\SliderCurve.cs" />
-    <Compile Include="Rulesets\Objects\Types\CurveType.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasCombo.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasCurve.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasDistance.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasEndTime.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasHold.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasPosition.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasRepeats.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasXPosition.cs" />
-    <Compile Include="Rulesets\Objects\Types\IHasYPosition.cs" />
-    <Compile Include="Rulesets\Replays\AutoGenerator.cs" />
-    <Compile Include="Rulesets\Replays\FramedReplayInputHandler.cs" />
-    <Compile Include="Rulesets\Replays\IAutoGenerator.cs" />
-    <Compile Include="Rulesets\Replays\Replay.cs" />
-    <Compile Include="Rulesets\Ruleset.cs" />
-    <Compile Include="Rulesets\RulesetInfo.cs" />
-    <Compile Include="Rulesets\RulesetStore.cs" />
-    <Compile Include="Rulesets\Scoring\PerformanceCalculator.cs" />
-    <Compile Include="Rulesets\Scoring\Score.cs" />
-    <Compile Include="Rulesets\Scoring\ScoreProcessor.cs" />
-    <Compile Include="Rulesets\Scoring\ScoreRank.cs" />
-    <Compile Include="Rulesets\Scoring\ScoreStore.cs" />
-    <Compile Include="Rulesets\Timing\MultiplierControlPoint.cs" />
-    <Compile Include="Rulesets\UI\ModIcon.cs" />
-    <Compile Include="Rulesets\UI\Playfield.cs" />
-    <Compile Include="Rulesets\UI\RulesetContainer.cs" />
-    <Compile Include="Rulesets\UI\RulesetInputManager.cs" />
-    <Compile Include="Screens\BackgroundScreen.cs" />
-    <Compile Include="Screens\Backgrounds\BackgroundScreenBeatmap.cs" />
-    <Compile Include="Screens\Backgrounds\BackgroundScreenCustom.cs" />
-    <Compile Include="Screens\Backgrounds\BackgroundScreenDefault.cs" />
-    <Compile Include="Screens\Backgrounds\BackgroundScreenEmpty.cs" />
-    <Compile Include="Screens\Charts\ChartInfo.cs" />
-    <Compile Include="Screens\Charts\ChartListing.cs" />
-    <Compile Include="Screens\Direct\OnlineListing.cs" />
-    <Compile Include="Screens\Edit\Editor.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Parts\BreakPart.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Parts\BookmarkPart.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Parts\ControlPointPart.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Parts\MarkerPart.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Parts\TimelinePart.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Visualisations\DurationVisualisation.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\Visualisations\PointVisualisation.cs" />
-    <Compile Include="Screens\Edit\Components\Timelines\Summary\SummaryTimeline.cs" />
-    <Compile Include="Screens\Edit\Screens\EditorScreenMode.cs" />
-    <Compile Include="Screens\Edit\Menus\EditorMenuBar.cs" />
-    <Compile Include="Screens\Edit\Menus\EditorMenuItem.cs" />
-    <Compile Include="Screens\Edit\Menus\EditorMenuItemSpacer.cs" />
-    <Compile Include="Screens\Edit\Menus\ScreenSelectionTabControl.cs" />
-    <Compile Include="Screens\Edit\Screens\Design\Design.cs" />
-    <Compile Include="Screens\Edit\Screens\EditorScreen.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Compose.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Timeline\ScrollableTimeline.cs" />
-    <Compile Include="Screens\Edit\Screens\Compose\Timeline\ScrollingTimelineContainer.cs" />
-    <Compile Include="Screens\Loader.cs" />
-    <Compile Include="Screens\Menu\Button.cs" />
-    <Compile Include="Screens\Menu\ButtonSystem.cs" />
-    <Compile Include="Screens\Menu\Disclaimer.cs" />
-    <Compile Include="Screens\Menu\FlowContainerWithOrigin.cs" />
-    <Compile Include="Screens\Menu\Intro.cs" />
-    <Compile Include="Screens\Menu\IntroSequence.cs" />
-    <Compile Include="Screens\Menu\LogoVisualisation.cs" />
-    <Compile Include="Screens\Menu\MainMenu.cs" />
-    <Compile Include="Screens\Menu\MenuSideFlashes.cs" />
-    <Compile Include="Screens\Menu\OsuLogo.cs" />
-    <Compile Include="Screens\Multiplayer\DrawableGameType.cs" />
-    <Compile Include="Screens\Multiplayer\DrawableRoom.cs" />
-    <Compile Include="Screens\Multiplayer\Lobby.cs" />
-    <Compile Include="Screens\Multiplayer\Match.cs" />
-    <Compile Include="Screens\Multiplayer\MatchCreate.cs" />
-    <Compile Include="Screens\Multiplayer\ModeTypeInfo.cs" />
-    <Compile Include="Screens\Multiplayer\ParticipantInfo.cs" />
-    <Compile Include="Screens\Multiplayer\RoomInspector.cs" />
-    <Compile Include="Screens\OsuScreen.cs" />
-    <Compile Include="Screens\Play\FailOverlay.cs" />
-    <Compile Include="Screens\Play\HotkeyRetryOverlay.cs" />
-    <Compile Include="Screens\Play\HUDOverlay.cs" />
-    <Compile Include="Screens\Play\HUD\ComboCounter.cs" />
-    <Compile Include="Screens\Play\HUD\ComboResultCounter.cs" />
-    <Compile Include="Screens\Play\HUD\HealthDisplay.cs" />
-    <Compile Include="Screens\Play\HUD\ModDisplay.cs" />
-    <Compile Include="Screens\Play\HUD\StandardComboCounter.cs" />
-    <Compile Include="Screens\Play\HUD\StandardHealthDisplay.cs" />
-    <Compile Include="Screens\Play\KeyCounter.cs" />
-    <Compile Include="Screens\Play\KeyCounterAction.cs" />
-    <Compile Include="Screens\Play\KeyCounterCollection.cs" />
-    <Compile Include="Screens\Play\KeyCounterKeyboard.cs" />
-    <Compile Include="Screens\Play\KeyCounterMouse.cs" />
-    <Compile Include="Screens\Play\GameplayMenuOverlay.cs" />
-    <Compile Include="Screens\Play\PauseContainer.cs" />
-    <Compile Include="Screens\Play\Player.cs" />
-    <Compile Include="Screens\Play\PlayerLoader.cs" />
-    <Compile Include="Screens\Play\ReplayPlayer.cs" />
-    <Compile Include="Screens\Play\HUD\PlayerSettingsOverlay.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\CollectionSettings.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\DiscussionSettings.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\PlaybackSettings.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\PlayerCheckbox.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\PlayerSettingsGroup.cs" />
-    <Compile Include="Screens\Play\PlayerSettings\PlayerSliderBar.cs" />
-    <Compile Include="Screens\Play\SkipOverlay.cs" />
-    <Compile Include="Screens\Play\SongProgress.cs" />
-    <Compile Include="Screens\Play\SongProgressBar.cs" />
-    <Compile Include="Screens\Play\SongProgressGraph.cs" />
-    <Compile Include="Screens\Play\SongProgressInfo.cs" />
-    <Compile Include="Screens\Play\SquareGraph.cs" />
-    <Compile Include="Screens\Ranking\AspectContainer.cs" />
-    <Compile Include="Screens\Ranking\ResultMode.cs" />
-    <Compile Include="Screens\Ranking\ResultModeButton.cs" />
-    <Compile Include="Screens\Ranking\ResultModeTabControl.cs" />
-    <Compile Include="Screens\Ranking\Results.cs" />
-    <Compile Include="Screens\Ranking\ResultsPage.cs" />
-    <Compile Include="Screens\Ranking\ResultsPageRanking.cs" />
-    <Compile Include="Screens\Ranking\ResultsPageScore.cs" />
-    <Compile Include="Screens\ScreenWhiteBox.cs" />
-    <Compile Include="Screens\Select\BeatmapCarousel.cs" />
-    <Compile Include="Screens\Select\BeatmapDeleteDialog.cs" />
-    <Compile Include="Screens\Select\BeatmapDetailArea.cs" />
-    <Compile Include="Screens\Select\BeatmapDetailAreaTabControl.cs" />
-    <Compile Include="Screens\Select\BeatmapDetails.cs" />
-    <Compile Include="Screens\Select\BeatmapInfoWedge.cs" />
-    <Compile Include="Screens\Select\Carousel\CarouselBeatmap.cs" />
-    <Compile Include="Screens\Select\Carousel\CarouselBeatmapSet.cs" />
-    <Compile Include="Screens\Select\Carousel\CarouselGroup.cs" />
-    <Compile Include="Screens\Select\Carousel\CarouselGroupEagerSelect.cs" />
-    <Compile Include="Screens\Select\Carousel\CarouselItem.cs" />
-    <Compile Include="Screens\Select\Carousel\DrawableCarouselBeatmap.cs" />
-    <Compile Include="Screens\Select\Carousel\DrawableCarouselBeatmapSet.cs" />
-    <Compile Include="Screens\Select\Carousel\DrawableCarouselItem.cs" />
-    <Compile Include="Screens\Select\Details\AdvancedStats.cs" />
-    <Compile Include="Screens\Select\Details\FailRetryGraph.cs" />
-    <Compile Include="Screens\Select\Details\UserRatings.cs" />
-    <Compile Include="Screens\Select\EditSongSelect.cs" />
-    <Compile Include="Screens\Select\FilterControl.cs" />
-    <Compile Include="Screens\Select\FilterCriteria.cs" />
-    <Compile Include="Screens\Select\Filter\GroupMode.cs" />
-    <Compile Include="Screens\Select\Filter\SortMode.cs" />
-    <Compile Include="Screens\Select\Footer.cs" />
-    <Compile Include="Screens\Select\FooterButton.cs" />
-    <Compile Include="Screens\Select\Leaderboards\DrawableRank.cs" />
-    <Compile Include="Screens\Select\Leaderboards\Leaderboard.cs" />
-    <Compile Include="Screens\Select\Leaderboards\LeaderboardScore.cs" />
-    <Compile Include="Screens\Select\Leaderboards\MessagePlaceholder.cs" />
-    <Compile Include="Screens\Select\Leaderboards\Placeholder.cs" />
-    <Compile Include="Screens\Select\Leaderboards\RetrievalFailurePlaceholder.cs" />
-    <Compile Include="Screens\Select\MatchSongSelect.cs" />
-    <Compile Include="Screens\Select\Options\BeatmapOptionsButton.cs" />
-    <Compile Include="Screens\Select\Options\BeatmapOptionsOverlay.cs" />
-    <Compile Include="Screens\Select\PlaySongSelect.cs" />
-    <Compile Include="Screens\Select\SongSelect.cs" />
-    <Compile Include="Screens\Select\WedgeBackground.cs" />
-    <Compile Include="Screens\Tournament\Components\DrawingsConfigManager.cs" />
-    <Compile Include="Screens\Tournament\Components\VisualiserContainer.cs" />
-    <Compile Include="Screens\Tournament\Drawings.cs" />
-    <Compile Include="Screens\Tournament\Group.cs" />
-    <Compile Include="Screens\Tournament\GroupContainer.cs" />
-    <Compile Include="Screens\Tournament\ScrollingTeamContainer.cs" />
-    <Compile Include="Screens\Tournament\Teams\DrawingsTeam.cs" />
-    <Compile Include="Screens\Tournament\Teams\ITeamList.cs" />
-    <Compile Include="Screens\Tournament\Teams\StorageBackedTeamList.cs" />
-    <Compile Include="Skinning\LegacyBeatmapSkin.cs" />
-    <Compile Include="Skinning\DefaultSkin.cs" />
-    <Compile Include="Skinning\ISkinSource.cs" />
-    <Compile Include="Skinning\LegacySkin.cs" />
-    <Compile Include="Skinning\LegacySkinDecoder.cs" />
-    <Compile Include="Skinning\LocalSkinOverrideContainer.cs" />
-    <Compile Include="Skinning\Skin.cs" />
-    <Compile Include="Skinning\SkinConfiguration.cs" />
-    <Compile Include="Skinning\SkinFileInfo.cs" />
-    <Compile Include="Skinning\SkinInfo.cs" />
-    <Compile Include="Skinning\SkinManager.cs" />
-    <Compile Include="Skinning\SkinnableDrawable.cs" />
-    <Compile Include="Skinning\SkinnableSound.cs" />
-    <Compile Include="Skinning\SkinReloadableDrawable.cs" />
-    <Compile Include="Skinning\SkinStore.cs" />
-    <Compile Include="Storyboards\CommandLoop.cs" />
-    <Compile Include="Storyboards\CommandTimeline.cs" />
-    <Compile Include="Storyboards\CommandTimelineGroup.cs" />
-    <Compile Include="Storyboards\CommandTrigger.cs" />
-    <Compile Include="Storyboards\Drawables\DrawablesExtensions.cs" />
-    <Compile Include="Storyboards\Drawables\DrawableStoryboard.cs" />
-    <Compile Include="Storyboards\Drawables\DrawableStoryboardAnimation.cs" />
-    <Compile Include="Storyboards\Drawables\DrawableStoryboardLayer.cs" />
-    <Compile Include="Storyboards\Drawables\DrawableStoryboardSprite.cs" />
-    <Compile Include="Storyboards\Drawables\IFlippable.cs" />
-    <Compile Include="Storyboards\IStoryboardElement.cs" />
-    <Compile Include="Storyboards\Storyboard.cs" />
-    <Compile Include="Storyboards\StoryboardAnimation.cs" />
-    <Compile Include="Storyboards\StoryboardLayer.cs" />
-    <Compile Include="Storyboards\StoryboardSample.cs" />
-    <Compile Include="Storyboards\StoryboardSprite.cs" />
-    <Compile Include="Tests\Beatmaps\BeatmapConversionTest.cs" />
-    <Compile Include="Tests\Beatmaps\TestBeatmap.cs" />
-    <Compile Include="Tests\Beatmaps\TestWorkingBeatmap.cs" />
-    <Compile Include="Tests\CleanRunHeadlessGameHost.cs" />
-    <Compile Include="Tests\Platform\TestStorage.cs" />
-    <Compile Include="Tests\TestTestCase.cs" />
-    <Compile Include="Tests\Visual\OsuTestCase.cs" />
-    <Compile Include="Tests\Visual\EditorTestCase.cs" />
-    <Compile Include="Tests\Visual\TestCasePerformancePoints.cs" />
-    <Compile Include="Tests\Visual\ScreenTestCase.cs" />
-    <Compile Include="Tests\Visual\TestCasePlayer.cs" />
-    <Compile Include="Users\Avatar.cs" />
-    <Compile Include="Users\Country.cs" />
-    <Compile Include="Users\Medal.cs" />
-    <Compile Include="Users\Team.cs" />
-    <Compile Include="Users\UpdateableAvatar.cs" />
-    <Compile Include="Users\User.cs" />
-    <Compile Include="Users\UserCoverBackground.cs" />
-    <Compile Include="Users\UserPanel.cs" />
-    <Compile Include="Users\UserStatistics.cs" />
-    <Compile Include="Users\UserStatus.cs" />
-    <Compile Include="Overlays\BeatmapSetOverlay.cs" />
-    <Compile Include="Overlays\BeatmapSet\Info.cs" />
-    <Compile Include="Overlays\BeatmapSet\Header.cs" />
-    <Compile Include="Overlays\BeatmapSet\AuthorInfo.cs" />
-    <Compile Include="Overlays\BeatmapSet\BeatmapPicker.cs" />
-    <Compile Include="Overlays\BeatmapSet\HeaderButton.cs" />
-    <Compile Include="Overlays\BeatmapSet\Details.cs" />
-    <Compile Include="Overlays\BeatmapSet\FavouriteButton.cs" />
-    <Compile Include="Overlays\BeatmapSet\DownloadButton.cs" />
-    <Compile Include="Overlays\BeatmapSet\BasicStats.cs" />
-    <Compile Include="Overlays\BeatmapSet\SuccessRate.cs" />
-    <Compile Include="Overlays\BeatmapSet\PreviewButton.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-  <ProjectExtensions>
-    <VisualStudio>
-    </VisualStudio>
-  </ProjectExtensions>
-  <PropertyGroup>
-    <PreBuildEvent>
-    </PreBuildEvent>
-  </PropertyGroup>
-  <PropertyGroup>
-    <PostBuildEvent>
-    </PostBuildEvent>
-  </PropertyGroup>
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
-  <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+<Project Sdk="Microsoft.NET.Sdk">
+  <Import Project="..\osu.Game.props" />
+  <PropertyGroup Label="Project">
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <OutputType>Library</OutputType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <WarningLevel>0</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup Label="Service">
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
+    <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
+  </ItemGroup>
+  <ItemGroup Label="Package References">
+    <PackageReference Include="Humanizer" Version="2.2.0" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.0.1" />
+    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
+    <PackageReference Include="SharpCompress" Version="0.18.1" />
+    <PackageReference Include="NUnit" Version="3.8.1" />
+    <PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/osu.Game/packages.config b/osu.Game/packages.config
deleted file mode 100644
index 6d46360b99..0000000000
--- a/osu.Game/packages.config
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
-Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
--->
-<packages>
-  <package id="DotNetZip" version="1.10.1" targetFramework="net461" />
-  <package id="Humanizer" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.af" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.ar" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.bg" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.bn-BD" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.cs" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.da" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.de" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.el" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.es" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.fa" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.fi-FI" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.fr" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.fr-BE" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.he" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.hr" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.hu" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.id" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.it" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.ja" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.lv" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.nb" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.nb-NO" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.nl" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.pl" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.pt" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.ro" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.ru" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.sk" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.sl" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.sr" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.sr-Latn" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.sv" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.tr" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.uk" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.uz-Cyrl-UZ" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.uz-Latn-UZ" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.vi" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.zh-CN" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.zh-Hans" version="2.2.0" targetFramework="net461" />
-  <package id="Humanizer.Core.zh-Hant" version="2.2.0" targetFramework="net461" />
-  <package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
-  <package id="Microsoft.CSharp" version="4.4.0" targetFramework="net461" />
-  <package id="Microsoft.Data.Sqlite.Core" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Design" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Relational" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Sqlite" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Sqlite.Core" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Tools" version="2.0.0" targetFramework="net461" developmentDependency="true" />
-  <package id="Microsoft.Extensions.Caching.Abstractions" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Caching.Memory" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Configuration.Abstractions" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.DependencyInjection" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Logging" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Logging.Abstractions" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Options" version="2.0.0" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Primitives" version="2.0.0" targetFramework="net461" />
-  <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
-  <package id="NUnit" version="3.8.1" targetFramework="net461" />
-  <package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
-  <package id="Remotion.Linq" version="2.1.2" targetFramework="net461" />
-  <package id="SharpCompress" version="0.18.1" targetFramework="net461" />
-  <package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
-  <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
-  <package id="System.Collections" version="4.3.0" targetFramework="net461" />
-  <package id="System.Collections.Immutable" version="1.4.0" targetFramework="net461" />
-  <package id="System.ComponentModel.Annotations" version="4.4.0" targetFramework="net461" />
-  <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
-  <package id="System.Diagnostics.DiagnosticSource" version="4.4.1" targetFramework="net461" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net461" />
-  <package id="System.Linq" version="4.3.0" targetFramework="net461" />
-  <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
-  <package id="System.Linq.Queryable" version="4.3.0" targetFramework="net461" />
-  <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
-  <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
-  <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
-  <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
-  <package id="System.Runtime.CompilerServices.Unsafe" version="4.4.0" targetFramework="net461" />
-  <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
-  <package id="System.Threading" version="4.3.0" targetFramework="net461" />
-  <package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/osu.TestProject.props b/osu.TestProject.props
new file mode 100644
index 0000000000..cb841f1940
--- /dev/null
+++ b/osu.TestProject.props
@@ -0,0 +1,29 @@
+<Project>
+  <Import Project="osu.Game.props" />
+  <PropertyGroup>
+    <StartupObject>osu.Game.Tests.VisualTestRunner</StartupObject>
+  </PropertyGroup>
+  <ItemGroup Label="Service">
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+  <ItemGroup Label="Project References">
+    <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
+    <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
+    <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
+  </ItemGroup>
+  <ItemGroup Label="Package References">
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
+    <PackageReference Include="DeepEqual" Version="1.6.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.1" />
+    <PackageReference Include="NUnit" Version="3.8.1" />
+    <PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
+  </ItemGroup>
+  <ItemGroup>  
+    <Compile Include="..\osu.Game\Tests\VisualTestRunner.cs">
+      <Link>VisualTestRunner.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <PropertyGroup>
+    <GenerateProgramFile>false</GenerateProgramFile>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/osu.sln b/osu.sln
index 356ec4cc7b..f017bf9eab 100644
--- a/osu.sln
+++ b/osu.sln
@@ -3,90 +3,94 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
 VisualStudioVersion = 15.0.27004.2006
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Framework", "osu-framework\osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu-framework\osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko", "osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj", "{F167E17A-7DE6-4AF5-B920-A5112296C695}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Taiko", "osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj", "{F167E17A-7DE6-4AF5-B920-A5112296C695}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania", "osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Mania", "osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop.Deploy", "osu.Desktop.Deploy\osu.Desktop.Deploy.csproj", "{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Desktop.Deploy", "osu.Desktop.Deploy\osu.Desktop.Deploy.csproj", "{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests", "osu.Game.Tests\osu.Game.Tests.csproj", "{54377672-20B1-40AF-8087-5CF73BF3953A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Tests", "osu.Game.Tests\osu.Game.Tests.csproj", "{54377672-20B1-40AF-8087-5CF73BF3953A}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop", "osu.Desktop\osu.Desktop.csproj", "{419659FD-72EA-4678-9EB8-B22A746CED70}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Desktop", "osu.Desktop\osu.Desktop.csproj", "{419659FD-72EA-4678-9EB8-B22A746CED70}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Catch.Tests", "osu.Game.Rulesets.Catch.Tests\osu.Game.Rulesets.Catch.Tests.csproj", "{3AD63355-D6B1-4365-8D31-5652C989BEF1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Mania.Tests", "osu.Game.Rulesets.Mania.Tests\osu.Game.Rulesets.Mania.Tests.csproj", "{7E9E9C34-B204-406B-82E2-E01E900699CD}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Taiko.Tests", "osu.Game.Rulesets.Taiko.Tests\osu.Game.Rulesets.Taiko.Tests.csproj", "{B698561F-FB28-46B1-857E-3CA7B92F9D70}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Osu.Tests", "osu.Game.Rulesets.Osu.Tests\osu.Game.Rulesets.Osu.Tests.csproj", "{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
-		VisualTests|Any CPU = VisualTests|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C92A607B-1FDD-4954-9F92-03FF547D9080}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{C92A607B-1FDD-4954-9F92-03FF547D9080}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.Build.0 = Release|Any CPU
-		{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F167E17A-7DE6-4AF5-B920-A5112296C695}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{F167E17A-7DE6-4AF5-B920-A5112296C695}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU
-		{48F4582B-7687-4621-9CBE-5C24197CB536}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
-		{48F4582B-7687-4621-9CBE-5C24197CB536}.VisualTests|Any CPU.Build.0 = Debug|Any CPU
 		{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU
 		{54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{54377672-20B1-40AF-8087-5CF73BF3953A}.VisualTests|Any CPU.ActiveCfg = Release|Any CPU
-		{54377672-20B1-40AF-8087-5CF73BF3953A}.VisualTests|Any CPU.Build.0 = Release|Any CPU
 		{419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.Build.0 = Release|Any CPU
-		{419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.ActiveCfg = VisualTests|Any CPU
-		{419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.Build.0 = VisualTests|Any CPU
+		{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings
index 3b62dbe579..0b631d008b 100644
--- a/osu.sln.DotSettings
+++ b/osu.sln.DotSettings
@@ -43,6 +43,7 @@
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=FieldCanBeMadeReadOnly_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=FieldCanBeMadeReadOnly_002ELocal/@EntryIndexedValue">WARNING</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ForCanBeConvertedToForeach/@EntryIndexedValue">WARNING</s:String>
+	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ImpureMethodCallOnReadonlyValueField/@EntryIndexedValue">HINT</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InconsistentNaming/@EntryIndexedValue">ERROR</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InheritdocConsiderUsage/@EntryIndexedValue">HINT</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InlineOutVariableDeclaration/@EntryIndexedValue">HINT</s:String>