mirror of
https://github.com/ppy/osu.git
synced 2026-05-14 17:43:43 +08:00
Compare commits
337 Commits
2018.710.0
...
2018.804.0
@@ -24,9 +24,9 @@ Clone the repository including submodules
|
||||
Build and run
|
||||
|
||||
- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
|
||||
- From command line using `dotnet run --project osu.Desktop --framework netcoreapp2.1`
|
||||
- From command line using `dotnet run --project osu.Desktop`
|
||||
|
||||
The above methods should automatically do so, but if you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`).
|
||||
If you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`). Visual Studio Code users must run `Restore` task from debug tab before attempt to build.
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
+6
-5
@@ -2,20 +2,21 @@ clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017
|
||||
configuration: Debug
|
||||
cache:
|
||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: choco install resharper-clt -y
|
||||
- cmd: choco install nvika -y
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe
|
||||
- cmd: dotnet tool install CodeFileSanity --version 0.0.16 --global
|
||||
before_build:
|
||||
- cmd: CodeFileSanity.exe
|
||||
- cmd: CodeFileSanity
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
environment:
|
||||
TargetFramework: net471
|
||||
build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
|
||||
+3
-5
@@ -16,17 +16,15 @@ build_script:
|
||||
- cd osu-deploy
|
||||
- nuget restore -verbosity quiet
|
||||
- msbuild osu.Desktop.Deploy.csproj
|
||||
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\net471\osu.Desktop.Deploy.exe.config
|
||||
- cd bin\Debug\net471\
|
||||
- osu.Desktop.Deploy.exe %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
|
||||
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\netcoreapp2.1\osu.Desktop.Deploy.dll.config
|
||||
- dotnet bin/Debug/netcoreapp2.1/osu.Desktop.Deploy.dll %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
|
||||
environment:
|
||||
TargetFramework: net471
|
||||
decode_secret:
|
||||
secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY=
|
||||
code_signing_password:
|
||||
secure: 34tLNqvjmmZEi97MLKfrnQ==
|
||||
artifacts:
|
||||
- path: 'Releases\*'
|
||||
- path: 'osu-deploy/releases/*'
|
||||
deploy:
|
||||
- provider: Environment
|
||||
name: github
|
||||
@@ -13,6 +13,7 @@ using osu.Game;
|
||||
using OpenTK.Input;
|
||||
using Microsoft.Win32;
|
||||
using osu.Desktop.Updater;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Platform.Windows;
|
||||
|
||||
namespace osu.Desktop
|
||||
@@ -51,11 +52,10 @@ namespace osu.Desktop
|
||||
v.State = Visibility.Visible;
|
||||
});
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
Add(new SquirrelUpdateManager());
|
||||
#else
|
||||
Add(new SimpleUpdateManager());
|
||||
#endif
|
||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||
Add(new SquirrelUpdateManager());
|
||||
else
|
||||
Add(new SimpleUpdateManager());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,6 @@ using osu.Framework;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.IPC;
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
using System.Runtime;
|
||||
#endif
|
||||
|
||||
namespace osu.Desktop
|
||||
{
|
||||
public static class Program
|
||||
@@ -19,8 +15,6 @@ namespace osu.Desktop
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
useMultiCoreJit();
|
||||
|
||||
// Back up the cwd before DesktopGameHost changes it
|
||||
var cwd = Environment.CurrentDirectory;
|
||||
|
||||
@@ -51,14 +45,5 @@ namespace osu.Desktop
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void useMultiCoreJit()
|
||||
{
|
||||
#if NET_FRAMEWORK
|
||||
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
|
||||
ProfileOptimization.SetProfileRoot(directory.FullName);
|
||||
ProfileOptimization.StartProfile("Startup.Profile");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace osu.Desktop.Updater
|
||||
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe"));
|
||||
break;
|
||||
case RuntimeInfo.Platform.MacOsx:
|
||||
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".dmg"));
|
||||
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".app.zip"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -162,4 +161,3 @@ namespace osu.Desktop.Updater
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.Game.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@@ -13,9 +13,6 @@
|
||||
<Version>0.0.0</Version>
|
||||
<FileVersion>0.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Defines">
|
||||
<DefineConstants Condition="'$(TargetFramework)' == 'net471'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>osu.Desktop.Program</StartupObject>
|
||||
</PropertyGroup>
|
||||
@@ -29,11 +26,12 @@
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>osulazer</id>
|
||||
<version>0.0.0</version>
|
||||
<title>osulazer</title>
|
||||
<title>osu!lazer</title>
|
||||
<authors>ppy Pty Ltd</authors>
|
||||
<owners>Dean Herbert</owners>
|
||||
<projectUrl>https://osu.ppy.sh/</projectUrl>
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/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=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -28,18 +28,20 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||
{
|
||||
if (hitObject is JuiceStream stream)
|
||||
switch (hitObject)
|
||||
{
|
||||
foreach (var nested in stream.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
case JuiceStream stream:
|
||||
foreach (var nested in stream.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
break;
|
||||
case BananaShower shower:
|
||||
foreach (var nested in shower.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
break;
|
||||
default:
|
||||
yield return new ConvertValue((CatchHitObject)hitObject);
|
||||
break;
|
||||
}
|
||||
else if (hitObject is BananaShower shower)
|
||||
{
|
||||
foreach (var nested in shower.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
}
|
||||
else
|
||||
yield return new ConvertValue((CatchHitObject)hitObject);
|
||||
}
|
||||
|
||||
protected override Ruleset CreateRuleset() => new CatchRuleset();
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
|
||||
@@ -93,13 +93,11 @@ namespace osu.Game.Rulesets.Catch
|
||||
new CatchModHidden(),
|
||||
new CatchModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new CatchModRelax(),
|
||||
null,
|
||||
null,
|
||||
new MultiMod(new CatchModAutoplay(), new ModCinema()),
|
||||
new CatchModRelax(),
|
||||
};
|
||||
default:
|
||||
return new Mod[] { };
|
||||
|
||||
@@ -46,13 +46,16 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
|
||||
foreach (var hitObject in beatmap.HitObjects)
|
||||
{
|
||||
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
|
||||
if (hitObject is Fruit)
|
||||
switch (hitObject)
|
||||
{
|
||||
difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, halfCatchWidth));
|
||||
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
|
||||
case Fruit fruit:
|
||||
difficultyHitObjects.Add(new CatchDifficultyHitObject(fruit, halfCatchWidth));
|
||||
break;
|
||||
case JuiceStream _:
|
||||
difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType<CatchHitObject>().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
|
||||
break;
|
||||
}
|
||||
if (hitObject is JuiceStream)
|
||||
difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType<CatchHitObject>().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
|
||||
}
|
||||
|
||||
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private readonly CatcherArea catcherArea;
|
||||
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation)
|
||||
: base(ScrollingDirection.Down, BASE_WIDTH)
|
||||
: base(BASE_WIDTH)
|
||||
{
|
||||
Direction.Value = ScrollingDirection.Down;
|
||||
|
||||
Container explodingFruitContainer;
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
void runAfterLoaded(Action action)
|
||||
{
|
||||
if (lastPlateableFruit == null)
|
||||
return;
|
||||
|
||||
// this is required to make this run after the last caught fruit runs UpdateState at least once.
|
||||
// TODO: find a better alternative
|
||||
if (lastPlateableFruit.IsLoaded)
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/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=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }});
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
private Drawable createColumn(ScrollingDirection direction, ManiaAction action)
|
||||
{
|
||||
var column = new Column(direction)
|
||||
var column = new Column
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
return new ScrollingTestContainer(direction)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}")
|
||||
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
return new ScrollingTestContainer(direction)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}")
|
||||
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = new DrawableHoldNote(note)
|
||||
{
|
||||
@@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
};
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
var specialAction = ManiaAction.Special1;
|
||||
|
||||
var stage = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) { VisibleTimeRange = { Value = 2000 } };
|
||||
var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) { VisibleTimeRange = { Value = 2000 } };
|
||||
stages.Add(stage);
|
||||
|
||||
return new ScrollingTestContainer(direction)
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
|
||||
@@ -133,26 +133,26 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
if (ConversionDifficulty > 6.5)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.78, 0.3, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.85, 0.36, 0.03);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 4)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.43, 0.08, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.56, 0.18, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 2.5)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.3, 0, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.37, 0.08, 0);
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.17, 0, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.27, 0, 0);
|
||||
}
|
||||
@@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
var pattern = new Pattern();
|
||||
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
@@ -361,7 +361,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
bool isDoubleSample(SampleInfo sample) => sample.Name == SampleInfo.HIT_CLAP || sample.Name == SampleInfo.HIT_FINISH;
|
||||
|
||||
bool canGenerateTwoNotes = (convertType & PatternType.LowProbability) == 0;
|
||||
bool canGenerateTwoNotes = !convertType.HasFlag(PatternType.LowProbability);
|
||||
canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample);
|
||||
|
||||
if (canGenerateTwoNotes)
|
||||
@@ -391,7 +391,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
||||
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
@@ -425,7 +425,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
var pattern = new Pattern();
|
||||
|
||||
int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(holdColumn))
|
||||
holdColumn = Random.Next(RandomStart, TotalColumns);
|
||||
|
||||
@@ -33,15 +33,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
bool generateHold = endTime - HitObject.StartTime >= 100;
|
||||
|
||||
if (TotalColumns == 8)
|
||||
switch (TotalColumns)
|
||||
{
|
||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000)
|
||||
case 8 when HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000:
|
||||
addToPattern(pattern, 0, generateHold);
|
||||
else
|
||||
break;
|
||||
case 8:
|
||||
addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold);
|
||||
break;
|
||||
default:
|
||||
if (TotalColumns > 0)
|
||||
addToPattern(pattern, getNextRandomColumn(0), generateHold);
|
||||
break;
|
||||
}
|
||||
else if (TotalColumns > 0)
|
||||
addToPattern(pattern, getNextRandomColumn(0), generateHold);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
private readonly PatternType convertType;
|
||||
|
||||
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair, IBeatmap originalBeatmap)
|
||||
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density,
|
||||
PatternType lastStair, IBeatmap originalBeatmap)
|
||||
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
||||
{
|
||||
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
|
||||
@@ -79,7 +80,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
else
|
||||
convertType |= PatternType.LowProbability;
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) == 0)
|
||||
if (!convertType.HasFlag(PatternType.KeepSingle))
|
||||
{
|
||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
|
||||
convertType |= PatternType.Mirror;
|
||||
@@ -107,7 +108,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
|
||||
|
||||
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
|
||||
if (convertType.HasFlag(PatternType.Reverse) && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
// Generate a new pattern by copying the last hit objects in reverse-column order
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
@@ -117,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1
|
||||
if (convertType.HasFlag(PatternType.Cycle) && PreviousPattern.HitObjects.Count() == 1
|
||||
// If we convert to 7K + 1, let's not overload the special key
|
||||
&& (TotalColumns != 8 || lastColumn != 0)
|
||||
// Make sure the last column was not the centre column
|
||||
@@ -130,7 +131,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Any())
|
||||
if (convertType.HasFlag(PatternType.ForceStack) && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
// Generate a new pattern by placing on the already filled columns
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
@@ -142,7 +143,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
if (PreviousPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
if ((convertType & PatternType.Stair) > 0)
|
||||
if (convertType.HasFlag(PatternType.Stair))
|
||||
{
|
||||
// Generate a new pattern by placing on the next column, cycling back to the start if there is no "next"
|
||||
int targetColumn = lastColumn + 1;
|
||||
@@ -153,7 +154,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.ReverseStair) > 0)
|
||||
if (convertType.HasFlag(PatternType.ReverseStair))
|
||||
{
|
||||
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
|
||||
int targetColumn = lastColumn - 1;
|
||||
@@ -165,10 +166,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
}
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) > 0)
|
||||
if (convertType.HasFlag(PatternType.KeepSingle))
|
||||
return pattern = generateRandomNotes(1);
|
||||
|
||||
if ((convertType & PatternType.Mirror) > 0)
|
||||
if (convertType.HasFlag(PatternType.Mirror))
|
||||
{
|
||||
if (ConversionDifficulty > 6.5)
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
|
||||
@@ -179,21 +180,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
if (ConversionDifficulty > 6.5)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return pattern = generateRandomPattern(0.78, 0.42, 0, 0);
|
||||
return pattern = generateRandomPattern(1, 0.62, 0, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 4)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return pattern = generateRandomPattern(0.35, 0.08, 0, 0);
|
||||
return pattern = generateRandomPattern(0.52, 0.15, 0, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 2)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return pattern = generateRandomPattern(0.18, 0, 0, 0);
|
||||
return pattern = generateRandomPattern(0.45, 0, 0, 0);
|
||||
}
|
||||
@@ -204,9 +205,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
foreach (var obj in pattern.HitObjects)
|
||||
{
|
||||
if ((convertType & PatternType.Stair) > 0 && obj.Column == TotalColumns - 1)
|
||||
if (convertType.HasFlag(PatternType.Stair) && obj.Column == TotalColumns - 1)
|
||||
StairType = PatternType.ReverseStair;
|
||||
if ((convertType & PatternType.ReverseStair) > 0 && obj.Column == RandomStart)
|
||||
if (convertType.HasFlag(PatternType.ReverseStair) && obj.Column == RandomStart)
|
||||
StairType = PatternType.Stair;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +226,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
|
||||
bool allowStacking = (convertType & PatternType.ForceNotStack) == 0;
|
||||
bool allowStacking = !convertType.HasFlag(PatternType.ForceNotStack);
|
||||
|
||||
if (!allowStacking)
|
||||
noteCount = Math.Min(noteCount, TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects);
|
||||
@@ -235,7 +236,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking)
|
||||
{
|
||||
if ((convertType & PatternType.Gathered) > 0)
|
||||
if (convertType.HasFlag(PatternType.Gathered))
|
||||
{
|
||||
nextColumn++;
|
||||
if (nextColumn == TotalColumns)
|
||||
@@ -367,7 +368,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
addToCentre = false;
|
||||
|
||||
if ((convertType & PatternType.ForceNotStack) > 0)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack))
|
||||
return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3);
|
||||
|
||||
switch (TotalColumns)
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()),
|
||||
new ManiaModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ManiaModKey4(),
|
||||
@@ -135,6 +135,10 @@ namespace osu.Game.Rulesets.Mania
|
||||
new ManiaModRandom(),
|
||||
new ManiaModDualStages(),
|
||||
new ManiaModMirror(),
|
||||
};
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
|
||||
};
|
||||
default:
|
||||
|
||||
@@ -19,14 +19,14 @@ namespace osu.Game.Rulesets.Mania
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ManiaConfigManager config)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsEnumDropdown<ManiaScrollingDirection>
|
||||
{
|
||||
LabelText = "Scrolling direction",
|
||||
Bindable = config.GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
|
||||
Bindable = ((ManiaConfigManager)Config).GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override string ShortenedName => Name;
|
||||
public abstract int KeyCount { get; }
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
|
||||
public override bool Ranked => true;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string Name => "Dual Stages";
|
||||
public override string ShortenedName => "DS";
|
||||
public override string Description => @"Double the stages, double the fun!";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
private bool isForCurrentRuleset;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override string Name => "Mirror";
|
||||
public override string ShortenedName => "MR";
|
||||
public override ModType Type => ModType.Special;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override string Name => "Random";
|
||||
public override string ShortenedName => "RD";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
|
||||
public override string Description => @"Shuffle around the keys!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
@@ -56,10 +56,15 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
{
|
||||
foreach (var point in group)
|
||||
{
|
||||
if (point is HitPoint)
|
||||
actions.Add(columnActions[point.Column]);
|
||||
if (point is ReleasePoint)
|
||||
actions.Remove(columnActions[point.Column]);
|
||||
switch (point)
|
||||
{
|
||||
case HitPoint _:
|
||||
actions.Add(columnActions[point.Column]);
|
||||
break;
|
||||
case ReleasePoint _:
|
||||
actions.Remove(columnActions[point.Column]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray()));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Replays
|
||||
|
||||
@@ -32,8 +32,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
protected override Container<Drawable> Content => hitObjectArea;
|
||||
|
||||
public Column(ScrollingDirection direction)
|
||||
: base(direction)
|
||||
public Column()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = column_width;
|
||||
@@ -118,9 +117,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IBindable<ManiaAction>>(Action);
|
||||
return dependencies;
|
||||
}
|
||||
@@ -139,7 +138,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (!judgement.IsHit || !judgedObject.DisplayJudgement)
|
||||
if (!judgement.IsHit || !judgedObject.DisplayJudgement || !DisplayJudgements)
|
||||
return;
|
||||
|
||||
explosionContainer.Add(new HitExplosion(judgedObject)
|
||||
|
||||
@@ -8,11 +8,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@@ -21,8 +19,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
|
||||
public ManiaPlayfield(ScrollingDirection direction, List<StageDefinition> stageDefinitions)
|
||||
: base(direction)
|
||||
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||
{
|
||||
if (stageDefinitions == null)
|
||||
throw new ArgumentNullException(nameof(stageDefinitions));
|
||||
@@ -42,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
int firstColumnIndex = 0;
|
||||
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||
{
|
||||
var newStage = new ManiaStage(direction, firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
newStage.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||
|
||||
playfieldGrid.Content[0][i] = newStage;
|
||||
@@ -76,10 +73,5 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
maniaConfig.BindWith(ManiaSetting.ScrollTime, VisibleTimeRange);
|
||||
}
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,24 +70,24 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ManiaConfigManager config)
|
||||
private void load()
|
||||
{
|
||||
BarLines.ForEach(Playfield.Add);
|
||||
|
||||
config.BindWith(ManiaSetting.ScrollDirection, configDirection);
|
||||
((ManiaConfigManager)Config).BindWith(ManiaSetting.ScrollDirection, configDirection);
|
||||
configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true);
|
||||
}
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo());
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(scrollingInfo.Direction, Beatmap.Stages)
|
||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
||||
@@ -11,11 +11,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
public ManiaScrollingPlayfield(ScrollingDirection direction)
|
||||
: base(direction)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
|
||||
@@ -43,8 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
private readonly int firstColumnIndex;
|
||||
|
||||
public ManiaStage(ScrollingDirection direction, int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||
: base(direction)
|
||||
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||
{
|
||||
this.firstColumnIndex = firstColumnIndex;
|
||||
|
||||
@@ -124,7 +123,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
for (int i = 0; i < definition.Columns; i++)
|
||||
{
|
||||
var isSpecial = definition.IsSpecialColumn(i);
|
||||
var column = new Column(direction)
|
||||
var column = new Column
|
||||
{
|
||||
IsSpecial = isSpecial,
|
||||
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
|
||||
@@ -164,7 +163,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (!judgedObject.DisplayJudgement)
|
||||
if (!judgedObject.DisplayJudgement || !DisplayJudgements)
|
||||
return;
|
||||
|
||||
judgements.Clear();
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/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=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
||||
@@ -1,12 +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 osu.Game.Rulesets.Osu.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
public class OsuEditPlayfield : OsuPlayfield
|
||||
{
|
||||
protected override bool DisplayJudgements => false;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit
|
||||
@@ -16,8 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
}
|
||||
|
||||
protected override Playfield CreatePlayfield() => new OsuEditPlayfield();
|
||||
|
||||
protected override Vector2 PlayfieldArea => Vector2.One;
|
||||
|
||||
protected override CursorContainer CreateCursor() => null;
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Name => "Autopilot";
|
||||
public override string ShortenedName => "AP";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Name => "Spun Out";
|
||||
public override string ShortenedName => "SO";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => @"Spinners will be automatically completed.";
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
public override bool Ranked => true;
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public override string Name => "Target";
|
||||
public override string ShortenedName => "TP";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
|
||||
public override string Description => @"Practice keeping up with the beat of the song.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
@@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
@@ -20,27 +21,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Masking = true;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
CornerRadius = width / 2;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
Child = new SkinnableDrawable("Play/osu/followpoint", _ => new Container
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = Color4.White.Opacity(0.2f),
|
||||
Radius = 4,
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
Masking = true,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
CornerRadius = width / 2,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = Color4.White.Opacity(0.2f),
|
||||
Radius = 4,
|
||||
},
|
||||
Child = new Box
|
||||
{
|
||||
Size = new Vector2(width),
|
||||
Blending = BlendingMode.Additive,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
};
|
||||
}
|
||||
}, restrictSize: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
Vector2 distanceVector = endPosition - startPosition;
|
||||
int distance = (int)distanceVector.Length;
|
||||
float rotation = (float)Math.Atan2(distanceVector.Y, distanceVector.X);
|
||||
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
|
||||
double duration = endTime - startTime;
|
||||
|
||||
for (int d = (int)(PointDistance * 1.5); d < distance - PointDistance; d += PointDistance)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@@ -32,7 +34,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
UpdatePreemptState();
|
||||
|
||||
using (BeginDelayedSequence(HitObject.TimePreempt + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
|
||||
var judgementOffset = Math.Min(HitObject.HitWindows.HalfWindowFor(HitResult.Miss), Judgements.FirstOrDefault()?.TimeOffset ?? 0);
|
||||
|
||||
using (BeginDelayedSequence(HitObject.TimePreempt + judgementOffset, true))
|
||||
UpdateCurrentState(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using OpenTK;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@@ -33,11 +34,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new SpriteIcon
|
||||
new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Icon = FontAwesome.fa_chevron_right
|
||||
}
|
||||
}, restrictSize: false)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,6 +75,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
private bool hasRotation;
|
||||
|
||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||
{
|
||||
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
|
||||
@@ -87,15 +90,33 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
int searchStart = isRepeatAtEnd ? curve.Count - 1 : 0;
|
||||
int direction = isRepeatAtEnd ? -1 : 1;
|
||||
|
||||
Vector2 aimRotationVector = Vector2.Zero;
|
||||
|
||||
// find the next vector2 in the curve which is not equal to our current position to infer a rotation.
|
||||
for (int i = searchStart; i >= 0 && i < curve.Count; i += direction)
|
||||
{
|
||||
if (Precision.AlmostEquals(curve[i], Position))
|
||||
continue;
|
||||
|
||||
Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - Position.Y, curve[i].X - Position.X));
|
||||
aimRotationVector = curve[i];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
float aimRotation = MathHelper.RadiansToDegrees((float)Math.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
|
||||
while (Math.Abs(aimRotation - Rotation) > 180)
|
||||
aimRotation += aimRotation < Rotation ? 360 : -360;
|
||||
|
||||
if (!hasRotation)
|
||||
{
|
||||
Rotation = aimRotation;
|
||||
hasRotation = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're already snaking, interpolate to smooth out sharp curves (linear sliders, mainly).
|
||||
Rotation = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 100), Rotation, aimRotation, 0, 50, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@@ -22,23 +24,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||
{
|
||||
Size = new Vector2(16) * sliderTick.Scale;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = Size.X / 2;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
BorderThickness = 2;
|
||||
BorderColour = Color4.White;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new Container
|
||||
{
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Alpha = 0.3f,
|
||||
}
|
||||
Origin = Anchor.Centre,
|
||||
CornerRadius = Size.X / 2,
|
||||
|
||||
BorderThickness = 2,
|
||||
BorderColour = Color4.White,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Alpha = 0.3f,
|
||||
}
|
||||
}, restrictSize: false)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.EventArgs;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
@@ -17,6 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
private const float width = 128;
|
||||
|
||||
private Color4 accentColour = Color4.Black;
|
||||
|
||||
/// <summary>
|
||||
/// The colour that is used for the slider ball.
|
||||
/// </summary>
|
||||
@@ -26,14 +29,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
if (ball != null)
|
||||
ball.Colour = value;
|
||||
if (drawableBall != null)
|
||||
drawableBall.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Slider slider;
|
||||
public readonly Box FollowCircle;
|
||||
private readonly Box ball;
|
||||
public readonly Drawable FollowCircle;
|
||||
private Drawable drawableBall;
|
||||
|
||||
public SliderBall(Slider slider)
|
||||
{
|
||||
@@ -42,19 +45,30 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Blending = BlendingMode.Additive;
|
||||
Origin = Anchor.Centre;
|
||||
BorderThickness = 10;
|
||||
BorderColour = Color4.Orange;
|
||||
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
FollowCircle = new Box
|
||||
FollowCircle = new Container
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Colour = Color4.Orange,
|
||||
Width = width,
|
||||
Height = width,
|
||||
Alpha = 0,
|
||||
Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = 5,
|
||||
BorderColour = Color4.Orange,
|
||||
Blending = BlendingMode.Additive,
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.Orange,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.2f,
|
||||
}
|
||||
}),
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
@@ -62,18 +76,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
BorderThickness = 10,
|
||||
BorderColour = Color4.White,
|
||||
Alpha = 1,
|
||||
Children = new[]
|
||||
Child = new Container
|
||||
{
|
||||
ball = new Box
|
||||
Width = width,
|
||||
Height = width,
|
||||
// TODO: support skin filename animation (sliderb0, sliderb1...)
|
||||
Child = new SkinnableDrawable("Play/osu/sliderb", _ => new CircularContainer
|
||||
{
|
||||
Colour = AccentColour,
|
||||
Alpha = 0.4f,
|
||||
Width = width,
|
||||
Height = width,
|
||||
},
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
BorderThickness = 10,
|
||||
BorderColour = Color4.White,
|
||||
Alpha = 1,
|
||||
Child = drawableBall = new Box
|
||||
{
|
||||
Colour = AccentColour,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.4f,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -110,6 +132,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
}
|
||||
|
||||
private bool tracking;
|
||||
|
||||
public bool Tracking
|
||||
{
|
||||
get { return tracking; }
|
||||
@@ -119,8 +142,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
return;
|
||||
tracking = value;
|
||||
|
||||
FollowCircle.ScaleTo(tracking ? 2.8f : 1, 300, Easing.OutQuint);
|
||||
FollowCircle.FadeTo(tracking ? 0.2f : 0, 300, Easing.OutQuint);
|
||||
FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint);
|
||||
FollowCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
// Out preempt should be one span early to give the user ample warning.
|
||||
TimePreempt += SpanDuration;
|
||||
|
||||
// We want to show the first RepeatPoint as the TimePreempt dictates but on short (and possibly fast) sliders
|
||||
// we may need to cut down this time on following RepeatPoints to only show up to two RepeatPoints at any given time.
|
||||
if (RepeatIndex > 0)
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.Z, OsuAction.LeftButton),
|
||||
new KeyBinding(InputKey.X, OsuAction.RightButton),
|
||||
new KeyBinding(InputKey.A, OsuAction.LeftButton),
|
||||
new KeyBinding(InputKey.S, OsuAction.RightButton),
|
||||
new KeyBinding(InputKey.MouseLeft, OsuAction.LeftButton),
|
||||
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
||||
};
|
||||
@@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModEasy(),
|
||||
new OsuModNoFail(),
|
||||
new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
|
||||
new OsuModSpunOut(),
|
||||
};
|
||||
case ModType.DifficultyIncrease:
|
||||
return new Mod[]
|
||||
@@ -104,14 +105,17 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new OsuModTarget(),
|
||||
};
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
||||
new OsuModRelax(),
|
||||
new OsuModAutopilot(),
|
||||
new OsuModSpunOut(),
|
||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
||||
new OsuModTarget(),
|
||||
};
|
||||
default:
|
||||
return new Mod[] { };
|
||||
|
||||
@@ -285,44 +285,45 @@ namespace osu.Game.Rulesets.Osu.Replays
|
||||
|
||||
AddFrameToReplay(startFrame);
|
||||
|
||||
// We add intermediate frames for spinning / following a slider here.
|
||||
if (h is Spinner)
|
||||
switch (h)
|
||||
{
|
||||
Spinner s = h as Spinner;
|
||||
|
||||
Vector2 difference = startPosition - SPINNER_CENTRE;
|
||||
|
||||
float radius = difference.Length;
|
||||
float angle = radius == 0 ? 0 : (float)Math.Atan2(difference.Y, difference.X);
|
||||
|
||||
double t;
|
||||
|
||||
for (double j = h.StartTime + FrameDelay; j < s.EndTime; j += FrameDelay)
|
||||
// We add intermediate frames for spinning / following a slider here.
|
||||
case Spinner spinner:
|
||||
{
|
||||
t = ApplyModsToTime(j - h.StartTime) * spinnerDirection;
|
||||
Vector2 difference = startPosition - SPINNER_CENTRE;
|
||||
|
||||
Vector2 pos = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
AddFrameToReplay(new OsuReplayFrame((int)j, new Vector2(pos.X, pos.Y), action));
|
||||
float radius = difference.Length;
|
||||
float angle = radius == 0 ? 0 : (float)Math.Atan2(difference.Y, difference.X);
|
||||
|
||||
double t;
|
||||
|
||||
for (double j = h.StartTime + FrameDelay; j < spinner.EndTime; j += FrameDelay)
|
||||
{
|
||||
t = ApplyModsToTime(j - h.StartTime) * spinnerDirection;
|
||||
|
||||
Vector2 pos = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
AddFrameToReplay(new OsuReplayFrame((int)j, new Vector2(pos.X, pos.Y), action));
|
||||
}
|
||||
|
||||
t = ApplyModsToTime(spinner.EndTime - h.StartTime) * spinnerDirection;
|
||||
Vector2 endPosition = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(spinner.EndTime, new Vector2(endPosition.X, endPosition.Y), action));
|
||||
|
||||
endFrame.Position = endPosition;
|
||||
break;
|
||||
}
|
||||
|
||||
t = ApplyModsToTime(s.EndTime - h.StartTime) * spinnerDirection;
|
||||
Vector2 endPosition = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(s.EndTime, new Vector2(endPosition.X, endPosition.Y), action));
|
||||
|
||||
endFrame.Position = endPosition;
|
||||
}
|
||||
else if (h is Slider)
|
||||
{
|
||||
Slider s = h as Slider;
|
||||
|
||||
for (double j = FrameDelay; j < s.Duration; j += FrameDelay)
|
||||
case Slider slider:
|
||||
{
|
||||
Vector2 pos = s.StackedPositionAt(j / s.Duration);
|
||||
AddFrameToReplay(new OsuReplayFrame(h.StartTime + j, new Vector2(pos.X, pos.Y), action));
|
||||
}
|
||||
for (double j = FrameDelay; j < slider.Duration; j += FrameDelay)
|
||||
{
|
||||
Vector2 pos = slider.StackedPositionAt(j / slider.Duration);
|
||||
AddFrameToReplay(new OsuReplayFrame(h.StartTime + j, new Vector2(pos.X, pos.Y), action));
|
||||
}
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(s.EndTime, new Vector2(s.StackedEndPosition.X, s.StackedEndPosition.Y), action));
|
||||
AddFrameToReplay(new OsuReplayFrame(slider.EndTime, new Vector2(slider.StackedEndPosition.X, slider.StackedEndPosition.Y), action));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We only want to let go of our button if we are at the end of the current replay. Otherwise something is still going on after us so we need to keep the button pressed!
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using OpenTK;
|
||||
|
||||
@@ -12,6 +12,7 @@ using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Timing;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
private int downCount;
|
||||
|
||||
private const float pressed_scale = 1.2f;
|
||||
private const float released_scale = 1f;
|
||||
|
||||
private float targetScale => downCount > 0 ? pressed_scale : released_scale;
|
||||
|
||||
public bool OnPressed(OsuAction action)
|
||||
{
|
||||
switch (action)
|
||||
@@ -46,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
case OsuAction.LeftButton:
|
||||
case OsuAction.RightButton:
|
||||
downCount++;
|
||||
ActiveCursor.ScaleTo(1).ScaleTo(1.2f, 100, Easing.OutQuad);
|
||||
ActiveCursor.ScaleTo(released_scale).ScaleTo(targetScale, 100, Easing.OutQuad);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -60,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
case OsuAction.LeftButton:
|
||||
case OsuAction.RightButton:
|
||||
if (--downCount == 0)
|
||||
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
|
||||
ActiveCursor.ScaleTo(targetScale, 200, Easing.OutQuad);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -72,13 +77,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
protected override void PopIn()
|
||||
{
|
||||
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(targetScale, 400, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(targetScale * 0.8f, 450, Easing.OutQuint);
|
||||
}
|
||||
|
||||
public class OsuCursor : Container
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
|
||||
|
||||
protected virtual bool DisplayJudgements => true;
|
||||
|
||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||
|
||||
public OsuPlayfield()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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.Linq;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
@@ -33,19 +34,30 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
protected override DrawableHitObject<OsuHitObject> GetVisualRepresentation(OsuHitObject h)
|
||||
{
|
||||
if (h is HitCircle circle)
|
||||
return new DrawableHitCircle(circle);
|
||||
switch (h)
|
||||
{
|
||||
case HitCircle circle:
|
||||
return new DrawableHitCircle(circle);
|
||||
case Slider slider:
|
||||
return new DrawableSlider(slider);
|
||||
case Spinner spinner:
|
||||
return new DrawableSpinner(spinner);
|
||||
}
|
||||
|
||||
if (h is Slider slider)
|
||||
return new DrawableSlider(slider);
|
||||
|
||||
if (h is Spinner spinner)
|
||||
return new DrawableSpinner(spinner);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay);
|
||||
|
||||
public override double GameplayStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
var first = (OsuHitObject)Objects.First();
|
||||
return first.StartTime - first.TimePreempt;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 GetAspectAdjustedSize()
|
||||
{
|
||||
var aspectSize = DrawSize.X * 0.75f < DrawSize.Y ? new Vector2(DrawSize.X, DrawSize.X * 0.75f) : new Vector2(DrawSize.Y * 4f / 3f, DrawSize.Y);
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Taiko.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/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=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
|
||||
@@ -80,30 +80,31 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
{
|
||||
if (obj is Hit)
|
||||
switch (obj)
|
||||
{
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
else if (obj is DrumRoll)
|
||||
{
|
||||
for (int i = 0; i < ((DrumRoll)obj).NestedHitObjects.OfType<DrumRollTick>().Count(); i++)
|
||||
{
|
||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
||||
case Hit _:
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
break;
|
||||
case DrumRoll drumRoll:
|
||||
var count = drumRoll.NestedHitObjects.OfType<DrumRollTick>().Count();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
||||
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
else if (obj is Swell)
|
||||
{
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
break;
|
||||
case Swell _:
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +93,11 @@ namespace osu.Game.Rulesets.Taiko
|
||||
new TaikoModHidden(),
|
||||
new TaikoModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new TaikoModRelax(),
|
||||
null,
|
||||
null,
|
||||
new MultiMod(new TaikoModAutoplay(), new ModCinema()),
|
||||
new TaikoModRelax(),
|
||||
};
|
||||
default:
|
||||
return new Mod[] { };
|
||||
|
||||
@@ -58,8 +58,9 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
private readonly Box background;
|
||||
|
||||
public TaikoPlayfield(ControlPointInfo controlPoints)
|
||||
: base(ScrollingDirection.Left)
|
||||
{
|
||||
Direction.Value = ScrollingDirection.Left;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
backgroundContainer = new Container
|
||||
@@ -212,17 +213,22 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
|
||||
base.Add(h);
|
||||
|
||||
var barline = h as DrawableBarLine;
|
||||
if (barline != null)
|
||||
barlineContainer.Add(barline.CreateProxy());
|
||||
|
||||
var taikoObject = h as DrawableTaikoHitObject;
|
||||
if (taikoObject != null)
|
||||
topLevelHitContainer.Add(taikoObject.CreateProxiedContent());
|
||||
switch (h)
|
||||
{
|
||||
case DrawableBarLine barline:
|
||||
barlineContainer.Add(barline.CreateProxy());
|
||||
break;
|
||||
case DrawableTaikoHitObject taikoObject:
|
||||
topLevelHitContainer.Add(taikoObject.CreateProxiedContent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (!DisplayJudgements)
|
||||
return;
|
||||
|
||||
if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
|
||||
{
|
||||
judgementContainer.Add(new DrawableTaikoJudgement(judgement, judgedObject)
|
||||
|
||||
@@ -98,32 +98,22 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
|
||||
protected override DrawableHitObject<TaikoHitObject> GetVisualRepresentation(TaikoHitObject h)
|
||||
{
|
||||
var centreHit = h as CentreHit;
|
||||
if (centreHit != null)
|
||||
switch (h)
|
||||
{
|
||||
if (h.IsStrong)
|
||||
case CentreHit centreHit when h.IsStrong:
|
||||
return new DrawableCentreHitStrong(centreHit);
|
||||
return new DrawableCentreHit(centreHit);
|
||||
}
|
||||
|
||||
var rimHit = h as RimHit;
|
||||
if (rimHit != null)
|
||||
{
|
||||
if (h.IsStrong)
|
||||
case CentreHit centreHit:
|
||||
return new DrawableCentreHit(centreHit);
|
||||
case RimHit rimHit when h.IsStrong:
|
||||
return new DrawableRimHitStrong(rimHit);
|
||||
return new DrawableRimHit(rimHit);
|
||||
case RimHit rimHit:
|
||||
return new DrawableRimHit(rimHit);
|
||||
case DrumRoll drumRoll:
|
||||
return new DrawableDrumRoll(drumRoll);
|
||||
case Swell swell:
|
||||
return new DrawableSwell(swell);
|
||||
}
|
||||
|
||||
var drumRoll = h as DrumRoll;
|
||||
if (drumRoll != null)
|
||||
{
|
||||
return new DrawableDrumRoll(drumRoll);
|
||||
}
|
||||
|
||||
var swell = h as Swell;
|
||||
if (swell != null)
|
||||
return new DrawableSwell(swell);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,10 +214,10 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeCustomSamples()
|
||||
public void TestDecodeControlPointCustomSampleBank()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("custom-samples.osu"))
|
||||
using (var resStream = Resource.OpenResource("controlpoint-custom-samplebank.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
@@ -228,25 +228,42 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[3]).LookupNames.First());
|
||||
}
|
||||
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" });
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeCustomHitObjectSamples()
|
||||
public void TestDecodeHitObjectCustomSampleBank()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("custom-hitobject-samples.osu"))
|
||||
using (var resStream = Resource.OpenResource("hitobject-custom-samplebank.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
Assert.AreEqual("hit_1.wav", hitObjects[0].Samples[0].LookupNames.First());
|
||||
Assert.AreEqual("hit_2.wav", hitObjects[1].Samples[0].LookupNames.First());
|
||||
Assert.AreEqual("normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
|
||||
Assert.AreEqual("hit_1.wav", hitObjects[3].Samples[0].LookupNames.First());
|
||||
Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First());
|
||||
Assert.AreEqual("normal-hitnormal2", getTestableSampleInfo(hitObjects[1]).LookupNames.First());
|
||||
Assert.AreEqual("normal-hitnormal3", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
|
||||
}
|
||||
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" });
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeHitObjectFileSamples()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("hitobject-file-samples.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
Assert.AreEqual("hit_1.wav", getTestableSampleInfo(hitObjects[0]).LookupNames.First());
|
||||
Assert.AreEqual("hit_2.wav", getTestableSampleInfo(hitObjects[1]).LookupNames.First());
|
||||
Assert.AreEqual("normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
|
||||
Assert.AreEqual("hit_1.wav", getTestableSampleInfo(hitObjects[3]).LookupNames.First());
|
||||
}
|
||||
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
SampleSet: Normal
|
||||
|
||||
[TimingPoints]
|
||||
2170,468.75,4,1,0,40,1,0
|
||||
3107,-100,4,1,2,40,0,0
|
||||
|
||||
[HitObjects]
|
||||
255,193,2170,1,0,0:0:0:0:
|
||||
256,191,3107,5,0,0:0:0:0:
|
||||
255,193,4000,1,0,0:0:3:70:
|
||||
@@ -530,7 +530,7 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public new List<DrawableCarouselItem> Items => base.Items;
|
||||
|
||||
public bool PendingFilterTask => FilterTask != null;
|
||||
public bool PendingFilterTask => PendingFilter != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public class TestCaseDisclaimer : OsuTestCase
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
new Disclaimer()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using System.Linq;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.EventArgs;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
|
||||
@@ -25,11 +25,7 @@ namespace osu.Game.Tests.Visual
|
||||
Children = new[]
|
||||
{
|
||||
new NamedIconButton("No change", new IconButton()),
|
||||
new NamedIconButton("Background colours", new IconButton
|
||||
{
|
||||
FlashColour = Color4.DarkGreen,
|
||||
HoverColour = Color4.Green,
|
||||
}),
|
||||
new NamedIconButton("Background colours", new ColouredIconButton()),
|
||||
new NamedIconButton("Full-width", new IconButton { ButtonSize = new Vector2(200, 30) }),
|
||||
new NamedIconButton("Unchanging size", new IconButton(), false),
|
||||
new NamedIconButton("Icon colours", new IconButton
|
||||
@@ -41,6 +37,15 @@ namespace osu.Game.Tests.Visual
|
||||
};
|
||||
}
|
||||
|
||||
private class ColouredIconButton : IconButton
|
||||
{
|
||||
public ColouredIconButton()
|
||||
{
|
||||
FlashColour = Color4.DarkGreen;
|
||||
HoverColour = Color4.Green;
|
||||
}
|
||||
}
|
||||
|
||||
private class NamedIconButton : Container
|
||||
{
|
||||
public NamedIconButton(string name, IconButton button, bool allowSizeChange = true)
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
IsCounting = true,
|
||||
Children = new KeyCounter[]
|
||||
{
|
||||
new KeyCounterKeyboard(Key.Z),
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Edit.Screens.Setup.Components.LabelledComponents;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCaseLabelledTextBox : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(LabelledTextBox),
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Padding = new MarginPadding { Left = 150, Right = 150 },
|
||||
Child = new LabelledTextBox
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
LabelText = "Testing text",
|
||||
PlaceholderText = "This is definitely working as intended",
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays.Mods.Sections;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
@@ -36,7 +37,9 @@ namespace osu.Game.Tests.Visual
|
||||
typeof(ModButtonEmpty),
|
||||
typeof(DifficultyReductionSection),
|
||||
typeof(DifficultyIncreaseSection),
|
||||
typeof(SpecialSection),
|
||||
typeof(AutomationSection),
|
||||
typeof(ConversionSection),
|
||||
typeof(FunSection),
|
||||
};
|
||||
|
||||
private RulesetStore rulesets;
|
||||
@@ -95,7 +98,7 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
var easierMods = ruleset.GetModsFor(ModType.DifficultyReduction);
|
||||
var harderMods = ruleset.GetModsFor(ModType.DifficultyIncrease);
|
||||
var assistMods = ruleset.GetModsFor(ModType.Special);
|
||||
var assistMods = ruleset.GetModsFor(ModType.Automation);
|
||||
|
||||
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
|
||||
var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden);
|
||||
@@ -119,7 +122,7 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
private void testManiaMods(ManiaRuleset ruleset)
|
||||
{
|
||||
testRankedText(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom));
|
||||
testRankedText(ruleset.GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom));
|
||||
}
|
||||
|
||||
private void testSingleMod(Mod mod)
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK.Graphics;
|
||||
@@ -23,19 +22,15 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
public TestCaseOsuGame()
|
||||
{
|
||||
var rateAdjustClock = new StopwatchClock(true);
|
||||
var framedClock = new FramedClock(rateAdjustClock);
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
Add(new Box
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
});
|
||||
|
||||
Add(new Loader());
|
||||
|
||||
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
new Loader()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
using osu.Game.Tests.Platform;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
@@ -28,6 +27,7 @@ namespace osu.Game.Tests.Visual
|
||||
private RulesetStore rulesets;
|
||||
|
||||
private WorkingBeatmap defaultBeatmap;
|
||||
private DatabaseContextFactory factory;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@@ -54,58 +54,63 @@ namespace osu.Game.Tests.Visual
|
||||
public new BeatmapCarousel Carousel => base.Carousel;
|
||||
}
|
||||
|
||||
private TestSongSelect songSelect;
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
factory.ResetDatabase();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
factory = new DatabaseContextFactory(LocalStorage);
|
||||
factory.ResetDatabase();
|
||||
|
||||
var storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||
using (var usage = factory.Get())
|
||||
usage.Migrate();
|
||||
|
||||
// this is by no means clean. should be replacing inside of OsuGameBase somehow.
|
||||
IDatabaseContextFactory factory = new SingletonContextFactory(new OsuDbContext());
|
||||
factory.ResetDatabase();
|
||||
|
||||
using (var usage = factory.Get())
|
||||
usage.Migrate();
|
||||
|
||||
Dependencies.Cache(rulesets = new RulesetStore(factory));
|
||||
Dependencies.Cache(manager = new BeatmapManager(storage, factory, rulesets, null, null)
|
||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null)
|
||||
{
|
||||
DefaultBeatmap = defaultBeatmap = Beatmap.Default
|
||||
});
|
||||
|
||||
void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () =>
|
||||
{
|
||||
if (deleteMaps)
|
||||
{
|
||||
manager.Delete(manager.GetAllUsableBeatmapSets());
|
||||
Beatmap.SetDefault();
|
||||
}
|
||||
Beatmap.SetDefault();
|
||||
}
|
||||
|
||||
if (songSelect != null)
|
||||
{
|
||||
Remove(songSelect);
|
||||
songSelect.Dispose();
|
||||
}
|
||||
|
||||
Add(songSelect = new TestSongSelect());
|
||||
});
|
||||
|
||||
loadNewSongSelect(true);
|
||||
|
||||
AddWaitStep(3);
|
||||
[SetUp]
|
||||
public virtual void SetUp()
|
||||
{
|
||||
manager?.Delete(manager.GetAllUsableBeatmapSets());
|
||||
Child = songSelect = new TestSongSelect();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDummy()
|
||||
{
|
||||
AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap);
|
||||
|
||||
AddAssert("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap);
|
||||
|
||||
AddStep("import test maps", () =>
|
||||
{
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
manager.Import(createTestBeatmapSet(i));
|
||||
});
|
||||
|
||||
addManyTestMaps();
|
||||
AddWaitStep(3);
|
||||
|
||||
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
||||
}
|
||||
|
||||
loadNewSongSelect();
|
||||
[Test]
|
||||
public void TestSorting()
|
||||
{
|
||||
addManyTestMaps();
|
||||
AddWaitStep(3);
|
||||
|
||||
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
||||
|
||||
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
|
||||
@@ -114,55 +119,84 @@ namespace osu.Game.Tests.Visual
|
||||
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createTestBeatmapSet(int i)
|
||||
[Test]
|
||||
[Ignore("needs fixing")]
|
||||
public void ImportUnderDifferentRuleset()
|
||||
{
|
||||
changeRuleset(2);
|
||||
importForRuleset(0);
|
||||
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImportUnderCurrentRuleset()
|
||||
{
|
||||
changeRuleset(2);
|
||||
importForRuleset(2);
|
||||
importForRuleset(1);
|
||||
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 2, "has selection");
|
||||
|
||||
changeRuleset(1);
|
||||
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 1, "has selection");
|
||||
|
||||
changeRuleset(0);
|
||||
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection");
|
||||
}
|
||||
|
||||
private void importForRuleset(int id) => AddStep($"import test map for ruleset {id}", () => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())));
|
||||
|
||||
private static int importId;
|
||||
private int getImportId() => ++importId;
|
||||
|
||||
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));
|
||||
|
||||
private void addManyTestMaps()
|
||||
{
|
||||
AddStep("import test maps", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
|
||||
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
manager.Import(createTestBeatmapSet(i, usableRulesets));
|
||||
});
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createTestBeatmapSet(int setId, RulesetInfo[] rulesets)
|
||||
{
|
||||
int j = 0;
|
||||
RulesetInfo getRuleset() => rulesets[j++ % rulesets.Length];
|
||||
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
int beatmapId = setId * 10 + i;
|
||||
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Ruleset = getRuleset(),
|
||||
OnlineBeatmapID = beatmapId,
|
||||
Path = "normal.osu",
|
||||
Version = $"{beatmapId}",
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
OnlineBeatmapSetID = setId,
|
||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
// Create random metadata, then we can check if sorting works based on these
|
||||
Artist = "MONACA " + RNG.Next(0, 9),
|
||||
Title = "Black Song " + RNG.Next(0, 9),
|
||||
Artist = "Some Artist " + RNG.Next(0, 9),
|
||||
Title = $"Some Song (set id {setId})",
|
||||
AuthorString = "Some Guy " + RNG.Next(0, 9),
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>(new[]
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 1234 + i,
|
||||
Ruleset = rulesets.AvailableRulesets.First(),
|
||||
Path = "normal.osu",
|
||||
Version = "Normal",
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
}
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 1235 + i,
|
||||
Ruleset = rulesets.AvailableRulesets.First(),
|
||||
Path = "hard.osu",
|
||||
Version = "Hard",
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 5,
|
||||
}
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 1236 + i,
|
||||
Ruleset = rulesets.AvailableRulesets.First(),
|
||||
Path = "insane.osu",
|
||||
Version = "Insane",
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 7,
|
||||
}
|
||||
},
|
||||
}),
|
||||
Beatmaps = beatmaps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
private readonly PreviewTrackManager trackManager = new TestPreviewTrackManager();
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs(trackManager);
|
||||
dependencies.CacheAs<IPreviewTrackOwner>(this);
|
||||
return dependencies;
|
||||
@@ -101,9 +101,9 @@ namespace osu.Game.Tests.Visual
|
||||
AddInternal(track);
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IPreviewTrackOwner>(this);
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@@ -54,11 +54,11 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
breadcrumbs.Current.TriggerChange();
|
||||
|
||||
assertCurrent();
|
||||
waitForCurrent();
|
||||
pushNext();
|
||||
assertCurrent();
|
||||
waitForCurrent();
|
||||
pushNext();
|
||||
assertCurrent();
|
||||
waitForCurrent();
|
||||
|
||||
AddStep(@"make start current", () =>
|
||||
{
|
||||
@@ -66,8 +66,9 @@ namespace osu.Game.Tests.Visual
|
||||
currentScreen = startScreen;
|
||||
});
|
||||
|
||||
assertCurrent();
|
||||
waitForCurrent();
|
||||
pushNext();
|
||||
waitForCurrent();
|
||||
AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2);
|
||||
AddStep(@"exit current", () => changedScreen.Exit());
|
||||
AddAssert(@"current screen is first", () => startScreen == changedScreen);
|
||||
@@ -80,7 +81,7 @@ namespace osu.Game.Tests.Visual
|
||||
}
|
||||
|
||||
private void pushNext() => AddStep(@"push next screen", () => currentScreen = ((TestScreen)currentScreen).PushNext());
|
||||
private void assertCurrent() => AddAssert(@"changedScreen correct", () => currentScreen == changedScreen);
|
||||
private void waitForCurrent() => AddUntilStep(() => currentScreen.IsCurrentScreen, "current screen");
|
||||
|
||||
private abstract class TestScreen : OsuScreen
|
||||
{
|
||||
|
||||
@@ -117,7 +117,6 @@ namespace osu.Game.Tests.Visual
|
||||
public new readonly ScrollingDirection Direction;
|
||||
|
||||
public TestPlayfield(ScrollingDirection direction)
|
||||
: base(direction)
|
||||
{
|
||||
Direction = direction;
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
||||
@@ -45,6 +45,16 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadBegan;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a beatmap download is interrupted, due to user cancellation or other failures.
|
||||
/// </summary>
|
||||
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadFailed;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a beatmap load is requested (into the interactive game UI).
|
||||
/// </summary>
|
||||
public Action<BeatmapSetInfo> PresentBeatmap;
|
||||
|
||||
/// <summary>
|
||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||
/// </summary>
|
||||
@@ -79,33 +89,46 @@ namespace osu.Game.Beatmaps
|
||||
this.audioManager = audioManager;
|
||||
}
|
||||
|
||||
protected override void Populate(BeatmapSetInfo model, ArchiveReader archive)
|
||||
protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive)
|
||||
{
|
||||
model.Beatmaps = createBeatmapDifficulties(archive);
|
||||
if (archive != null)
|
||||
beatmapSet.Beatmaps = createBeatmapDifficulties(archive);
|
||||
|
||||
foreach (BeatmapInfo b in model.Beatmaps)
|
||||
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
|
||||
{
|
||||
// remove metadata from difficulties where it matches the set
|
||||
if (model.Metadata.Equals(b.Metadata))
|
||||
if (beatmapSet.Metadata.Equals(b.Metadata))
|
||||
b.Metadata = null;
|
||||
|
||||
// by setting the model here, we can update the noline set id below.
|
||||
b.BeatmapSet = model;
|
||||
|
||||
fetchAndPopulateOnlineIDs(b);
|
||||
b.BeatmapSet = beatmapSet;
|
||||
}
|
||||
|
||||
// check if a set already exists with the same online id, delete if it does.
|
||||
if (model.OnlineBeatmapSetID != null)
|
||||
if (beatmapSet.OnlineBeatmapSetID != null)
|
||||
{
|
||||
var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID);
|
||||
var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == beatmapSet.OnlineBeatmapSetID);
|
||||
if (existingOnlineId != null)
|
||||
{
|
||||
Delete(existingOnlineId);
|
||||
beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID);
|
||||
Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database);
|
||||
Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({beatmapSet.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database);
|
||||
}
|
||||
}
|
||||
|
||||
validateOnlineIds(beatmapSet.Beatmaps);
|
||||
|
||||
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
|
||||
fetchAndPopulateOnlineIDs(b, beatmapSet.Beatmaps);
|
||||
}
|
||||
|
||||
private void validateOnlineIds(List<BeatmapInfo> beatmaps)
|
||||
{
|
||||
var beatmapIds = beatmaps.Where(b => b.OnlineBeatmapID.HasValue).Select(b => b.OnlineBeatmapID).ToList();
|
||||
|
||||
// ensure all IDs are unique in this set and none match existing IDs in the local beatmap store.
|
||||
if (beatmapIds.GroupBy(b => b).Any(g => g.Count() > 1) || QueryBeatmaps(b => beatmapIds.Contains(b.OnlineBeatmapID)).Any())
|
||||
// remove all online IDs if any problems were found.
|
||||
beatmaps.ForEach(b => b.OnlineBeatmapID = null);
|
||||
}
|
||||
|
||||
protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model)
|
||||
@@ -143,7 +166,7 @@ namespace osu.Game.Beatmaps
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadNotification = new ProgressNotification
|
||||
var downloadNotification = new DownloadNotification
|
||||
{
|
||||
CompletionText = $"Imported {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}!",
|
||||
Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
|
||||
@@ -163,18 +186,28 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
BeatmapSetInfo importedBeatmap;
|
||||
|
||||
// This gets scheduled back to the update thread, but we want the import to run in the background.
|
||||
using (var stream = new MemoryStream(data))
|
||||
using (var archive = new ZipArchiveReader(stream, beatmapSetInfo.ToString()))
|
||||
Import(archive);
|
||||
importedBeatmap = Import(archive);
|
||||
|
||||
downloadNotification.CompletionClickAction = () =>
|
||||
{
|
||||
PresentBeatmap?.Invoke(importedBeatmap);
|
||||
return true;
|
||||
};
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
|
||||
currentDownloads.Remove(request);
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
};
|
||||
|
||||
request.Failure += error =>
|
||||
{
|
||||
BeatmapDownloadFailed?.Invoke(request);
|
||||
|
||||
if (error is OperationCanceledException) return;
|
||||
|
||||
downloadNotification.State = ProgressNotificationState.Cancelled;
|
||||
@@ -276,7 +309,7 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public IEnumerable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
|
||||
public IQueryable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
|
||||
|
||||
/// <summary>
|
||||
/// Denotes whether an osu-stable installation is present to perform automated imports from.
|
||||
@@ -339,8 +372,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var beatmapInfos = new List<BeatmapInfo>();
|
||||
|
||||
bool invalidateOnlineIDs = false;
|
||||
|
||||
foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu")))
|
||||
{
|
||||
using (var raw = reader.GetStream(name))
|
||||
@@ -357,38 +388,15 @@ namespace osu.Game.Beatmaps
|
||||
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
||||
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
|
||||
|
||||
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue)
|
||||
{
|
||||
var ourId = beatmap.BeatmapInfo.OnlineBeatmapID;
|
||||
|
||||
// check that no existing beatmap in database exists that is imported with the same online beatmap ID. if so, give it precedence.
|
||||
if (QueryBeatmap(b => b.OnlineBeatmapID.Value == ourId) != null)
|
||||
beatmap.BeatmapInfo.OnlineBeatmapID = null;
|
||||
|
||||
// check that no other beatmap in this imported set has a conflicting online beatmap ID. If so, presume *all* are incorrect.
|
||||
if (beatmapInfos.Any(b => b.OnlineBeatmapID == ourId))
|
||||
invalidateOnlineIDs = true;
|
||||
}
|
||||
|
||||
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
|
||||
|
||||
var ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
|
||||
beatmap.BeatmapInfo.Ruleset = ruleset;
|
||||
|
||||
if (ruleset != null)
|
||||
{
|
||||
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
||||
beatmap.BeatmapInfo.StarDifficulty = ruleset.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating;
|
||||
}
|
||||
else
|
||||
beatmap.BeatmapInfo.StarDifficulty = 0;
|
||||
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
||||
beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating ?? 0;
|
||||
|
||||
beatmapInfos.Add(beatmap.BeatmapInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidateOnlineIDs)
|
||||
beatmapInfos.ForEach(b => b.OnlineBeatmapID = null);
|
||||
|
||||
return beatmapInfos;
|
||||
}
|
||||
|
||||
@@ -396,16 +404,17 @@ namespace osu.Game.Beatmaps
|
||||
/// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap to populate.</param>
|
||||
/// <param name="otherBeatmaps">The other beatmaps contained within this set.</param>
|
||||
/// <param name="force">Whether to re-query if the provided beatmap already has populated values.</param>
|
||||
/// <returns>True if population was successful.</returns>
|
||||
private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false)
|
||||
private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, IEnumerable<BeatmapInfo> otherBeatmaps, bool force = false)
|
||||
{
|
||||
if (api?.State != APIState.Online)
|
||||
return false;
|
||||
|
||||
if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null)
|
||||
return true;
|
||||
|
||||
if (api.State != APIState.Online)
|
||||
return false;
|
||||
|
||||
Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database);
|
||||
|
||||
try
|
||||
@@ -418,6 +427,12 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database);
|
||||
|
||||
if (otherBeatmaps.Any(b => b.OnlineBeatmapID == res.OnlineBeatmapID))
|
||||
{
|
||||
Logger.Log("Another beatmap in the same set already mapped to this ID. We'll skip adding it this time.", LoggingTarget.Database);
|
||||
return false;
|
||||
}
|
||||
|
||||
beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID;
|
||||
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
|
||||
return true;
|
||||
@@ -446,5 +461,21 @@ namespace osu.Game.Beatmaps
|
||||
protected override Texture GetBackground() => null;
|
||||
protected override Track GetTrack() => null;
|
||||
}
|
||||
|
||||
private class DownloadNotification : ProgressNotification
|
||||
{
|
||||
public override bool IsImportant => false;
|
||||
|
||||
protected override Notification CreateCompletionNotification() => new SilencedProgressCompletionNotification
|
||||
{
|
||||
Activated = CompletionClickAction,
|
||||
Text = CompletionText
|
||||
};
|
||||
|
||||
private class SilencedProgressCompletionNotification : ProgressCompletionNotification
|
||||
{
|
||||
public override bool IsImportant => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
var newSampleInfo = sampleInfo.Clone();
|
||||
newSampleInfo.Bank = sampleInfo.Bank ?? SampleBank;
|
||||
newSampleInfo.Name = sampleInfo.Name;
|
||||
newSampleInfo.Volume = sampleInfo.Volume > 0 ? sampleInfo.Volume : SampleVolume;
|
||||
return newSampleInfo;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
@@ -19,9 +20,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the associated beatmap set has been downloading (by this instance or any other instance).
|
||||
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
|
||||
/// </summary>
|
||||
public readonly BindableBool Downloaded = new BindableBool();
|
||||
public readonly Bindable<DownloadStatus> DownloadState = new Bindable<DownloadStatus>();
|
||||
|
||||
public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false)
|
||||
{
|
||||
@@ -36,10 +37,16 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
beatmaps.ItemRemoved += setRemoved;
|
||||
beatmaps.BeatmapDownloadBegan += downloadBegan;
|
||||
beatmaps.BeatmapDownloadFailed += downloadFailed;
|
||||
|
||||
// initial value
|
||||
if (set.OnlineBeatmapSetID != null)
|
||||
Downloaded.Value = beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any();
|
||||
if (set.OnlineBeatmapSetID != null && beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any())
|
||||
DownloadState.Value = DownloadStatus.Downloaded;
|
||||
else if (beatmaps.GetExistingDownload(set) != null)
|
||||
DownloadState.Value = DownloadStatus.Downloading;
|
||||
else
|
||||
DownloadState.Value = DownloadStatus.NotDownloaded;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
@@ -50,6 +57,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
beatmaps.ItemAdded -= setAdded;
|
||||
beatmaps.ItemRemoved -= setRemoved;
|
||||
beatmaps.BeatmapDownloadBegan -= downloadBegan;
|
||||
beatmaps.BeatmapDownloadFailed -= downloadFailed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,28 +66,45 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
/// Begin downloading the associated beatmap set.
|
||||
/// </summary>
|
||||
/// <returns>True if downloading began. False if an existing download is active or completed.</returns>
|
||||
public bool Download()
|
||||
public void Download()
|
||||
{
|
||||
if (Downloaded.Value)
|
||||
return false;
|
||||
|
||||
if (beatmaps.GetExistingDownload(set) != null)
|
||||
return false;
|
||||
if (DownloadState.Value > DownloadStatus.NotDownloaded)
|
||||
return;
|
||||
|
||||
beatmaps.Download(set, noVideo);
|
||||
return true;
|
||||
|
||||
DownloadState.Value = DownloadStatus.Downloading;
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo s)
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
Downloaded.Value = true;
|
||||
DownloadState.Value = DownloadStatus.Downloaded;
|
||||
}
|
||||
|
||||
private void setRemoved(BeatmapSetInfo s)
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
Downloaded.Value = false;
|
||||
DownloadState.Value = DownloadStatus.NotDownloaded;
|
||||
}
|
||||
|
||||
private void downloadBegan(DownloadBeatmapSetRequest d)
|
||||
{
|
||||
if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
DownloadState.Value = DownloadStatus.Downloading;
|
||||
}
|
||||
|
||||
private void downloadFailed(DownloadBeatmapSetRequest d)
|
||||
{
|
||||
if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
DownloadState.Value = DownloadStatus.NotDownloaded;
|
||||
}
|
||||
|
||||
public enum DownloadStatus
|
||||
{
|
||||
NotDownloaded,
|
||||
Downloading,
|
||||
Downloaded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
if (value == status) return;
|
||||
status = value;
|
||||
|
||||
statusText.Text = Enum.GetName(typeof(BeatmapSetOnlineStatus), Status)?.ToUpper();
|
||||
statusText.Text = Enum.GetName(typeof(BeatmapSetOnlineStatus), Status)?.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public class DifficultyColouredContainer : Container, IHasAccentColour
|
||||
public abstract class DifficultyColouredContainer : Container, IHasAccentColour
|
||||
{
|
||||
public Color4 AccentColour { get; set; }
|
||||
|
||||
private readonly BeatmapInfo beatmap;
|
||||
private OsuColour palette;
|
||||
|
||||
public DifficultyColouredContainer(BeatmapInfo beatmap)
|
||||
protected DifficultyColouredContainer(BeatmapInfo beatmap)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
@@ -14,7 +18,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
private readonly BeatmapInfo beatmap;
|
||||
|
||||
public DifficultyIcon(BeatmapInfo beatmap) : base(beatmap)
|
||||
public DifficultyIcon(BeatmapInfo beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
@@ -28,16 +33,29 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SpriteIcon
|
||||
new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.84f),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Icon = FontAwesome.fa_circle
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.08f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 5,
|
||||
},
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
},
|
||||
},
|
||||
new ConstrainedIconContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
// the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment)
|
||||
Icon = beatmap.Ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.fa_question_circle_o }
|
||||
|
||||
@@ -62,28 +62,30 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected override void ParseLine(Beatmap beatmap, Section section, string line)
|
||||
{
|
||||
var strippedLine = StripComments(line);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case Section.General:
|
||||
handleGeneral(line);
|
||||
handleGeneral(strippedLine);
|
||||
return;
|
||||
case Section.Editor:
|
||||
handleEditor(line);
|
||||
handleEditor(strippedLine);
|
||||
return;
|
||||
case Section.Metadata:
|
||||
handleMetadata(line);
|
||||
return;
|
||||
case Section.Difficulty:
|
||||
handleDifficulty(line);
|
||||
handleDifficulty(strippedLine);
|
||||
return;
|
||||
case Section.Events:
|
||||
handleEvent(line);
|
||||
handleEvent(strippedLine);
|
||||
return;
|
||||
case Section.TimingPoints:
|
||||
handleTimingPoint(line);
|
||||
handleTimingPoint(strippedLine);
|
||||
return;
|
||||
case Section.HitObjects:
|
||||
handleHitObject(line);
|
||||
handleHitObject(strippedLine);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -305,12 +307,12 @@ namespace osu.Game.Beatmaps.Formats
|
||||
bool omitFirstBarSignature = false;
|
||||
if (split.Length >= 8)
|
||||
{
|
||||
int effectFlags = int.Parse(split[7]);
|
||||
kiaiMode = (effectFlags & 1) > 0;
|
||||
omitFirstBarSignature = (effectFlags & 8) > 0;
|
||||
EffectFlags effectFlags = (EffectFlags)int.Parse(split[7]);
|
||||
kiaiMode = effectFlags.HasFlag(EffectFlags.Kiai);
|
||||
omitFirstBarSignature = effectFlags.HasFlag(EffectFlags.OmitFirstBarLine);
|
||||
}
|
||||
|
||||
string stringSampleSet = sampleSet.ToString().ToLower();
|
||||
string stringSampleSet = sampleSet.ToString().ToLowerInvariant();
|
||||
if (stringSampleSet == @"none")
|
||||
stringSampleSet = @"normal";
|
||||
|
||||
@@ -405,5 +407,13 @@ namespace osu.Game.Beatmaps.Formats
|
||||
private double getOffsetTime() => ApplyOffsets ? offset : 0;
|
||||
|
||||
private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0);
|
||||
|
||||
[Flags]
|
||||
internal enum EffectFlags
|
||||
{
|
||||
None = 0,
|
||||
Kiai = 1,
|
||||
OmitFirstBarLine = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected virtual void ParseLine(T output, Section section, string line)
|
||||
{
|
||||
line = StripComments(line);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case Section.Colours:
|
||||
@@ -65,6 +67,14 @@ namespace osu.Game.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
protected string StripComments(string line)
|
||||
{
|
||||
var index = line.IndexOf("//", StringComparison.Ordinal);
|
||||
if (index > 0)
|
||||
return line.Substring(0, index);
|
||||
return line;
|
||||
}
|
||||
|
||||
private bool hasComboColours;
|
||||
|
||||
private void handleColours(T output, string line)
|
||||
@@ -178,7 +188,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
var baseInfo = base.ApplyTo(sampleInfo);
|
||||
|
||||
if (CustomSampleBank > 1)
|
||||
if (string.IsNullOrEmpty(baseInfo.Suffix) && CustomSampleBank > 1)
|
||||
baseInfo.Suffix = CustomSampleBank.ToString();
|
||||
|
||||
return baseInfo;
|
||||
|
||||
@@ -42,6 +42,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected override void ParseLine(Storyboard storyboard, Section section, string line)
|
||||
{
|
||||
line = StripComments(line);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case Section.Events:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user