1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-02 05:30:17 +08:00

Compare commits

..

2 Commits

133 changed files with 983 additions and 1843 deletions
+7 -23
View File
@@ -11,11 +11,7 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Debug)",
"linux": {
"env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"env": {},
"console": "internalConsole"
},
{
@@ -28,11 +24,7 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Release)",
"linux": {
"env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"env": {},
"console": "internalConsole"
},
{
@@ -41,15 +33,11 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll"
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug)",
"linux": {
"env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"env": {},
"console": "internalConsole"
},
{
@@ -58,16 +46,12 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll"
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release)",
"linux": {
"env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"env": {},
"console": "internalConsole"
}
]
}
}
+6 -20
View File
@@ -1,32 +1,18 @@
# osu! [![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu) [![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu) [![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy)
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Commonly known by the codename "osu!lazer". Pew pew.
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era!
# Status
This project is still heavily under development, but is in a state where users are encouraged to try it out and keep it installed alongside the stable osu! client. It will continue to evolve over the coming months and hopefully bring some new unique features to the table.
We are accepting bug reports (please report with as much detail as possible). Feature requests are welcome as long as you read and understand the contribution guidelines listed below.
This is still heavily under development and is not intended for end-user use. This repository is intended for developer collaboration. You're welcome to try and use it but please do not submit bug reports without a patch. Please do not ask for help building or using this software.
# Requirements
- A desktop platform with the [.NET Core SDK 2.1](https://www.microsoft.com/net/learn/get-started) or higher installed.
- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio Code](https://code.visualstudio.com/) (with the C# plugin installed) or [Jetbrains Rider](https://www.jetbrains.com/rider/) (commercial).
- A desktop platform that can compile .NET 4.7.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
# Building and running
If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled (download and run the install executable for your platform).
Clone the repository including submodules
`git clone --recurse-submodules https://github.com/ppy/osu`
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`
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`).
# Getting Started
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
- Build in your IDE of choice (recommended IDEs automatically restore nuget packages; if you are using an alternative make sure to `nuget restore`)
# Contributing
+1 -4
View File
@@ -2,9 +2,6 @@ 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
@@ -21,4 +18,4 @@ build:
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
+40 -47
View File
@@ -12,7 +12,6 @@ using osu.Framework.Platform;
using osu.Game;
using OpenTK.Input;
using Microsoft.Win32;
using osu.Desktop.Updater;
using osu.Framework.Platform.Windows;
namespace osu.Desktop
@@ -39,52 +38,6 @@ namespace osu.Desktop
}
}
protected override void LoadComplete()
{
base.LoadComplete();
if (!noVersionOverlay)
{
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
v.State = Visibility.Visible;
});
#if NET_FRAMEWORK
Add(new SquirrelUpdateManager());
#else
Add(new SimpleUpdateManager());
#endif
}
}
public override void SetHost(GameHost host)
{
base.SetHost(host);
var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null)
{
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
desktopWindow.Title = Name;
desktopWindow.FileDrop += fileDrop;
}
}
private void fileDrop(object sender, FileDropEventArgs e)
{
var filePaths = new[] { e.FileName };
var firstExtension = Path.GetExtension(filePaths.First());
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
}
/// <summary>
/// A method of accessing an osu-stable install in a controlled fashion.
/// </summary>
@@ -124,5 +77,45 @@ namespace osu.Desktop
{
}
}
protected override void LoadComplete()
{
base.LoadComplete();
if (!noVersionOverlay)
{
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
v.State = Visibility.Visible;
});
}
}
public override void SetHost(GameHost host)
{
base.SetHost(host);
var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null)
{
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
desktopWindow.Title = Name;
desktopWindow.FileDrop += fileDrop;
}
}
private void fileDrop(object sender, FileDropEventArgs e)
{
var filePaths = new[] { e.FileName };
var firstExtension = Path.GetExtension(filePaths.First());
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
}
}
}
@@ -3,7 +3,6 @@
#if NET_FRAMEWORK
using System;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
@@ -17,7 +16,7 @@ using OpenTK;
using OpenTK.Graphics;
using Squirrel;
namespace osu.Desktop.Updater
namespace osu.Desktop.Overlays
{
public class SquirrelUpdateManager : Component
{
@@ -36,7 +35,7 @@ namespace osu.Desktop.Updater
notificationOverlay = notification;
if (game.IsDeployedBuild)
Schedule(() => Task.Run(() => checkForUpdateAsync()));
Schedule(() => checkForUpdateAsync());
}
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
+4 -2
View File
@@ -91,6 +91,10 @@ namespace osu.Desktop.Overlays
}
}
};
#if NET_FRAMEWORK
Add(new SquirrelUpdateManager());
#endif
}
protected override void LoadComplete()
@@ -111,8 +115,6 @@ namespace osu.Desktop.Overlays
private class UpdateCompleteNotification : SimpleNotification
{
public override bool IsImportant => true;
public UpdateCompleteNotification(string version, Action<string> openUrl = null)
{
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
+5 -3
View File
@@ -7,7 +7,6 @@ using System.Linq;
using osu.Framework;
using osu.Framework.Platform;
using osu.Game.IPC;
#if NET_FRAMEWORK
using System.Runtime;
#endif
@@ -19,7 +18,10 @@ namespace osu.Desktop
[STAThread]
public static int Main(string[] args)
{
useMultiCoreJit();
// required to initialise native SQLite libraries on some platforms.
if (!RuntimeInfo.IsMono)
useMulticoreJit();
// Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory;
@@ -52,7 +54,7 @@ namespace osu.Desktop
}
}
private static void useMultiCoreJit()
private static void useMulticoreJit()
{
#if NET_FRAMEWORK
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
-108
View File
@@ -1,108 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.IO.Network;
using osu.Framework.Platform;
using osu.Game;
using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Desktop.Updater
{
/// <summary>
/// An update manager that shows notifications if a newer release is detected.
/// Installation is left up to the user.
/// </summary>
internal class SimpleUpdateManager : CompositeDrawable
{
private NotificationOverlay notificationOverlay;
private string version;
private GameHost host;
[BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuGameBase game, GameHost host)
{
notificationOverlay = notification;
this.host = host;
version = game.Version;
if (game.IsDeployedBuild)
Schedule(() => Task.Run(() => checkForUpdateAsync()));
}
private async void checkForUpdateAsync()
{
var releases = new JsonWebRequest<GitHubRelease>("https://api.github.com/repos/ppy/osu/releases/latest");
await releases.PerformAsync();
var latest = releases.ResponseObject;
if (latest.TagName != version)
{
notificationOverlay.Post(new UpdateNotification
{
Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n"
+ "Click here to download the new version, which can be installed over the top of your existing installation",
Icon = FontAwesome.fa_upload,
Activated = () =>
{
host.OpenUrlExternally(getBestUrl(latest));
return true;
}
});
}
}
private class UpdateNotification : SimpleNotification
{
public override bool IsImportant => true;
}
private string getBestUrl(GitHubRelease release)
{
GitHubAsset bestAsset = null;
switch (RuntimeInfo.OS)
{
case RuntimeInfo.Platform.Windows:
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe"));
break;
case RuntimeInfo.Platform.MacOsx:
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".app.zip"));
break;
}
return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
}
public class GitHubRelease
{
[JsonProperty("html_url")]
public string HtmlUrl { get; set; }
[JsonProperty("tag_name")]
public string TagName { get; set; }
[JsonProperty("assets")]
public List<GitHubAsset> Assets { get; set; }
}
public class GitHubAsset
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("browser_download_url")]
public string BrowserDownloadUrl { get; set; }
}
}
}
@@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperDashState(status ? 2 : 1);
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperdashState(status ? 2 : 1);
}
}
}
@@ -8,9 +8,9 @@ using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
public class TestCaseHyperDash : Game.Tests.Visual.TestCasePlayer
public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
{
public TestCaseHyperDash()
public TestCaseHyperdash()
: base(new CatchRuleset())
{
}
@@ -61,12 +61,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty
return new CatchDifficultyAttributes(mods, 0);
// this is the same as osu!, so there's potential to share the implementation... maybe
double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
double preEmpt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;
return new CatchDifficultyAttributes(mods, starRating)
{
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0,
MaxCombo = difficultyHitObjects.Count
};
}
+13 -13
View File
@@ -255,11 +255,11 @@ namespace osu.Game.Rulesets.Catch.UI
double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition;
double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
SetHyperDashState(Math.Abs(velocity), target.X);
SetHyperdashState(Math.Abs(velocity), target.X);
}
else
{
SetHyperDashState();
SetHyperdashState();
}
return validCatch;
@@ -270,18 +270,18 @@ namespace osu.Game.Rulesets.Catch.UI
private float hyperDashTargetPosition;
/// <summary>
/// Whether we are hyper-dashing or not.
/// Whether we are hypderdashing or not.
/// </summary>
public bool HyperDashing => hyperDashModifier != 1;
/// <summary>
/// Set hyper-dash state.
/// Set hyperdash state.
/// </summary>
/// <param name="modifier">The speed multiplier. If this is less or equals to 1, this catcher will be non-hyper-dashing state.</param>
/// <param name="targetPosition">When this catcher crosses this position, this catcher ends hyper-dashing.</param>
public void SetHyperDashState(double modifier = 1, float targetPosition = -1)
/// <param name="modifier">The speed multiplier. If this is less or equals to 1, this catcher will be non-hyperdashing state.</param>
/// <param name="targetPosition">When this catcher crosses this position, this catcher ends hyperdashing.</param>
public void SetHyperdashState(double modifier = 1, float targetPosition = -1)
{
const float hyper_dash_transition_length = 180;
const float hyperdash_transition_length = 180;
bool previouslyHyperDashing = HyperDashing;
if (modifier <= 1 || X == targetPosition)
@@ -291,8 +291,8 @@ namespace osu.Game.Rulesets.Catch.UI
if (previouslyHyperDashing)
{
this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
this.FadeColour(Color4.White, hyperdash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyperdash_transition_length, Easing.OutQuint);
}
}
else
@@ -303,8 +303,8 @@ namespace osu.Game.Rulesets.Catch.UI
if (!previouslyHyperDashing)
{
this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
this.FadeColour(Color4.OrangeRed, hyperdash_transition_length, Easing.OutQuint);
this.FadeTo(0.2f, hyperdash_transition_length, Easing.OutQuint);
Trail = true;
}
}
@@ -370,7 +370,7 @@ namespace osu.Game.Rulesets.Catch.UI
hyperDashDirection < 0 && hyperDashTargetPosition > X)
{
X = hyperDashTargetPosition;
SetHyperDashState();
SetHyperdashState();
}
}
@@ -5,8 +5,6 @@ using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@@ -15,10 +13,11 @@ using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
[NonParallelizable]
[TestCase("basic")]
public new void Test(string name)
{
@@ -35,35 +34,9 @@ namespace osu.Game.Rulesets.Mania.Tests
};
}
protected override ManiaConvertMapping CreateConvertMapping() => new ManiaConvertMapping(Converter);
protected override Ruleset CreateRuleset() => new ManiaRuleset();
}
public class ManiaConvertMapping : ConvertMapping<ConvertValue>, IEquatable<ManiaConvertMapping>
{
public uint RandomW;
public uint RandomX;
public uint RandomY;
public uint RandomZ;
public ManiaConvertMapping()
{
}
public ManiaConvertMapping(IBeatmapConverter converter)
{
var maniaConverter = (ManiaBeatmapConverter)converter;
RandomW = maniaConverter.Random.W;
RandomX = maniaConverter.Random.X;
RandomY = maniaConverter.Random.Y;
RandomZ = maniaConverter.Random.Z;
}
public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
public override bool Equals(ConvertMapping<ConvertValue> other) => base.Equals(other) && Equals(other as ManiaConvertMapping);
}
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
@@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Mania.Tests
this.direction = direction;
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }});
return dependencies;
}
@@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.Mania.Tests
};
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
return dependencies;
}
@@ -153,6 +153,9 @@ namespace osu.Game.Rulesets.Mania.Tests
if (!(obj.HitObject is IHasEndTime endTime))
continue;
if (!obj.HasNestedHitObjects)
continue;
foreach (var nested in obj.NestedHitObjects)
{
double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration;
@@ -5,7 +5,6 @@ using osu.Game.Rulesets.Mania.Objects;
using System;
using System.Linq;
using System.Collections.Generic;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@@ -29,10 +28,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
public int TargetColumns;
public readonly bool IsForCurrentRuleset;
// Internal for testing purposes
internal FastRandom Random { get; private set; }
private Pattern lastPattern = new Pattern();
private FastRandom random;
private ManiaBeatmap beatmap;
@@ -65,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
Random = new FastRandom(seed);
random = new FastRandom(seed);
return base.ConvertBeatmap(original);
}
@@ -103,7 +100,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private double lastTime;
private Vector2 lastPosition;
private PatternType lastStair = PatternType.Stair;
private PatternType lastStair;
private void recordNote(double time, Vector2 position)
{
lastTime = time;
@@ -118,15 +115,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap)
{
var generator = new SpecificBeatmapPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap);
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
foreach (var newPattern in generator.Generate())
{
lastPattern = newPattern;
Pattern newPattern = generator.Generate();
lastPattern = newPattern;
foreach (var obj in newPattern.HitObjects)
yield return obj;
}
return newPattern.HitObjects;
}
/// <summary>
@@ -144,44 +138,27 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
Patterns.PatternGenerator conversion = null;
if (distanceData != null)
{
var generator = new DistanceObjectPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap);
conversion = generator;
for (double time = original.StartTime; !Precision.DefinitelyBigger(time, generator.EndTime); time += generator.SegmentDuration)
{
recordNote(time, positionData?.Position ?? Vector2.Zero);
computeDensity(time);
}
}
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
else if (endTimeData != null)
{
conversion = new EndTimeObjectPatternGenerator(Random, original, beatmap, originalBeatmap);
recordNote(endTimeData.EndTime, new Vector2(256, 192));
computeDensity(endTimeData.EndTime);
}
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, originalBeatmap);
else if (positionData != null)
{
computeDensity(original.StartTime);
conversion = new HitObjectPatternGenerator(Random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
recordNote(original.StartTime, positionData.Position);
}
if (conversion == null)
yield break;
return null;
foreach (var newPattern in conversion.Generate())
{
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
Pattern newPattern = conversion.Generate();
foreach (var obj in newPattern.HitObjects)
yield return obj;
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
}
return newPattern.HitObjects;
}
/// <summary>
@@ -194,12 +171,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
{
}
public override IEnumerable<Pattern> Generate()
{
yield return generate();
}
private Pattern generate()
public override Pattern Generate()
{
var endTimeData = HitObject as IHasEndTime;
var positionData = HitObject as IHasXPosition;
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.MathUtils;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.MathUtils;
@@ -25,9 +24,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// </summary>
private const float osu_base_scoring_distance = 100;
public readonly double EndTime;
public readonly double SegmentDuration;
private readonly double endTime;
private readonly double segmentDuration;
private readonly int spanCount;
private PatternType convertType;
@@ -54,81 +52,53 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// The duration of the osu! hit object
double osuDuration = distance / osuVelocity;
EndTime = hitObject.StartTime + osuDuration;
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
endTime = hitObject.StartTime + osuDuration;
segmentDuration = (endTime - HitObject.StartTime) / spanCount;
}
public override IEnumerable<Pattern> Generate()
{
var originalPattern = generate();
if (originalPattern.HitObjects.Count() == 1)
{
yield return originalPattern;
yield break;
}
// We need to split the intermediate pattern into two new patterns:
// 1. A pattern containing all objects that do not end at our EndTime.
// 2. A pattern containing all objects that end at our EndTime. This will be used for further pattern generation.
var intermediatePattern = new Pattern();
var endTimePattern = new Pattern();
foreach (var obj in originalPattern.HitObjects)
{
if (!Precision.AlmostEquals(EndTime, (obj as IHasEndTime)?.EndTime ?? obj.StartTime))
intermediatePattern.Add(obj);
else
endTimePattern.Add(obj);
}
yield return intermediatePattern;
yield return endTimePattern;
}
private Pattern generate()
public override Pattern Generate()
{
if (TotalColumns == 1)
{
var pattern = new Pattern();
addToPattern(pattern, 0, HitObject.StartTime, EndTime);
addToPattern(pattern, 0, HitObject.StartTime, endTime);
return pattern;
}
if (spanCount > 1)
{
if (SegmentDuration <= 90)
if (segmentDuration <= 90)
return generateRandomHoldNotes(HitObject.StartTime, 1);
if (SegmentDuration <= 120)
if (segmentDuration <= 120)
{
convertType |= PatternType.ForceNotStack;
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
}
if (SegmentDuration <= 160)
if (segmentDuration <= 160)
return generateStair(HitObject.StartTime);
if (SegmentDuration <= 200 && ConversionDifficulty > 3)
if (segmentDuration <= 200 && ConversionDifficulty > 3)
return generateRandomMultipleNotes(HitObject.StartTime);
double duration = EndTime - HitObject.StartTime;
double duration = endTime - HitObject.StartTime;
if (duration >= 4000)
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
if (SegmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
if (segmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
return generateTiledHoldNotes(HitObject.StartTime);
return generateHoldAndNormalNotes(HitObject.StartTime);
}
if (SegmentDuration <= 110)
if (segmentDuration <= 110)
{
if (PreviousPattern.ColumnWithObjects < TotalColumns)
convertType |= PatternType.ForceNotStack;
else
convertType &= ~PatternType.ForceNotStack;
return generateRandomNotes(HitObject.StartTime, SegmentDuration < 80 ? 1 : 2);
return generateRandomNotes(HitObject.StartTime, segmentDuration < 80 ? 1 : 2);
}
if (ConversionDifficulty > 6.5)
@@ -178,7 +148,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(pattern, nextColumn, startTime, EndTime);
addToPattern(pattern, nextColumn, startTime, endTime);
}
// This is can't be combined with the above loop due to RNG
@@ -186,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
while (pattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(pattern, nextColumn, startTime, EndTime);
addToPattern(pattern, nextColumn, startTime, endTime);
}
return pattern;
@@ -223,7 +193,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
nextColumn = Random.Next(RandomStart, TotalColumns);
lastColumn = nextColumn;
startTime += SegmentDuration;
startTime += segmentDuration;
}
return pattern;
@@ -253,7 +223,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
for (int i = 0; i <= spanCount; i++)
{
addToPattern(pattern, column, startTime, startTime);
startTime += SegmentDuration;
startTime += segmentDuration;
// Check if we're at the borders of the stage, and invert the pattern if so
if (increasing)
@@ -314,7 +284,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
addToPattern(pattern, nextColumn, startTime, startTime);
nextColumn = Random.Next(RandomStart, TotalColumns);
startTime += SegmentDuration;
startTime += segmentDuration;
}
return pattern;
@@ -402,8 +372,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
while (pattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(pattern, nextColumn, startTime, EndTime);
startTime += SegmentDuration;
addToPattern(pattern, nextColumn, startTime, endTime);
startTime += segmentDuration;
}
return pattern;
@@ -432,7 +402,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
}
// Create the hold note
addToPattern(pattern, holdColumn, startTime, EndTime);
addToPattern(pattern, holdColumn, startTime, endTime);
int nextColumn = Random.Next(RandomStart, TotalColumns);
int noteCount;
@@ -464,7 +434,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
pattern.Add(rowPattern);
rowPattern.Clear();
startTime += SegmentDuration;
startTime += segmentDuration;
}
return pattern;
@@ -482,7 +452,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (curveData == null)
return HitObject.Samples;
double segmentTime = (EndTime - HitObject.StartTime) / spanCount;
double segmentTime = (endTime - HitObject.StartTime) / spanCount;
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
return curveData.RepeatSamples[index];
@@ -19,15 +19,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap)
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
{
endTime = (HitObject as IHasEndTime)?.EndTime ?? 0;
var endtimeData = HitObject as IHasEndTime;
endTime = endtimeData?.EndTime ?? 0;
}
public override IEnumerable<Pattern> Generate()
{
yield return generate();
}
private Pattern generate()
public override Pattern Generate()
{
var pattern = new Pattern();
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using OpenTK;
using osu.Game.Audio;
@@ -83,133 +82,127 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
convertType |= PatternType.Mirror;
else if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP))
else
convertType |= PatternType.Gathered;
}
}
public override IEnumerable<Pattern> Generate()
public override Pattern Generate()
{
yield return generate();
}
private Pattern generate()
{
var pattern = new Pattern();
try
if (TotalColumns == 1)
{
if (TotalColumns == 1)
var pattern = new Pattern();
addToPattern(pattern, 0);
return pattern;
}
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
{
// Generate a new pattern by copying the last hit objects in reverse-column order
var pattern = new Pattern();
for (int i = RandomStart; i < TotalColumns; i++)
if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
return pattern;
}
if ((convertType & PatternType.Cycle) > 0 && 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
&& (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
{
// Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object)
var pattern = new Pattern();
int column = RandomStart + TotalColumns - lastColumn - 1;
addToPattern(pattern, column);
return pattern;
}
if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Any())
{
// Generate a new pattern by placing on the already filled columns
var pattern = new Pattern();
for (int i = RandomStart; i < TotalColumns; i++)
if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, i);
return pattern;
}
if ((convertType & PatternType.Stair) > 0 && PreviousPattern.HitObjects.Count() == 1)
{
// Generate a new pattern by placing on the next column, cycling back to the start if there is no "next"
var pattern = new Pattern();
int targetColumn = lastColumn + 1;
if (targetColumn == TotalColumns)
{
addToPattern(pattern, 0);
return pattern;
targetColumn = RandomStart;
StairType = PatternType.ReverseStair;
}
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
addToPattern(pattern, targetColumn);
return pattern;
}
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1)
{
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
var pattern = new Pattern();
int targetColumn = lastColumn - 1;
if (targetColumn == RandomStart - 1)
{
// Generate a new pattern by copying the last hit objects in reverse-column order
for (int i = RandomStart; i < TotalColumns; i++)
if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
return pattern;
targetColumn = TotalColumns - 1;
StairType = PatternType.Stair;
}
if ((convertType & PatternType.Cycle) > 0 && 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
&& (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
{
// Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object)
int column = RandomStart + TotalColumns - lastColumn - 1;
addToPattern(pattern, column);
addToPattern(pattern, targetColumn);
return pattern;
}
return pattern;
}
if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Any())
{
// Generate a new pattern by placing on the already filled columns
for (int i = RandomStart; i < TotalColumns; i++)
if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, i);
return pattern;
}
if (PreviousPattern.HitObjects.Count() == 1)
{
if ((convertType & PatternType.Stair) > 0)
{
// Generate a new pattern by placing on the next column, cycling back to the start if there is no "next"
int targetColumn = lastColumn + 1;
if (targetColumn == TotalColumns)
targetColumn = RandomStart;
addToPattern(pattern, targetColumn);
return pattern;
}
if ((convertType & PatternType.ReverseStair) > 0)
{
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
int targetColumn = lastColumn - 1;
if (targetColumn == RandomStart - 1)
targetColumn = TotalColumns - 1;
addToPattern(pattern, targetColumn);
return pattern;
}
}
if ((convertType & PatternType.KeepSingle) > 0)
return pattern = generateRandomNotes(1);
if ((convertType & PatternType.Mirror) > 0)
{
if (ConversionDifficulty > 6.5)
return pattern = generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
if (ConversionDifficulty > 4)
return pattern = generateRandomPatternWithMirrored(0.12, 0.17, 0);
return pattern = generateRandomPatternWithMirrored(0.12, 0, 0);
}
if ((convertType & PatternType.KeepSingle) > 0)
return generateRandomNotes(1);
if ((convertType & PatternType.Mirror) > 0)
{
if (ConversionDifficulty > 6.5)
{
if ((convertType & PatternType.LowProbability) > 0)
return pattern = generateRandomPattern(0.78, 0.42, 0, 0);
return pattern = generateRandomPattern(1, 0.62, 0, 0);
}
return generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
if (ConversionDifficulty > 4)
{
if ((convertType & PatternType.LowProbability) > 0)
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)
return pattern = generateRandomPattern(0.18, 0, 0, 0);
return pattern = generateRandomPattern(0.45, 0, 0, 0);
}
return pattern = generateRandomPattern(0, 0, 0, 0);
return generateRandomPatternWithMirrored(0.12, 0.17, 0);
return generateRandomPatternWithMirrored(0.12, 0, 0);
}
finally
if (ConversionDifficulty > 6.5)
{
foreach (var obj in pattern.HitObjects)
{
if ((convertType & PatternType.Stair) > 0 && obj.Column == TotalColumns - 1)
StairType = PatternType.ReverseStair;
if ((convertType & PatternType.ReverseStair) > 0 && obj.Column == RandomStart)
StairType = PatternType.Stair;
}
if ((convertType & PatternType.LowProbability) > 0)
return generateRandomPattern(0.78, 0.42, 0, 0);
return generateRandomPattern(1, 0.62, 0, 0);
}
if (ConversionDifficulty > 4)
{
if ((convertType & PatternType.LowProbability) > 0)
return generateRandomPattern(0.35, 0.08, 0, 0);
return generateRandomPattern(0.52, 0.15, 0, 0);
}
if (ConversionDifficulty > 2)
{
if ((convertType & PatternType.LowProbability) > 0)
return generateRandomPattern(0.18, 0, 0, 0);
return generateRandomPattern(0.45, 0, 0, 0);
}
return generateRandomPattern(0, 0, 0, 0);
}
/// <summary>
@@ -103,14 +103,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault();
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault();
// Drain time in seconds
int drainTime = (int)(((lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0) - OriginalBeatmap.TotalBreakTime) / 1000);
double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0);
drainTime -= OriginalBeatmap.TotalBreakTime;
if (drainTime == 0)
drainTime = 10000;
drainTime = 10000000;
// We need this in seconds
drainTime /= 1000;
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
return conversionDifficulty.Value;
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
@@ -43,9 +42,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
}
/// <summary>
/// Generates the patterns for <see cref="HitObject"/>, each filled with hit objects.
/// Generates the pattern for <see cref="HitObject"/>, filled with hit objects.
/// </summary>
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
public abstract IEnumerable<Pattern> Generate();
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
public abstract Pattern Generate();
}
}
@@ -19,14 +19,14 @@ namespace osu.Game.Rulesets.Mania
}
[BackgroundDependencyLoader]
private void load()
private void load(ManiaConfigManager config)
{
Children = new Drawable[]
{
new SettingsEnumDropdown<ManiaScrollingDirection>
{
LabelText = "Scrolling direction",
Bindable = ((ManiaConfigManager)Config).GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
Bindable = config.GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
}
};
}
@@ -15,15 +15,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils
private const uint y = 842502087;
private const uint z = 3579807591;
private const uint w = 273326509;
internal uint X { get; private set; }
internal uint Y { get; private set; } = y;
internal uint Z { get; private set; } = z;
internal uint W { get; private set; } = w;
private uint _x, _y = y, _z = z, _w = w;
public FastRandom(int seed)
{
X = (uint)seed;
_x = (uint)seed;
}
public FastRandom()
@@ -37,11 +33,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils
/// <returns>The random value.</returns>
public uint NextUInt()
{
uint t = X ^ X << 11;
X = Y;
Y = Z;
Z = W;
return W = W ^ W >> 19 ^ t ^ t >> 8;
uint t = _x ^ _x << 11;
_x = _y;
_y = _z;
_z = _w;
return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
}
/// <summary>
@@ -1,132 +1,103 @@
{
"Mappings": [{
"RandomW": 2659373485,
"RandomX": 3579807591,
"RandomY": 273326509,
"RandomZ": 272969173,
"StartTime": 500.0,
"Objects": [{
"StartTime": 500.0,
"EndTime": 2500.0,
"Column": 0
}, {
"StartTime": 1500.0,
"EndTime": 2500.0,
"Column": 1
}]
}, {
"RandomW": 3083803045,
"RandomX": 273326509,
"RandomY": 272969173,
"RandomZ": 2659373485,
"StartTime": 3000.0,
"Objects": [{
"StartTime": 3000.0,
"EndTime": 4000.0,
"Column": 2
}]
}, {
"RandomW": 4073554232,
"RandomX": 272969173,
"RandomY": 2659373485,
"RandomZ": 3083803045,
"StartTime": 4500.0,
"Objects": [{
"StartTime": 4500.0,
"EndTime": 5500.0,
"Column": 4
}]
}, {
"RandomW": 3420401969,
"RandomX": 2659373485,
"RandomY": 3083803045,
"RandomZ": 4073554232,
"StartTime": 6000.0,
"Objects": [{
"StartTime": 6000.0,
"EndTime": 6500.0,
"Column": 2
}]
}, {
"RandomW": 1129881182,
"RandomX": 3083803045,
"RandomY": 4073554232,
"RandomZ": 3420401969,
"StartTime": 7000.0,
"Objects": [{
"StartTime": 7000.0,
"EndTime": 8000.0,
"Column": 2
}]
}, {
"RandomW": 315568458,
"RandomX": 3420401969,
"RandomY": 1129881182,
"RandomZ": 2358617505,
"StartTime": 8500.0,
"Objects": [{
"StartTime": 8500.0,
"EndTime": 11000.0,
"Column": 0
}]
}, {
"RandomW": 548134043,
"RandomX": 1129881182,
"RandomY": 2358617505,
"RandomZ": 315568458,
"StartTime": 11500.0,
"Objects": [{
"StartTime": 11500.0,
"EndTime": 12000.0,
"Column": 1
}]
}, {
"RandomW": 3979422122,
"RandomX": 548134043,
"RandomY": 2810584254,
"RandomZ": 2250186050,
"StartTime": 12500.0,
"Objects": [{
"StartTime": 12500.0,
"EndTime": 16500.0,
"Column": 4
}]
}, {
"RandomW": 2466283411,
"RandomX": 2810584254,
"RandomY": 2250186050,
"RandomZ": 3979422122,
"StartTime": 17000.0,
"Objects": [{
"StartTime": 17000.0,
"EndTime": 18000.0,
"Column": 2
}]
}, {
"RandomW": 83157665,
"RandomX": 2250186050,
"RandomY": 3979422122,
"RandomZ": 2466283411,
"StartTime": 18500.0,
"Objects": [{
"StartTime": 18500.0,
"EndTime": 19450.0,
"Column": 0
}]
}, {
"RandomW": 2383087700,
"RandomX": 83157665,
"RandomY": 2055150192,
"RandomZ": 510071020,
"StartTime": 19875.0,
"Objects": [{
"StartTime": 19875.0,
"EndTime": 23875.0,
"Column": 1
}, {
"StartTime": 19875.0,
"EndTime": 23875.0,
"Column": 0
}]
}]
"StartTime": 500,
"Objects": [{
"StartTime": 500,
"EndTime": 2500,
"Column": 0
},
{
"StartTime": 1500,
"EndTime": 2500,
"Column": 1
}
]
},
{
"StartTime": 3000,
"Objects": [{
"StartTime": 3000,
"EndTime": 4000,
"Column": 2
}]
},
{
"StartTime": 4500,
"Objects": [{
"StartTime": 4500,
"EndTime": 5500,
"Column": 4
}]
},
{
"StartTime": 6000,
"Objects": [{
"StartTime": 6000,
"EndTime": 6500,
"Column": 2
}]
},
{
"StartTime": 7000,
"Objects": [{
"StartTime": 7000,
"EndTime": 8000,
"Column": 2
}]
},
{
"StartTime": 8500,
"Objects": [{
"StartTime": 8500,
"EndTime": 11000,
"Column": 0
}]
},
{
"StartTime": 11500,
"Objects": [{
"StartTime": 11500,
"EndTime": 12000,
"Column": 1
}]
},
{
"StartTime": 12500,
"Objects": [{
"StartTime": 12500,
"EndTime": 16500,
"Column": 4
}]
},
{
"StartTime": 17000,
"Objects": [{
"StartTime": 17000,
"EndTime": 18000,
"Column": 2
}]
},
{
"StartTime": 18500,
"Objects": [{
"StartTime": 18500,
"EndTime": 19450,
"Column": 0
}]
},
{
"StartTime": 19875,
"Objects": [{
"StartTime": 19875,
"EndTime": 23875,
"Column": 1
},
{
"StartTime": 19875,
"EndTime": 23875,
"Column": 0
}
]
}
]
}
+2 -2
View File
@@ -118,9 +118,9 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(Action);
return dependencies;
}
@@ -70,19 +70,19 @@ namespace osu.Game.Rulesets.Mania.UI
}
[BackgroundDependencyLoader]
private void load()
private void load(ManiaConfigManager config)
{
BarLines.ForEach(Playfield.Add);
((ManiaConfigManager)Config).BindWith(ManiaSetting.ScrollDirection, configDirection);
config.BindWith(ManiaSetting.ScrollDirection, configDirection);
configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true);
}
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo());
return dependencies;
}
@@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
/// A sane value to account for osu!stable using <see cref="int"/>s everywhere.
/// A sane value to account for osu!stable using ints everwhere.
/// </summary>
private const double conversion_lenience = 2;
@@ -61,19 +61,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
int maxCombo = beatmap.HitObjects.Count();
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
return new OsuDifficultyAttributes(mods, starRating)
{
AimStrain = aimRating,
SpeedStrain = speedRating,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
ApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
MaxCombo = maxCombo
};
+2 -2
View File
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{
void adjustFadeIn(OsuHitObject h) => h.TimeFadeIn = h.TimePreempt * fade_in_duration_multiplier;
void adjustFadeIn(OsuHitObject h) => h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier;
foreach (var d in drawables.OfType<DrawableOsuHitObject>())
{
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods
var h = d.HitObject;
var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadeIn;
var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadein;
var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier;
// new duration from completed fade in to end (before fading out)
@@ -96,12 +96,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
using (fp.BeginAbsoluteSequence(fadeInTime))
{
fp.FadeIn(currHitObject.TimeFadeIn);
fp.ScaleTo(1, currHitObject.TimeFadeIn, Easing.Out);
fp.FadeIn(currHitObject.TimeFadein);
fp.ScaleTo(1, currHitObject.TimeFadein, Easing.Out);
fp.MoveTo(pointEndPosition, currHitObject.TimeFadeIn, Easing.Out);
fp.MoveTo(pointEndPosition, currHitObject.TimeFadein, Easing.Out);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadeIn);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadein);
}
fp.Expire(true);
@@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
base.UpdatePreemptState();
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadein * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
}
@@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
}
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadein);
protected virtual void UpdateCurrentState(ArmedState state)
{
@@ -93,9 +93,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.AccentColour = value;
Body.AccentColour = AccentColour;
Ball.AccentColour = AccentColour;
foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour = AccentColour;
if (HasNestedHitObjects)
foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour = AccentColour;
}
}
@@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
if (!userTriggered && Time.Current >= slider.EndTime)
{
var judgementsCount = NestedHitObjects.Count();
var judgementsCount = NestedHitObjects.Count;
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
var hitFraction = (double)judgementsHit / judgementsCount;
@@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton);
if (!spmCounter.IsPresent && Disc.Tracking)
spmCounter.FadeIn(HitObject.TimeFadeIn);
spmCounter.FadeIn(HitObject.TimeFadein);
base.Update();
}
@@ -212,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
var spanProgress = slider.ProgressAt(completionProgress);
double start = 0;
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadein, 0, 1) : 1;
if (span >= slider.SpanCount() - 1)
{
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects
public event Action<Vector2> PositionChanged;
public double TimePreempt = 600;
public double TimeFadeIn = 400;
public double TimeFadein = 400;
private Vector2 position;
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Objects
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
TimeFadeIn = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
}
+1 -1
View File
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
// This is so on repeats ticks don't appear too late to be visually processed by the player.
offset = 200;
else
offset = TimeFadeIn * 0.66f;
offset = TimeFadein * 0.66f;
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
}
+2 -2
View File
@@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Osu
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{
new KeyBinding(InputKey.A, OsuAction.LeftButton),
new KeyBinding(InputKey.S, OsuAction.RightButton),
new KeyBinding(InputKey.Z, OsuAction.LeftButton),
new KeyBinding(InputKey.X, OsuAction.RightButton),
new KeyBinding(InputKey.MouseLeft, OsuAction.LeftButton),
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
};
@@ -11,7 +11,6 @@ using osu.Game.Audio;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects;
using osu.Game.Skinning;
namespace osu.Game.Tests.Beatmaps.Formats
@@ -212,41 +211,5 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
}
}
[Test]
public void TestDecodeCustomSamples()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = Resource.OpenResource("custom-samples.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First());
Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[1]).LookupNames.First());
Assert.AreEqual("normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[3]).LookupNames.First());
}
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" });
}
[Test]
public void TestDecodeCustomHitObjectSamples()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = Resource.OpenResource("custom-hitobject-samples.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());
}
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" });
}
}
}
@@ -118,11 +118,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestParity(string beatmap)
{
var legacy = decode(beatmap, out Beatmap json);
json.WithDeepEqual(legacy)
.IgnoreProperty(r => r.DeclaringType == typeof(HitWindows)
// Todo: CustomSampleBank shouldn't exist going forward, we need a conversion mechanism
|| r.Name == nameof(LegacyDecoder<Beatmap>.LegacySampleControlPoint.CustomSampleBank))
.Assert();
json.WithDeepEqual(legacy).IgnoreProperty(r => r.DeclaringType == typeof(HitWindows)).Assert();
}
/// <summary>
@@ -1,16 +0,0 @@
osu file format v14
[General]
SampleSet: Normal
[TimingPoints]
2170,468.75,4,1,0,40,1,0
2638,-100,4,1,1,40,0,0
3107,-100,4,1,2,40,0,0
3576,-100,4,1,0,40,0,0
[HitObjects]
255,193,2170,1,0,0:0:0:0:hit_1.wav
256,191,2638,5,0,0:0:0:0:hit_2.wav
255,193,3107,1,0,0:0:0:0:
256,191,3576,1,0,0:0:0:0:hit_1.wav
@@ -1,16 +0,0 @@
osu file format v14
[General]
SampleSet: Normal
[TimingPoints]
2170,468.75,4,1,0,40,1,0
2638,-100,4,1,1,40,0,0
3107,-100,4,1,2,40,0,0
3576,-100,4,1,0,40,0,0
[HitObjects]
255,193,2170,1,0,0:0:0:0:
256,191,2638,5,0,0:0:0:0:
255,193,3107,1,0,0:0:0:0:
256,191,3576,1,0,0:0:0:0:
@@ -110,8 +110,8 @@ namespace osu.Game.Tests.Visual
private void testInfoLabels(int expectedCount)
{
AddAssert("check info labels exists", () => infoWedge.Info.InfoLabelContainer.Children.Any());
AddAssert("check info labels count", () => infoWedge.Info.InfoLabelContainer.Children.Count == expectedCount);
AddAssert("check infolabels exists", () => infoWedge.Info.InfoLabelContainer.Children.Any());
AddAssert("check infolabels count", () => infoWedge.Info.InfoLabelContainer.Children.Count == expectedCount);
}
private void testNullBeatmap()
@@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual
AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Title);
AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Artist);
AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any());
AddAssert("check no info labels", () => !infoWedge.Info.InfoLabelContainer.Children.Any());
AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any());
}
private void selectBeatmap(IBeatmap b)
@@ -1,28 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using 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()
};
}
}
}
+5 -10
View File
@@ -25,7 +25,11 @@ namespace osu.Game.Tests.Visual
Children = new[]
{
new NamedIconButton("No change", new IconButton()),
new NamedIconButton("Background colours", new ColouredIconButton()),
new NamedIconButton("Background colours", new IconButton
{
FlashColour = Color4.DarkGreen,
HoverColour = Color4.Green,
}),
new NamedIconButton("Full-width", new IconButton { ButtonSize = new Vector2(200, 30) }),
new NamedIconButton("Unchanging size", new IconButton(), false),
new NamedIconButton("Icon colours", new IconButton
@@ -37,15 +41,6 @@ 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)
+2 -2
View File
@@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual
testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour);
testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour);
testUnimplementedMod(autoPilotMod);
testUnimplmentedMod(autoPilotMod);
}
private void testManiaMods(ManiaRuleset ruleset)
@@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual
checkNotSelected(mod);
}
private void testUnimplementedMod(Mod mod)
private void testUnimplmentedMod(Mod mod)
{
selectNext(mod);
checkNotSelected(mod);
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual
private class TestOnScreenDisplay : OnScreenDisplay
{
protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
protected override void Display(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
}
}
}
+13 -8
View File
@@ -6,6 +6,7 @@ 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;
@@ -22,15 +23,19 @@ namespace osu.Game.Tests.Visual
public TestCaseOsuGame()
{
Children = new Drawable[]
var rateAdjustClock = new StopwatchClock(true);
var framedClock = new FramedClock(rateAdjustClock);
framedClock.ProcessFrame();
Add(new Box
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
new Loader()
};
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
});
Add(new Loader());
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
}
}
}
@@ -14,9 +14,9 @@ namespace osu.Game.Tests.Visual
{
private readonly PreviewTrackManager trackManager = new TestPreviewTrackManager();
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs(trackManager);
dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies;
@@ -101,9 +101,9 @@ namespace osu.Game.Tests.Visual
AddInternal(track);
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies;
}
+2 -2
View File
@@ -16,8 +16,8 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(ToolbarButton),
typeof(ToolbarRulesetSelector),
typeof(ToolbarRulesetButton),
typeof(ToolbarModeSelector),
typeof(ToolbarModeButton),
typeof(ToolbarNotificationButton),
};
@@ -53,6 +53,7 @@ namespace osu.Game.Tests.Visual
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
JoinDate = DateTimeOffset.Now.AddDays(-1),
LastVisit = DateTimeOffset.Now,
Age = 1,
ProfileOrder = new[] { "me" },
Statistics = new UserStatistics
{
-29
View File
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
namespace osu.Game.Audio
{
@@ -29,37 +28,9 @@ namespace osu.Game.Audio
/// </summary>
public string Name;
/// <summary>
/// An optional suffix to provide priority lookup. Falls back to non-suffixed <see cref="Name"/>.
/// </summary>
public string Suffix;
/// <summary>
/// The sample volume.
/// </summary>
public int Volume;
/// <summary>
/// Retrieve all possible filenames that can be used as a source, returned in order of preference (highest first).
/// </summary>
public virtual IEnumerable<string> LookupNames
{
get
{
if (!string.IsNullOrEmpty(Namespace))
{
if (!string.IsNullOrEmpty(Suffix))
yield return $"{Namespace}/{Bank}-{Name}{Suffix}";
yield return $"{Namespace}/{Bank}-{Name}";
}
// check non-namespace as a fallback even when we have a namespace
if (!string.IsNullOrEmpty(Suffix))
yield return $"{Bank}-{Name}{Suffix}";
yield return $"{Bank}-{Name}";
}
}
public SampleInfo Clone() => (SampleInfo)MemberwiseClone();
}
}
+6 -47
View File
@@ -45,16 +45,6 @@ namespace osu.Game.Beatmaps
/// </summary>
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadBegan;
/// <summary>
/// Fired when a beatmap load is requested (into the interactive game UI).
/// </summary>
public Action<BeatmapSetInfo> PresentBeatmap;
/// <summary>
/// Fired when a beatmap download is interrupted, due to user cancellation or other failures.
/// </summary>
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadFailed;
/// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary>
@@ -102,7 +92,7 @@ namespace osu.Game.Beatmaps
// by setting the model here, we can update the noline set id below.
b.BeatmapSet = model;
fetchAndPopulateOnlineIDs(b, model.Beatmaps);
fetchAndPopulateOnlineIDs(b);
}
// check if a set already exists with the same online id, delete if it does.
@@ -173,28 +163,18 @@ 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()))
importedBeatmap = Import(archive);
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;
@@ -359,8 +339,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))
@@ -377,18 +355,9 @@ 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;
}
// check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence.
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null)
beatmap.BeatmapInfo.OnlineBeatmapID = null;
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
@@ -406,9 +375,6 @@ namespace osu.Game.Beatmaps
}
}
if (invalidateOnlineIDs)
beatmapInfos.ForEach(b => b.OnlineBeatmapID = null);
return beatmapInfos;
}
@@ -416,10 +382,9 @@ 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, IEnumerable<BeatmapInfo> otherBeatmaps, bool force = false)
private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false)
{
if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null)
return true;
@@ -439,12 +404,6 @@ 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;
+1
View File
@@ -14,6 +14,7 @@ namespace osu.Game.Beatmaps
public class BeatmapMetadata : IEquatable<BeatmapMetadata>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
public int ID { get; set; }
public string Title { get; set; }
@@ -14,15 +14,6 @@ namespace osu.Game.Beatmaps.ControlPoints
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
/// <summary>
/// Whether this <see cref="ControlPoint"/> provides the same parametric changes as another <see cref="ControlPoint"/>.
/// Basically an equality check without considering the <see cref="Time"/>.
/// </summary>
/// <param name="other">The <see cref="ControlPoint"/> to compare to.</param>
/// <returns>Whether this <see cref="ControlPoint"/> is equivalent to <paramref name="other"/>.</returns>
public virtual bool EquivalentTo(ControlPoint other) => true;
public bool Equals(ControlPoint other)
=> EquivalentTo(other) && Time.Equals(other?.Time);
public bool Equals(ControlPoint other) => Time.Equals(other?.Time);
}
}
@@ -17,10 +17,5 @@ namespace osu.Game.Beatmaps.ControlPoints
}
private double speedMultiplier = 1;
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is DifficultyControlPoint difficulty
&& SpeedMultiplier.Equals(difficulty.SpeedMultiplier);
}
}
@@ -14,11 +14,5 @@ namespace osu.Game.Beatmaps.ControlPoints
/// Whether the first bar line of this control point is ignored.
/// </summary>
public bool OmitFirstBarLine;
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is EffectControlPoint effect
&& KiaiMode.Equals(effect.KiaiMode)
&& OmitFirstBarLine.Equals(effect.OmitFirstBarLine);
}
}
@@ -30,25 +30,5 @@ namespace osu.Game.Beatmaps.ControlPoints
Name = sampleName,
Volume = SampleVolume,
};
/// <summary>
/// Applies <see cref="SampleBank"/> and <see cref="SampleVolume"/> to a <see cref="SampleInfo"/> if necessary, returning the modified <see cref="SampleInfo"/>.
/// </summary>
/// <param name="sampleInfo">The <see cref="SampleInfo"/>. This will not be modified.</param>
/// <returns>The modified <see cref="SampleInfo"/>. This does not share a reference with <paramref name="sampleInfo"/>.</returns>
public virtual SampleInfo ApplyTo(SampleInfo sampleInfo)
{
var newSampleInfo = sampleInfo.Clone();
newSampleInfo.Bank = sampleInfo.Bank ?? SampleBank;
newSampleInfo.Name = sampleInfo.Name;
newSampleInfo.Volume = sampleInfo.Volume > 0 ? sampleInfo.Volume : SampleVolume;
return newSampleInfo;
}
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is SampleControlPoint sample
&& SampleBank.Equals(sample.SampleBank)
&& SampleVolume.Equals(sample.SampleVolume);
}
}
@@ -23,11 +23,5 @@ namespace osu.Game.Beatmaps.ControlPoints
}
private double beatLength = 1000;
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is TimingControlPoint timing
&& TimeSignature.Equals(timing.TimeSignature)
&& BeatLength.Equals(timing.BeatLength);
}
}
@@ -5,7 +5,6 @@ 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
{
@@ -20,9 +19,9 @@ namespace osu.Game.Beatmaps.Drawables
private BeatmapManager beatmaps;
/// <summary>
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
/// Whether the associated beatmap set has been downloading (by this instance or any other instance).
/// </summary>
public readonly Bindable<DownloadStatus> DownloadState = new Bindable<DownloadStatus>();
public readonly BindableBool Downloaded = new BindableBool();
public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false)
{
@@ -37,16 +36,10 @@ namespace osu.Game.Beatmaps.Drawables
beatmaps.ItemAdded += setAdded;
beatmaps.ItemRemoved += setRemoved;
beatmaps.BeatmapDownloadBegan += downloadBegan;
beatmaps.BeatmapDownloadFailed += downloadFailed;
// initial value
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;
if (set.OnlineBeatmapSetID != null)
Downloaded.Value = beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any();
}
protected override void Dispose(bool isDisposing)
@@ -57,8 +50,6 @@ namespace osu.Game.Beatmaps.Drawables
{
beatmaps.ItemAdded -= setAdded;
beatmaps.ItemRemoved -= setRemoved;
beatmaps.BeatmapDownloadBegan -= downloadBegan;
beatmaps.BeatmapDownloadFailed -= downloadFailed;
}
}
@@ -66,45 +57,28 @@ 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 void Download()
public bool Download()
{
if (DownloadState.Value > DownloadStatus.NotDownloaded)
return;
if (Downloaded.Value)
return false;
if (beatmaps.GetExistingDownload(set) != null)
return false;
beatmaps.Download(set, noVideo);
DownloadState.Value = DownloadStatus.Downloading;
return true;
}
private void setAdded(BeatmapSetInfo s)
{
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.Downloaded;
Downloaded.Value = true;
}
private void setRemoved(BeatmapSetInfo s)
{
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
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,
Downloaded.Value = false;
}
}
}
@@ -9,14 +9,14 @@ using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
public abstract class DifficultyColouredContainer : Container, IHasAccentColour
public class DifficultyColouredContainer : Container, IHasAccentColour
{
public Color4 AccentColour { get; set; }
private readonly BeatmapInfo beatmap;
private OsuColour palette;
protected DifficultyColouredContainer(BeatmapInfo beatmap)
public DifficultyColouredContainer(BeatmapInfo beatmap)
{
this.beatmap = beatmap;
}
+5 -23
View File
@@ -3,14 +3,10 @@
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
{
@@ -18,8 +14,7 @@ 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));
@@ -33,29 +28,16 @@ namespace osu.Game.Beatmaps.Drawables
{
Children = new Drawable[]
{
new CircularContainer
new SpriteIcon
{
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.84f),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.08f),
Type = EdgeEffectType.Shadow,
Radius = 5,
},
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = AccentColour,
},
RelativeSizeAxes = Axes.Both,
Colour = AccentColour,
Icon = FontAwesome.fa_circle
},
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 }
@@ -289,9 +289,9 @@ namespace osu.Game.Beatmaps.Formats
if (split.Length >= 4)
sampleSet = (LegacySampleBank)int.Parse(split[3]);
int customSampleBank = 0;
if (split.Length >= 5)
customSampleBank = int.Parse(split[4]);
//SampleBank sampleBank = SampleBank.Default;
//if (split.Length >= 5)
// sampleBank = (SampleBank)int.Parse(split[4]);
int sampleVolume = defaultSampleVolume;
if (split.Length >= 6)
@@ -314,9 +314,13 @@ namespace osu.Game.Beatmaps.Formats
if (stringSampleSet == @"none")
stringSampleSet = @"normal";
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time);
SampleControlPoint samplePoint = beatmap.ControlPointInfo.SamplePointAt(time);
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time);
if (timingChange)
{
handleTimingControlPoint(new TimingControlPoint
beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint
{
Time = time,
BeatLength = beatLength,
@@ -324,68 +328,41 @@ namespace osu.Game.Beatmaps.Formats
});
}
handleDifficultyControlPoint(new DifficultyControlPoint
if (speedMultiplier != difficultyPoint.SpeedMultiplier)
{
Time = time,
SpeedMultiplier = speedMultiplier
});
beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time);
beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint
{
Time = time,
SpeedMultiplier = speedMultiplier
});
}
handleEffectControlPoint(new EffectControlPoint
if (stringSampleSet != samplePoint.SampleBank || sampleVolume != samplePoint.SampleVolume)
{
Time = time,
KiaiMode = kiaiMode,
OmitFirstBarLine = omitFirstBarSignature
});
beatmap.ControlPointInfo.SamplePoints.Add(new SampleControlPoint
{
Time = time,
SampleBank = stringSampleSet,
SampleVolume = sampleVolume
});
}
handleSampleControlPoint(new LegacySampleControlPoint
if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine)
{
Time = time,
SampleBank = stringSampleSet,
SampleVolume = sampleVolume,
CustomSampleBank = customSampleBank
});
beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint
{
Time = time,
KiaiMode = kiaiMode,
OmitFirstBarLine = omitFirstBarSignature
});
}
}
catch (FormatException e)
{
}
}
private void handleTimingControlPoint(TimingControlPoint newPoint)
{
beatmap.ControlPointInfo.TimingPoints.Add(newPoint);
}
private void handleDifficultyControlPoint(DifficultyControlPoint newPoint)
{
var existing = beatmap.ControlPointInfo.DifficultyPointAt(newPoint.Time);
if (newPoint.EquivalentTo(existing))
return;
beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == newPoint.Time);
beatmap.ControlPointInfo.DifficultyPoints.Add(newPoint);
}
private void handleEffectControlPoint(EffectControlPoint newPoint)
{
var existing = beatmap.ControlPointInfo.EffectPointAt(newPoint.Time);
if (newPoint.EquivalentTo(existing))
return;
beatmap.ControlPointInfo.EffectPoints.Add(newPoint);
}
private void handleSampleControlPoint(SampleControlPoint newPoint)
{
var existing = beatmap.ControlPointInfo.SamplePointAt(newPoint.Time);
if (newPoint.EquivalentTo(existing))
return;
beatmap.ControlPointInfo.SamplePoints.Add(newPoint);
}
private void handleHitObject(string line)
{
// If the ruleset wasn't specified, assume the osu!standard ruleset.
@@ -5,8 +5,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.Logging;
using osu.Game.Audio;
using osu.Game.Beatmaps.ControlPoints;
using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Formats
@@ -169,25 +167,5 @@ namespace osu.Game.Beatmaps.Formats
Pass = 2,
Foreground = 3
}
internal class LegacySampleControlPoint : SampleControlPoint
{
public int CustomSampleBank;
public override SampleInfo ApplyTo(SampleInfo sampleInfo)
{
var baseInfo = base.ApplyTo(sampleInfo);
if (CustomSampleBank > 1)
baseInfo.Suffix = CustomSampleBank.ToString();
return baseInfo;
}
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is LegacySampleControlPoint legacy
&& CustomSampleBank == legacy.CustomSampleBank;
}
}
}
+1 -6
View File
@@ -116,7 +116,7 @@ namespace osu.Game.Database
/// <param name="paths">One or more archive locations on disk.</param>
public void Import(params string[] paths)
{
var notification = new ImportNotification
var notification = new ProgressNotification
{
Text = "Import is initialising...",
Progress = 0,
@@ -407,10 +407,5 @@ namespace osu.Game.Database
return new LegacyFilesystemReader(path);
throw new InvalidFormatException($"{path} is not a valid archive");
}
private class ImportNotification : ProgressNotification
{
public override bool IsImportant => true;
}
}
}
@@ -22,16 +22,13 @@ namespace osu.Game.Graphics.Containers
protected virtual bool PlaySamplesOnStateChange => true;
protected override bool BlockPassThroughKeyboard => true;
private PreviewTrackManager previewTrackManager;
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies;
}
@@ -72,13 +69,10 @@ namespace osu.Game.Graphics.Containers
public virtual bool OnPressed(GlobalAction action)
{
switch (action)
if (action == GlobalAction.Back)
{
case GlobalAction.Back:
State = Visibility.Hidden;
return true;
case GlobalAction.Select:
return true;
State = Visibility.Hidden;
return true;
}
return false;
+22 -21
View File
@@ -22,9 +22,7 @@ namespace osu.Game.Graphics.Cursor
private readonly IBindable<bool> screenshotCursorVisibility = new Bindable<bool>(true);
public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent;
protected override Drawable CreateCursor() => activeCursor = new Cursor();
private Cursor activeCursor;
protected override Drawable CreateCursor() => new Cursor();
private Bindable<bool> cursorRotate;
private DragRotationState dragRotationState;
@@ -56,12 +54,12 @@ namespace osu.Game.Graphics.Cursor
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
// Always rotate in the direction of least distance
float diff = (degrees - activeCursor.Rotation) % 360;
float diff = (degrees - ActiveCursor.Rotation) % 360;
if (diff < -180) diff += 360;
if (diff > 180) diff -= 360;
degrees = activeCursor.Rotation + diff;
degrees = ActiveCursor.Rotation + diff;
activeCursor.RotateTo(degrees, 600, Easing.OutQuint);
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
}
}
@@ -70,15 +68,11 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
// only trigger animation for main mouse buttons
if (args.Button <= MouseButton.Right)
{
activeCursor.Scale = new Vector2(1);
activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
ActiveCursor.Scale = new Vector2(1);
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
activeCursor.AdditiveLayer.Alpha = 0;
activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
}
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
if (args.Button == MouseButton.Left && cursorRotate)
{
@@ -92,29 +86,36 @@ namespace osu.Game.Graphics.Cursor
{
if (!state.Mouse.HasMainButtonPressed)
{
activeCursor.AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
activeCursor.ScaleTo(1, 500, Easing.OutElastic);
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
}
if (args.Button == MouseButton.Left)
{
if (dragRotationState == DragRotationState.Rotating)
activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
dragRotationState = DragRotationState.NotDragging;
}
return base.OnMouseUp(state, args);
}
protected override bool OnClick(InputState state)
{
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
return base.OnClick(state);
}
protected override void PopIn()
{
activeCursor.FadeTo(1, 250, Easing.OutQuint);
activeCursor.ScaleTo(1, 400, Easing.OutQuint);
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
activeCursor.FadeTo(0, 250, Easing.OutQuint);
activeCursor.ScaleTo(0.6f, 250, Easing.In);
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
}
public class Cursor : Container
@@ -21,8 +21,6 @@ namespace osu.Game.Graphics.Cursor
{
}
protected override double AppearDelay => (1 - CurrentTooltip.Alpha) * base.AppearDelay; // reduce appear delay if the tooltip is already partly visible.
public class OsuTooltip : Tooltip
{
private readonly Box background;
+96 -15
View File
@@ -3,17 +3,31 @@
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
{
public class IconButton : OsuAnimatedButton
public class IconButton : OsuClickableContainer
{
public const float BUTTON_SIZE = 30;
private Color4? iconColour;
private Color4? flashColour;
/// <summary>
/// The colour that should be flashed when the <see cref="IconButton"/> is clicked.
/// </summary>
public Color4 FlashColour
{
get { return flashColour ?? Color4.White; }
set { flashColour = value; }
}
private Color4? iconColour;
/// <summary>
/// The icon colour. This does not affect <see cref="IconButton.Colour"/>.
/// </summary>
@@ -28,7 +42,6 @@ namespace osu.Game.Graphics.UserInterface
}
private Color4? iconHoverColour;
/// <summary>
/// The icon colour while the <see cref="IconButton"/> is hovered.
/// </summary>
@@ -38,6 +51,20 @@ namespace osu.Game.Graphics.UserInterface
set { iconHoverColour = value; }
}
private Color4? hoverColour;
/// <summary>
/// The background colour of the <see cref="IconButton"/> while it is hovered.
/// </summary>
public Color4 HoverColour
{
get { return hoverColour ?? Color4.White; }
set
{
hoverColour = value;
hover.Colour = value;
}
}
/// <summary>
/// The icon.
/// </summary>
@@ -61,39 +88,93 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
public Vector2 ButtonSize
{
get => Content.Size;
set
{
Content.RelativeSizeAxes = Axes.None;
Content.Size = value;
}
get { return content.Size; }
set { content.Size = value; }
}
private readonly Container content;
private readonly SpriteIcon icon;
private readonly Box hover;
public IconButton()
{
AutoSizeAxes = Axes.Both;
ButtonSize = new Vector2(BUTTON_SIZE);
Add(icon = new SpriteIcon
Children = new Drawable[]
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(18),
});
content = new Container
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(BUTTON_SIZE),
CornerRadius = 5,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.04f),
Type = EdgeEffectType.Shadow,
Radius = 5,
},
Children = new Drawable[]
{
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
icon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(18),
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (hoverColour == null)
HoverColour = colours.Yellow.Opacity(0.6f);
if (flashColour == null)
FlashColour = colours.Yellow;
Enabled.ValueChanged += enabled => this.FadeColour(enabled ? Color4.White : colours.Gray9, 200, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(500, Easing.OutQuint);
icon.FadeColour(IconHoverColour, 500, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(500, Easing.OutQuint);
icon.FadeColour(IconColour, 500, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
hover.FlashColour(FlashColour, 800, Easing.OutQuint);
return base.OnClick(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
content.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}
}
@@ -1,109 +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.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics.Containers;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Highlight on hover, bounce on click.
/// </summary>
public class OsuAnimatedButton : OsuClickableContainer
{
/// <summary>
/// The colour that should be flashed when the <see cref="IconButton"/> is clicked.
/// </summary>
protected Color4 FlashColour = Color4.White.Opacity(0.3f);
private Color4 hoverColour = Color4.White.Opacity(0.1f);
/// <summary>
/// The background colour of the <see cref="IconButton"/> while it is hovered.
/// </summary>
protected Color4 HoverColour
{
get => hoverColour;
set
{
hoverColour = value;
hover.Colour = value;
}
}
protected override Container<Drawable> Content => content;
private readonly Container content;
private readonly Box hover;
public OsuAnimatedButton()
{
base.Content.Add(content = new Container
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
CornerRadius = 5,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.04f),
Type = EdgeEffectType.Shadow,
Radius = 5,
},
Children = new Drawable[]
{
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = HoverColour,
Blending = BlendingMode.Additive,
Alpha = 0,
},
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Enabled.BindValueChanged(enabled => this.FadeColour(enabled ? Color4.White : colours.Gray9, 200, Easing.OutQuint), true);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(500, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(500, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
hover.FlashColour(FlashColour, 800, Easing.OutQuint);
return base.OnClick(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Content.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}
}
@@ -8,6 +8,7 @@ namespace osu.Game.Migrations
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DELETE FROM KeyBinding WHERE RulesetID = 1");
Logger.Log("osu!taiko bindings have been reset due to new defaults", LoggingTarget.Runtime, LogLevel.Important);
}
protected override void Down(MigrationBuilder migrationBuilder)
@@ -63,14 +63,7 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"beatmapset")]
private BeatmapMetadata metadata
{
set
{
// extract the set ID to its correct place.
Beatmap.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = value.ID };
value.ID = 0;
Beatmap.Metadata = value;
}
set => Beatmap.Metadata = value;
}
[JsonProperty(@"statistics")]
+32 -61
View File
@@ -19,12 +19,10 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Notifications;
@@ -35,7 +33,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Skinning;
using OpenTK.Graphics;
using osu.Game.Overlays.Volume;
using osu.Game.Screens.Select;
namespace osu.Game
{
@@ -125,8 +122,8 @@ namespace osu.Game
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager frameworkConfig)
@@ -181,41 +178,6 @@ namespace osu.Game
/// <param name="setId">The set to display.</param>
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.FetchAndShowBeatmapSet(setId);
/// <summary>
/// Present a beatmap at song select.
/// </summary>
/// <param name="beatmap">The beatmap to select.</param>
public void PresentBeatmap(BeatmapSetInfo beatmap)
{
CloseAllOverlays(false);
void setBeatmap()
{
if (Beatmap.Disabled)
{
Schedule(setBeatmap);
return;
}
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(beatmap.Beatmaps.First());
}
switch (currentScreen)
{
case SongSelect _:
break;
default:
// navigate to song select if we are not already there.
var menu = (MainMenu)intro.ChildScreen;
menu.MakeCurrent();
menu.LoadToSolo();
break;
}
setBeatmap();
}
/// <summary>
/// Show a user's profile as an overlay.
/// </summary>
@@ -282,15 +244,13 @@ namespace osu.Game
BeatmapManager.PostNotification = n => notifications?.Post(n);
BeatmapManager.GetStableStorage = GetStorageForStableInstall;
BeatmapManager.PresentBeatmap = PresentBeatmap;
AddRange(new Drawable[]
{
new VolumeControlReceptor
{
RelativeSizeAxes = Axes.Both,
ActionRequested = action => volume.Adjust(action),
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
ActionRequested = action => volume.Adjust(action)
},
mainContent = new Container { RelativeSizeAxes = Axes.Both },
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
@@ -361,6 +321,24 @@ namespace osu.Game
dependencies.Cache(notifications);
dependencies.Cache(dialogOverlay);
// ensure only one of these overlays are open at once.
var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct };
overlays.AddRange(singleDisplayOverlays);
foreach (var overlay in singleDisplayOverlays)
{
overlay.StateChanged += state =>
{
if (state == Visibility.Hidden) return;
foreach (var c in singleDisplayOverlays)
{
if (c == overlay) continue;
c.State = Visibility.Hidden;
}
};
}
var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications };
overlays.AddRange(singleDisplaySideOverlays);
@@ -369,7 +347,12 @@ namespace osu.Game
overlay.StateChanged += state =>
{
if (state == Visibility.Hidden) return;
singleDisplaySideOverlays.Where(o => o != overlay).ForEach(o => o.Hide());
foreach (var c in singleDisplaySideOverlays)
{
if (c == overlay) continue;
c.State = Visibility.Hidden;
}
};
}
@@ -382,24 +365,12 @@ namespace osu.Game
overlay.StateChanged += state =>
{
if (state == Visibility.Hidden) return;
informationalOverlays.Where(o => o != overlay).ForEach(o => o.Hide());
};
}
// ensure only one of these overlays are open at once.
var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct };
overlays.AddRange(singleDisplayOverlays);
foreach (var overlay in singleDisplayOverlays)
{
overlay.StateChanged += state =>
{
// informational overlays should be dismissed on a show or hide of a full overlay.
informationalOverlays.ForEach(o => o.Hide());
if (state == Visibility.Hidden) return;
singleDisplayOverlays.Where(o => o != overlay).ForEach(o => o.Hide());
foreach (var c in informationalOverlays)
{
if (c == overlay) continue;
c.State = Visibility.Hidden;
}
};
}
+2 -32
View File
@@ -20,7 +20,6 @@ using osu.Game.Graphics.Cursor;
using osu.Game.Online.API;
using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Game.Audio;
using osu.Game.Database;
@@ -31,7 +30,6 @@ using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using OpenTK.Input;
using DebugUtils = osu.Game.Utils.DebugUtils;
namespace osu.Game
@@ -95,13 +93,11 @@ namespace osu.Game
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
private DatabaseContextFactory contextFactory;
protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager();
[BackgroundDependencyLoader]
private void load()
{
@@ -271,31 +267,5 @@ namespace osu.Game
return copy;
}
}
private class OsuUserInputManager : UserInputManager
{
protected override MouseButtonEventManager CreateButtonManagerFor(MouseButton button)
{
switch (button)
{
case MouseButton.Right:
return new RightMouseManager(button);
}
return base.CreateButtonManagerFor(button);
}
private class RightMouseManager : MouseButtonEventManager
{
public RightMouseManager(MouseButton button)
: base(button)
{
}
public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers.
public override bool EnableClick => false;
public override bool ChangeFocusOnClick => false;
}
}
}
}
@@ -61,23 +61,20 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
Action = () =>
{
if (downloader.DownloadState.Value == BeatmapSetDownloader.DownloadStatus.Downloading)
if (!downloader.Download())
{
Content.MoveToX(-5, 50, Easing.OutSine).Then()
.MoveToX(5, 100, Easing.InOutSine).Then()
.MoveToX(-5, 100, Easing.InOutSine).Then()
.MoveToX(0, 50, Easing.InSine);
return;
}
downloader.Download();
};
downloader.DownloadState.ValueChanged += d =>
downloader.Downloaded.ValueChanged += d =>
{
if (d == BeatmapSetDownloader.DownloadStatus.Downloaded)
if (d)
this.FadeOut(200);
else if (d == BeatmapSetDownloader.DownloadStatus.NotDownloaded)
else
this.FadeIn(200);
};
}
+2 -2
View File
@@ -70,10 +70,10 @@ namespace osu.Game.Overlays.Dialog
{
if (actionInvoked) return;
Hide();
actionInvoked = true;
action?.Invoke();
Hide();
};
}
}
+4 -3
View File
@@ -168,10 +168,11 @@ namespace osu.Game.Overlays.Direct
},
new DownloadButton(SetInfo)
{
Size = new Vector2(50, 30),
Size = new Vector2(30),
Margin = new MarginPadding(horizontal_padding),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Colour = colours.Gray5,
},
},
},
+2 -2
View File
@@ -120,8 +120,8 @@ namespace osu.Game.Overlays.Direct
Alpha = 0,
Child = new DownloadButton(SetInfo)
{
Size = new Vector2(height - vertical_padding * 3),
Margin = new MarginPadding { Left = vertical_padding, Right = vertical_padding },
Size = new Vector2(height - vertical_padding * 2),
Margin = new MarginPadding { Left = vertical_padding },
},
},
new FillFlowContainer
-8
View File
@@ -99,7 +99,6 @@ namespace osu.Game.Overlays.Direct
attachDownload(downloadRequest);
beatmaps.BeatmapDownloadBegan += attachDownload;
beatmaps.ItemAdded += setAdded;
}
public override bool DisposeOnDeathRemoval => true;
@@ -108,7 +107,6 @@ namespace osu.Game.Overlays.Direct
{
base.Dispose(isDisposing);
beatmaps.BeatmapDownloadBegan -= attachDownload;
beatmaps.ItemAdded -= setAdded;
}
protected override void Update()
@@ -173,12 +171,6 @@ namespace osu.Game.Overlays.Direct
};
}
private void setAdded(BeatmapSetInfo s)
{
if (s.OnlineBeatmapSetID == SetInfo.OnlineBeatmapSetID)
progressBar.FadeOut(500);
}
protected override void LoadComplete()
{
base.LoadComplete();
+29 -62
View File
@@ -1,109 +1,76 @@
// 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.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.Containers;
using OpenTK;
namespace osu.Game.Overlays.Direct
{
public class DownloadButton : OsuAnimatedButton
public class DownloadButton : OsuClickableContainer
{
private readonly SpriteIcon icon;
private readonly SpriteIcon checkmark;
private readonly BeatmapSetDownloader downloader;
private readonly Box background;
private OsuColour colours;
public DownloadButton(BeatmapSetInfo set, bool noVideo = false)
{
AddRange(new Drawable[]
BeatmapSetDownloader downloader;
Children = new Drawable[]
{
downloader = new BeatmapSetDownloader(set, noVideo),
background = new Box
{
RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue
},
icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(13),
Icon = FontAwesome.fa_download,
Size = new Vector2(30),
Icon = FontAwesome.fa_osu_chevron_down_o,
},
checkmark = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
X = 8,
Size = Vector2.Zero,
Icon = FontAwesome.fa_check,
}
});
};
Action = () =>
{
if (downloader.DownloadState == BeatmapSetDownloader.DownloadStatus.Downloading)
if (!downloader.Download())
{
// todo: replace with ShakeContainer after https://github.com/ppy/osu/pull/2909 is merged.
Content.MoveToX(-5, 50, Easing.OutSine).Then()
.MoveToX(5, 100, Easing.InOutSine).Then()
.MoveToX(-5, 100, Easing.InOutSine).Then()
.MoveToX(0, 50, Easing.InSine);
}
else if (downloader.DownloadState == BeatmapSetDownloader.DownloadStatus.Downloaded)
{
// TODO: Jump to song select with this set when the capability is implemented
}
};
downloader.Downloaded.ValueChanged += d =>
{
if (d)
this.FadeOut(200);
else
{
downloader.Download();
}
this.FadeIn(200);
};
}
protected override void LoadComplete()
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
base.LoadComplete();
downloader.DownloadState.BindValueChanged(updateState, true);
FinishTransforms(true);
icon.ScaleTo(0.9f, 1000, Easing.Out);
return base.OnMouseDown(state, args);
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours)
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
this.colours = colours;
icon.ScaleTo(1f, 500, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
private void updateState(BeatmapSetDownloader.DownloadStatus state)
protected override bool OnHover(InputState state)
{
switch (state)
{
case BeatmapSetDownloader.DownloadStatus.NotDownloaded:
background.FadeColour(colours.Gray4, 500, Easing.InOutExpo);
icon.MoveToX(0, 500, Easing.InOutExpo);
checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo);
break;
icon.ScaleTo(1.1f, 500, Easing.OutElastic);
return base.OnHover(state);
}
case BeatmapSetDownloader.DownloadStatus.Downloading:
background.FadeColour(colours.Blue, 500, Easing.InOutExpo);
icon.MoveToX(0, 500, Easing.InOutExpo);
checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo);
break;
case BeatmapSetDownloader.DownloadStatus.Downloaded:
background.FadeColour(colours.Green, 500, Easing.InOutExpo);
icon.MoveToX(-8, 500, Easing.InOutExpo);
checkmark.ScaleTo(new Vector2(13), 500, Easing.InOutExpo);
break;
}
protected override void OnHoverLost(InputState state)
{
icon.ScaleTo(1f, 500, Easing.OutElastic);
}
}
}
@@ -102,7 +102,6 @@ namespace osu.Game.Overlays.KeyBinding
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding(padding),
Padding = new MarginPadding { Top = height },
Alpha = 0,
Colour = colours.YellowDark
}
@@ -187,7 +186,7 @@ namespace osu.Game.Overlays.KeyBinding
{
if (bindTarget.IsHovered)
{
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state, state.Mouse.ScrollDelta));
bindTarget.UpdateKeyCombination(new KeyCombination(KeyCombination.FromInputState(state).Keys.Append(state.Mouse.ScrollDelta.Y > 0 ? InputKey.MouseWheelUp : InputKey.MouseWheelDown)));
finalise();
return true;
}
@@ -268,7 +267,7 @@ namespace osu.Game.Overlays.KeyBinding
GetContainingInputManager().ChangeFocus(null);
pressAKey.FadeOut(300, Easing.OutQuint);
pressAKey.BypassAutoSizeAxes |= Axes.Y;
pressAKey.Padding = new MarginPadding { Top = height, Bottom = -pressAKey.DrawHeight };
}
protected override void OnFocus(InputState state)
@@ -277,7 +276,7 @@ namespace osu.Game.Overlays.KeyBinding
AutoSizeEasing = Easing.OutQuint;
pressAKey.FadeIn(300, Easing.OutQuint);
pressAKey.BypassAutoSizeAxes &= ~Axes.Y;
pressAKey.Padding = new MarginPadding { Top = height };
updateBindTarget();
base.OnFocus(state);
+1 -6
View File
@@ -44,8 +44,6 @@ namespace osu.Game.Overlays.Mods
private void rulesetChanged(RulesetInfo newRuleset)
{
if (newRuleset == null) return;
var instance = newRuleset.CreateInstance();
foreach (ModSection section in ModSectionsContainer.Children)
@@ -175,10 +173,7 @@ namespace osu.Game.Overlays.Mods
refreshSelectedMods();
}
private void refreshSelectedMods()
{
SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
}
private void refreshSelectedMods() => SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
public ModSelectOverlay()
{
+4 -14
View File
@@ -142,14 +142,14 @@ namespace osu.Game.Overlays
Anchor = Anchor.Centre,
Children = new[]
{
prevButton = new MusicIconButton
prevButton = new IconButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Action = prev,
Icon = FontAwesome.fa_step_backward,
},
playButton = new MusicIconButton
playButton = new IconButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -158,7 +158,7 @@ namespace osu.Game.Overlays
Action = play,
Icon = FontAwesome.fa_play_circle_o,
},
nextButton = new MusicIconButton
nextButton = new IconButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -167,7 +167,7 @@ namespace osu.Game.Overlays
},
}
},
playlistButton = new MusicIconButton
playlistButton = new IconButton
{
Origin = Anchor.Centre,
Anchor = Anchor.CentreRight,
@@ -405,16 +405,6 @@ namespace osu.Game.Overlays
Prev
}
private class MusicIconButton : IconButton
{
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
HoverColour = colours.YellowDark.Opacity(0.6f);
FlashColour = colours.Yellow;
}
}
private class Background : BufferedContainer
{
private readonly Sprite sprite;
+1 -2
View File
@@ -128,8 +128,7 @@ namespace osu.Game.Overlays
var section = sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)));
section?.Add(notification, notification.DisplayOnTop ? -runningDepth : runningDepth);
if (notification.IsImportant)
State = Visibility.Visible;
State = Visibility.Visible;
updateCounts();
});
@@ -23,11 +23,6 @@ namespace osu.Game.Overlays.Notifications
/// </summary>
public event Action Closed;
/// <summary>
/// Whether this notification should forcefully display itself.
/// </summary>
public virtual bool IsImportant => false;
/// <summary>
/// Run on user activating the notification. Return true to close.
/// </summary>
@@ -9,8 +9,6 @@ namespace osu.Game.Overlays.Notifications
{
public class ProgressCompletionNotification : SimpleNotification
{
public override bool IsImportant => true;
public ProgressCompletionNotification()
{
Icon = FontAwesome.fa_check;
+11 -27
View File
@@ -14,8 +14,6 @@ using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Graphics.Sprites;
@@ -137,7 +135,7 @@ namespace osu.Game.Overlays
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
public void BeginTracking(object source, ITrackableConfigManager configManager)
{
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
if (trackedConfigManagers.ContainsKey((source, configManager)))
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
@@ -161,7 +159,7 @@ namespace osu.Game.Overlays
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <see cref="source"/>.</exception>
public void StopTracking(object source, ITrackableConfigManager configManager)
{
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
@@ -183,7 +181,7 @@ namespace osu.Game.Overlays
if (string.IsNullOrEmpty(textLine3.Text))
textLine3.Text = "NO KEY BOUND";
DisplayTemporarily(box);
Display(box);
int optionCount = 0;
int selectedOption = -1;
@@ -215,29 +213,15 @@ namespace osu.Game.Overlays
});
}
private TransformSequence<Drawable> fadeIn;
private ScheduledDelegate fadeOut;
protected virtual void DisplayTemporarily(Drawable toDisplay)
protected virtual void Display(Drawable toDisplay)
{
// avoid starting a new fade-in if one is already active.
if (fadeIn == null)
{
fadeIn = toDisplay.Animate(
b => b.FadeIn(500, Easing.OutQuint),
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
);
fadeIn.Finally(_ => fadeIn = null);
}
fadeOut?.Cancel();
fadeOut = Scheduler.AddDelayed(() =>
{
toDisplay.Animate(
b => b.FadeOutFromOne(1500, Easing.InQuint),
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint));
}, 500);
toDisplay.Animate(
b => b.FadeIn(500, Easing.OutQuint),
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
).Then(
b => b.FadeOutFromOne(1500, Easing.InQuint),
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint)
);
}
private class OptionLight : Container
+5 -7
View File
@@ -158,13 +158,6 @@ namespace osu.Game.Overlays.Profile
}
}
},
new Box // this is a temporary workaround for incorrect masking behaviour of FillMode.Fill used in UserCoverBackground (see https://github.com/ppy/osu-framework/issues/1675)
{
RelativeSizeAxes = Axes.X,
Height = 1,
Y = cover_height,
Colour = OsuColour.Gray(34),
},
infoTextLeft = new LinkFlowContainer(t => t.TextSize = 14)
{
X = UserProfileOverlay.CONTENT_X_MARGIN,
@@ -367,6 +360,11 @@ namespace osu.Game.Overlays.Profile
Text = text
};
if (user.Age != null)
{
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
}
if (user.Country != null)
{
infoTextLeft.AddText("From ", lightText);
@@ -9,7 +9,6 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Sections
{
/// <summary>
@@ -33,10 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections
{
Action = () =>
{
if (beatmap.OnlineBeatmapID != null)
beatmapSetOverlay?.FetchAndShowBeatmap(beatmap.OnlineBeatmapID.Value);
else if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null)
beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value);
if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value);
};
Child = new FillFlowContainer
@@ -3,7 +3,6 @@
using osu.Framework.Allocation;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Configuration;
namespace osu.Game.Overlays.Settings
{
@@ -15,8 +14,6 @@ namespace osu.Game.Overlays.Settings
{
private readonly Ruleset ruleset;
protected IRulesetConfigManager Config;
protected RulesetSettingsSubsection(Ruleset ruleset)
{
this.ruleset = ruleset;
@@ -24,13 +21,13 @@ namespace osu.Game.Overlays.Settings
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
Config = dependencies.Get<RulesetConfigCache>().GetConfigFor(ruleset);
if (Config != null)
dependencies.Cache(Config);
var config = dependencies.Get<RulesetConfigCache>().GetConfigFor(ruleset);
if (config != null)
dependencies.Cache(config);
return dependencies;
}
@@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
{
LabelText = "Audio Offset",
Bindable = config.GetBindable<double>(OsuSetting.AudioOffset),
KeyboardStep = 1f
KeyboardStep = 100f
},
new SettingsButton
{
@@ -17,10 +17,10 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
{
Children = new Drawable[]
{
new SettingsSlider<double> { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Master (Window Inactive)", Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive), KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.1f },
new SettingsSlider<double> { LabelText = "Master (Window Inactive)", Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive), KeyboardStep = 0.1f },
new SettingsSlider<double> { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.1f },
new SettingsSlider<double> { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.1f },
};
}
}
@@ -21,13 +21,13 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{
LabelText = "Background dim",
Bindable = config.GetBindable<double>(OsuSetting.DimLevel),
KeyboardStep = 0.01f
KeyboardStep = 0.1f
},
new SettingsSlider<double>
{
LabelText = "Background blur",
Bindable = config.GetBindable<double>(OsuSetting.BlurLevel),
KeyboardStep = 0.01f
KeyboardStep = 0.1f
},
new SettingsCheckbox
{
@@ -31,13 +31,13 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{
LabelText = "Display beatmaps from",
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum),
KeyboardStep = 0.1f
KeyboardStep = 1f
},
new SettingsSlider<double, StarSlider>
{
LabelText = "up to",
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum),
KeyboardStep = 0.1f
KeyboardStep = 1f
},
new SettingsEnumDropdown<RandomSelectAlgorithm>
{
@@ -50,13 +50,13 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{
LabelText = "Horizontal position",
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionX),
KeyboardStep = 0.01f
KeyboardStep = 0.1f
},
new SettingsSlider<double>
{
LabelText = "Vertical position",
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionY),
KeyboardStep = 0.01f
KeyboardStep = 0.1f
},
}
},
@@ -36,13 +36,13 @@ namespace osu.Game.Overlays.Settings.Sections
{
LabelText = "Menu cursor size",
Bindable = config.GetBindable<double>(OsuSetting.MenuCursorSize),
KeyboardStep = 0.01f
KeyboardStep = 0.1f
},
new SettingsSlider<double, SizeSlider>
{
LabelText = "Gameplay cursor size",
Bindable = config.GetBindable<double>(OsuSetting.GameplayCursorSize),
KeyboardStep = 0.01f
KeyboardStep = 0.1f
},
new SettingsCheckbox
{
+1 -1
View File
@@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Toolbar
{
Action = () => OnHome?.Invoke()
},
new ToolbarRulesetSelector()
new ToolbarModeSelector()
}
},
new FillFlowContainer
@@ -7,7 +7,7 @@ using OpenTK.Graphics;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarRulesetButton : ToolbarButton
public class ToolbarModeButton : ToolbarButton
{
private RulesetInfo ruleset;
public RulesetInfo Ruleset
@@ -16,18 +16,18 @@ using osu.Game.Rulesets;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarRulesetSelector : Container
public class ToolbarModeSelector : Container
{
private const float padding = 10;
private readonly FillFlowContainer modeButtons;
private readonly Drawable modeButtonLine;
private ToolbarRulesetButton activeButton;
private ToolbarModeButton activeButton;
private RulesetStore rulesets;
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
public ToolbarRulesetSelector()
public ToolbarModeSelector()
{
RelativeSizeAxes = Axes.Y;
@@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Toolbar
this.rulesets = rulesets;
foreach (var r in rulesets.AvailableRulesets)
{
modeButtons.Add(new ToolbarRulesetButton
modeButtons.Add(new ToolbarModeButton
{
Ruleset = r,
Action = delegate { ruleset.Value = r; }
@@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Toolbar
private void rulesetChanged(RulesetInfo ruleset)
{
foreach (ToolbarRulesetButton m in modeButtons.Children.Cast<ToolbarRulesetButton>())
foreach (ToolbarModeButton m in modeButtons.Children.Cast<ToolbarModeButton>())
{
bool isActive = m.Ruleset.ID == ruleset.ID;
m.Active = isActive;
@@ -9,13 +9,11 @@ using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Volume
{
public class VolumeControlReceptor : Container, IScrollBindingHandler<GlobalAction>, IHandleGlobalInput
public class VolumeControlReceptor : Container, IKeyBindingHandler<GlobalAction>, IHandleGlobalInput
{
public Func<GlobalAction, bool> ActionRequested;
public Func<GlobalAction, float, bool, bool> ScrollActionRequested;
public bool OnPressed(GlobalAction action) => ActionRequested?.Invoke(action) ?? false;
public bool OnScroll(GlobalAction action, float amount, bool isPrecise) => ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;
public bool OnReleased(GlobalAction action) => false;
}
}

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