mirror of
https://github.com/ppy/osu.git
synced 2025-02-19 17:33:18 +08:00
Merge remote-tracking branch 'ppy/master' into select_resolution_in_fullscreen_mode
This commit is contained in:
commit
3dbdfcc1e2
30
.vscode/launch.json
vendored
30
.vscode/launch.json
vendored
@ -11,7 +11,11 @@
|
|||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build tests (Debug)",
|
"preLaunchTask": "Build tests (Debug)",
|
||||||
"env": {},
|
"linux": {
|
||||||
|
"env": {
|
||||||
|
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -24,7 +28,11 @@
|
|||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build tests (Release)",
|
"preLaunchTask": "Build tests (Release)",
|
||||||
"env": {},
|
"linux": {
|
||||||
|
"env": {
|
||||||
|
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -33,11 +41,15 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "dotnet",
|
"program": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
|
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll"
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build osu! (Debug)",
|
"preLaunchTask": "Build osu! (Debug)",
|
||||||
"env": {},
|
"linux": {
|
||||||
|
"env": {
|
||||||
|
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -46,12 +58,16 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "dotnet",
|
"program": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
|
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll"
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build osu! (Release)",
|
"preLaunchTask": "Build osu! (Release)",
|
||||||
"env": {},
|
"linux": {
|
||||||
|
"env": {
|
||||||
|
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
26
README.md
26
README.md
@ -1,18 +1,32 @@
|
|||||||
# osu! [](https://ci.appveyor.com/project/peppy/osu) [](https://www.codefactor.io/repository/github/ppy/osu) [](https://discord.gg/ppy)
|
# osu! [](https://ci.appveyor.com/project/peppy/osu) [](https://www.codefactor.io/repository/github/ppy/osu) [](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!
|
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.
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
- 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.
|
- 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).
|
||||||
|
|
||||||
# Getting Started
|
# Building and running
|
||||||
- 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`)
|
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`).
|
||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
{
|
{
|
||||||
public class CatchBeatmapProcessor : BeatmapProcessor
|
public class CatchBeatmapProcessor : BeatmapProcessor
|
||||||
{
|
{
|
||||||
|
public const int RNG_SEED = 1337;
|
||||||
|
|
||||||
public CatchBeatmapProcessor(IBeatmap beatmap)
|
public CatchBeatmapProcessor(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
@ -22,12 +24,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
|
|
||||||
public override void PostProcess()
|
public override void PostProcess()
|
||||||
{
|
{
|
||||||
|
base.PostProcess();
|
||||||
|
|
||||||
applyPositionOffsets();
|
applyPositionOffsets();
|
||||||
|
|
||||||
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
|
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
|
||||||
|
|
||||||
base.PostProcess();
|
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
|
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
|
||||||
{
|
{
|
||||||
@ -37,8 +39,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public const int RNG_SEED = 1337;
|
|
||||||
|
|
||||||
private void applyPositionOffsets()
|
private void applyPositionOffsets()
|
||||||
{
|
{
|
||||||
var rng = new FastRandom(RNG_SEED);
|
var rng = new FastRandom(RNG_SEED);
|
||||||
|
@ -5,6 +5,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -13,11 +15,10 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
[NonParallelizable]
|
|
||||||
[TestCase("basic")]
|
[TestCase("basic")]
|
||||||
public new void Test(string name)
|
public new void Test(string name)
|
||||||
{
|
{
|
||||||
@ -34,9 +35,35 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override ManiaConvertMapping CreateConvertMapping() => new ManiaConvertMapping(Converter);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
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>
|
public struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
|
var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
|
||||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
columns[i].Add(new DrawableNote(obj, columns[i].Action));
|
columns[i].Add(new DrawableNote(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
|
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
|
||||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
columns[i].Add(new DrawableHoldNote(obj, columns[i].Action));
|
columns[i].Add(new DrawableHoldNote(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Height = 0.85f,
|
Height = 0.85f,
|
||||||
AccentColour = Color4.OrangeRed,
|
AccentColour = Color4.OrangeRed,
|
||||||
Action = action,
|
Action = { Value = action },
|
||||||
VisibleTimeRange = { Value = 2000 }
|
VisibleTimeRange = { Value = 2000 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}")
|
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}")
|
||||||
{
|
{
|
||||||
Child = new DrawableNote(note, ManiaAction.Key1) { AccentColour = Color4.OrangeRed }
|
Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}")
|
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}")
|
||||||
{
|
{
|
||||||
Child = new DrawableHoldNote(note, ManiaAction.Key1)
|
Child = new DrawableHoldNote(note)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
AccentColour = Color4.OrangeRed,
|
AccentColour = Color4.OrangeRed,
|
||||||
@ -136,6 +137,13 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
{
|
||||||
|
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||||
|
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
@ -145,9 +153,6 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
if (!(obj.HitObject is IHasEndTime endTime))
|
if (!(obj.HitObject is IHasEndTime endTime))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!obj.HasNestedHitObjects)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var nested in obj.NestedHitObjects)
|
foreach (var nested in obj.NestedHitObjects)
|
||||||
{
|
{
|
||||||
double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration;
|
double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration;
|
||||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
|
var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
|
||||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
stage.Add(new DrawableNote(obj, stage.Columns[i].Action));
|
stage.Add(new DrawableNote(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
|
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
|
||||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
stage.Add(new DrawableHoldNote(obj, stage.Columns[i].Action));
|
stage.Add(new DrawableHoldNote(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using osu.Game.Rulesets.Mania.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -28,8 +29,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
public int TargetColumns;
|
public int TargetColumns;
|
||||||
public readonly bool IsForCurrentRuleset;
|
public readonly bool IsForCurrentRuleset;
|
||||||
|
|
||||||
|
// Internal for testing purposes
|
||||||
|
internal FastRandom Random { get; private set; }
|
||||||
|
|
||||||
private Pattern lastPattern = new Pattern();
|
private Pattern lastPattern = new Pattern();
|
||||||
private FastRandom random;
|
|
||||||
|
|
||||||
private ManiaBeatmap beatmap;
|
private ManiaBeatmap beatmap;
|
||||||
|
|
||||||
@ -62,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
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);
|
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);
|
return base.ConvertBeatmap(original);
|
||||||
}
|
}
|
||||||
@ -100,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
private double lastTime;
|
private double lastTime;
|
||||||
private Vector2 lastPosition;
|
private Vector2 lastPosition;
|
||||||
private PatternType lastStair;
|
private PatternType lastStair = PatternType.Stair;
|
||||||
private void recordNote(double time, Vector2 position)
|
private void recordNote(double time, Vector2 position)
|
||||||
{
|
{
|
||||||
lastTime = time;
|
lastTime = time;
|
||||||
@ -115,12 +118,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <returns>The hit objects generated.</returns>
|
/// <returns>The hit objects generated.</returns>
|
||||||
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap)
|
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);
|
||||||
|
|
||||||
Pattern newPattern = generator.Generate();
|
foreach (var newPattern in generator.Generate())
|
||||||
lastPattern = newPattern;
|
{
|
||||||
|
lastPattern = newPattern;
|
||||||
|
|
||||||
return newPattern.HitObjects;
|
foreach (var obj in newPattern.HitObjects)
|
||||||
|
yield return obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -138,27 +144,44 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
Patterns.PatternGenerator conversion = null;
|
Patterns.PatternGenerator conversion = null;
|
||||||
|
|
||||||
if (distanceData != null)
|
if (distanceData != null)
|
||||||
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (endTimeData != null)
|
else if (endTimeData != null)
|
||||||
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, originalBeatmap);
|
{
|
||||||
|
conversion = new EndTimeObjectPatternGenerator(Random, original, beatmap, originalBeatmap);
|
||||||
|
|
||||||
|
recordNote(endTimeData.EndTime, new Vector2(256, 192));
|
||||||
|
computeDensity(endTimeData.EndTime);
|
||||||
|
}
|
||||||
else if (positionData != null)
|
else if (positionData != null)
|
||||||
{
|
{
|
||||||
computeDensity(original.StartTime);
|
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);
|
recordNote(original.StartTime, positionData.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversion == null)
|
if (conversion == null)
|
||||||
return null;
|
yield break;
|
||||||
|
|
||||||
Pattern newPattern = conversion.Generate();
|
foreach (var newPattern in conversion.Generate())
|
||||||
|
{
|
||||||
|
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
|
||||||
|
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
|
||||||
|
|
||||||
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
|
foreach (var obj in newPattern.HitObjects)
|
||||||
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
|
yield return obj;
|
||||||
|
|
||||||
return newPattern.HitObjects;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -171,7 +194,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Pattern Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
|
{
|
||||||
|
yield return generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pattern generate()
|
||||||
{
|
{
|
||||||
var endTimeData = HitObject as IHasEndTime;
|
var endTimeData = HitObject as IHasEndTime;
|
||||||
var positionData = HitObject as IHasXPosition;
|
var positionData = HitObject as IHasXPosition;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.MathUtils;
|
using osu.Game.Rulesets.Mania.MathUtils;
|
||||||
@ -24,8 +25,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const float osu_base_scoring_distance = 100;
|
private const float osu_base_scoring_distance = 100;
|
||||||
|
|
||||||
private readonly double endTime;
|
public readonly double EndTime;
|
||||||
private readonly double segmentDuration;
|
public readonly double SegmentDuration;
|
||||||
|
|
||||||
private readonly int spanCount;
|
private readonly int spanCount;
|
||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
@ -52,53 +54,81 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
endTime = hitObject.StartTime + osuDuration;
|
EndTime = hitObject.StartTime + osuDuration;
|
||||||
segmentDuration = (endTime - HitObject.StartTime) / spanCount;
|
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Pattern Generate()
|
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()
|
||||||
{
|
{
|
||||||
if (TotalColumns == 1)
|
if (TotalColumns == 1)
|
||||||
{
|
{
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
addToPattern(pattern, 0, HitObject.StartTime, endTime);
|
addToPattern(pattern, 0, HitObject.StartTime, EndTime);
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spanCount > 1)
|
if (spanCount > 1)
|
||||||
{
|
{
|
||||||
if (segmentDuration <= 90)
|
if (SegmentDuration <= 90)
|
||||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||||
|
|
||||||
if (segmentDuration <= 120)
|
if (SegmentDuration <= 120)
|
||||||
{
|
{
|
||||||
convertType |= PatternType.ForceNotStack;
|
convertType |= PatternType.ForceNotStack;
|
||||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segmentDuration <= 160)
|
if (SegmentDuration <= 160)
|
||||||
return generateStair(HitObject.StartTime);
|
return generateStair(HitObject.StartTime);
|
||||||
|
|
||||||
if (segmentDuration <= 200 && ConversionDifficulty > 3)
|
if (SegmentDuration <= 200 && ConversionDifficulty > 3)
|
||||||
return generateRandomMultipleNotes(HitObject.StartTime);
|
return generateRandomMultipleNotes(HitObject.StartTime);
|
||||||
|
|
||||||
double duration = endTime - HitObject.StartTime;
|
double duration = EndTime - HitObject.StartTime;
|
||||||
if (duration >= 4000)
|
if (duration >= 4000)
|
||||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
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 generateTiledHoldNotes(HitObject.StartTime);
|
||||||
|
|
||||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segmentDuration <= 110)
|
if (SegmentDuration <= 110)
|
||||||
{
|
{
|
||||||
if (PreviousPattern.ColumnWithObjects < TotalColumns)
|
if (PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
convertType |= PatternType.ForceNotStack;
|
convertType |= PatternType.ForceNotStack;
|
||||||
else
|
else
|
||||||
convertType &= ~PatternType.ForceNotStack;
|
convertType &= ~PatternType.ForceNotStack;
|
||||||
return generateRandomNotes(HitObject.StartTime, segmentDuration < 80 ? 1 : 2);
|
return generateRandomNotes(HitObject.StartTime, SegmentDuration < 80 ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConversionDifficulty > 6.5)
|
if (ConversionDifficulty > 6.5)
|
||||||
@ -148,7 +178,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
|
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
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
|
// This is can't be combined with the above loop due to RNG
|
||||||
@ -156,7 +186,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
while (pattern.ColumnHasObject(nextColumn))
|
while (pattern.ColumnHasObject(nextColumn))
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
@ -193,7 +223,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||||
|
|
||||||
lastColumn = nextColumn;
|
lastColumn = nextColumn;
|
||||||
startTime += segmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
@ -223,7 +253,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= spanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, column, startTime, startTime);
|
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
|
// Check if we're at the borders of the stage, and invert the pattern if so
|
||||||
if (increasing)
|
if (increasing)
|
||||||
@ -284,7 +314,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||||
startTime += segmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
@ -372,8 +402,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
while (pattern.ColumnHasObject(nextColumn))
|
while (pattern.ColumnHasObject(nextColumn))
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||||
|
|
||||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||||
startTime += segmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
@ -402,7 +432,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the hold note
|
// Create the hold note
|
||||||
addToPattern(pattern, holdColumn, startTime, endTime);
|
addToPattern(pattern, holdColumn, startTime, EndTime);
|
||||||
|
|
||||||
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||||
int noteCount;
|
int noteCount;
|
||||||
@ -434,7 +464,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
pattern.Add(rowPattern);
|
pattern.Add(rowPattern);
|
||||||
rowPattern.Clear();
|
rowPattern.Clear();
|
||||||
|
|
||||||
startTime += segmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
@ -452,7 +482,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (curveData == null)
|
if (curveData == null)
|
||||||
return HitObject.Samples;
|
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);
|
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||||
return curveData.RepeatSamples[index];
|
return curveData.RepeatSamples[index];
|
||||||
|
@ -24,7 +24,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
endTime = endtimeData?.EndTime ?? 0;
|
endTime = endtimeData?.EndTime ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Pattern Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
|
{
|
||||||
|
yield return generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pattern generate()
|
||||||
{
|
{
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -82,127 +83,133 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
|
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
|
||||||
convertType |= PatternType.Mirror;
|
convertType |= PatternType.Mirror;
|
||||||
else
|
else if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP))
|
||||||
convertType |= PatternType.Gathered;
|
convertType |= PatternType.Gathered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Pattern Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
{
|
{
|
||||||
if (TotalColumns == 1)
|
yield return generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pattern generate()
|
||||||
|
{
|
||||||
|
var pattern = new Pattern();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var pattern = new Pattern();
|
if (TotalColumns == 1)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
targetColumn = RandomStart;
|
addToPattern(pattern, 0);
|
||||||
StairType = PatternType.ReverseStair;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
addToPattern(pattern, targetColumn);
|
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1)
|
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
targetColumn = TotalColumns - 1;
|
// Generate a new pattern by copying the last hit objects in reverse-column order
|
||||||
StairType = PatternType.Stair;
|
for (int i = RandomStart; i < TotalColumns; i++)
|
||||||
|
if (PreviousPattern.ColumnHasObject(i))
|
||||||
|
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
|
||||||
|
|
||||||
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
addToPattern(pattern, targetColumn);
|
if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1
|
||||||
return pattern;
|
// 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);
|
||||||
|
|
||||||
if ((convertType & PatternType.KeepSingle) > 0)
|
return pattern;
|
||||||
return generateRandomNotes(1);
|
}
|
||||||
|
|
||||||
|
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.Mirror) > 0)
|
|
||||||
{
|
|
||||||
if (ConversionDifficulty > 6.5)
|
if (ConversionDifficulty > 6.5)
|
||||||
return generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
|
{
|
||||||
|
if ((convertType & PatternType.LowProbability) > 0)
|
||||||
|
return pattern = generateRandomPattern(0.78, 0.42, 0, 0);
|
||||||
|
return pattern = generateRandomPattern(1, 0.62, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (ConversionDifficulty > 4)
|
if (ConversionDifficulty > 4)
|
||||||
return generateRandomPatternWithMirrored(0.12, 0.17, 0);
|
{
|
||||||
return generateRandomPatternWithMirrored(0.12, 0, 0);
|
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 > 6.5)
|
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);
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
if ((convertType & PatternType.LowProbability) > 0)
|
foreach (var obj in pattern.HitObjects)
|
||||||
return generateRandomPattern(0.78, 0.42, 0, 0);
|
{
|
||||||
return generateRandomPattern(1, 0.62, 0, 0);
|
if ((convertType & PatternType.Stair) > 0 && obj.Column == TotalColumns - 1)
|
||||||
|
StairType = PatternType.ReverseStair;
|
||||||
|
if ((convertType & PatternType.ReverseStair) > 0 && obj.Column == RandomStart)
|
||||||
|
StairType = PatternType.Stair;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
/// <summary>
|
||||||
|
@ -103,17 +103,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault();
|
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault();
|
||||||
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault();
|
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault();
|
||||||
|
|
||||||
double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0);
|
// Drain time in seconds
|
||||||
drainTime -= OriginalBeatmap.TotalBreakTime;
|
int drainTime = (int)(((lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0) - OriginalBeatmap.TotalBreakTime) / 1000);
|
||||||
|
|
||||||
if (drainTime == 0)
|
if (drainTime == 0)
|
||||||
drainTime = 10000000;
|
drainTime = 10000;
|
||||||
|
|
||||||
// We need this in seconds
|
|
||||||
drainTime /= 1000;
|
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
||||||
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
|
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
|
||||||
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
||||||
|
|
||||||
return conversionDifficulty.Value;
|
return conversionDifficulty.Value;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||||
@ -42,9 +43,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates the pattern for <see cref="HitObject"/>, filled with hit objects.
|
/// Generates the patterns for <see cref="HitObject"/>, each filled with hit objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
|
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
||||||
public abstract Pattern Generate();
|
public abstract IEnumerable<Pattern> Generate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,15 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
|||||||
private const uint y = 842502087;
|
private const uint y = 842502087;
|
||||||
private const uint z = 3579807591;
|
private const uint z = 3579807591;
|
||||||
private const uint w = 273326509;
|
private const uint w = 273326509;
|
||||||
private uint _x, _y = y, _z = z, _w = w;
|
|
||||||
|
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;
|
||||||
|
|
||||||
public FastRandom(int seed)
|
public FastRandom(int seed)
|
||||||
{
|
{
|
||||||
_x = (uint)seed;
|
X = (uint)seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FastRandom()
|
public FastRandom()
|
||||||
@ -33,11 +37,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
|||||||
/// <returns>The random value.</returns>
|
/// <returns>The random value.</returns>
|
||||||
public uint NextUInt()
|
public uint NextUInt()
|
||||||
{
|
{
|
||||||
uint t = _x ^ _x << 11;
|
uint t = X ^ X << 11;
|
||||||
_x = _y;
|
X = Y;
|
||||||
_y = _z;
|
Y = Z;
|
||||||
_z = _w;
|
Z = W;
|
||||||
return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
|
return W = W ^ W >> 19 ^ t ^ t >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -38,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
||||||
|
|
||||||
public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
|
public DrawableHoldNote(HoldNote hitObject)
|
||||||
: base(hitObject, action)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
@ -57,12 +57,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
HoldStartTime = () => holdStartTime
|
HoldStartTime = () => holdStartTime
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
head = new DrawableHeadNote(this, action)
|
head = new DrawableHeadNote(this)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
tail = new DrawableTailNote(this, action)
|
tail = new DrawableTailNote(this)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (action != Action)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
||||||
@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (!holdStartTime.HasValue)
|
if (!holdStartTime.HasValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (action != Action)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
holdStartTime = null;
|
holdStartTime = null;
|
||||||
@ -154,8 +154,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableHeadNote(DrawableHoldNote holdNote, ManiaAction action)
|
public DrawableHeadNote(DrawableHoldNote holdNote)
|
||||||
: base(holdNote.HitObject.Head, action)
|
: base(holdNote.HitObject.Head)
|
||||||
{
|
{
|
||||||
this.holdNote = holdNote;
|
this.holdNote = holdNote;
|
||||||
}
|
}
|
||||||
@ -191,8 +191,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
public DrawableTailNote(DrawableHoldNote holdNote)
|
||||||
: base(holdNote.HitObject.Tail, action)
|
: base(holdNote.HitObject.Tail)
|
||||||
{
|
{
|
||||||
this.holdNote = holdNote;
|
this.holdNote = holdNote;
|
||||||
}
|
}
|
||||||
@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (!holdNote.holdStartTime.HasValue)
|
if (!holdNote.holdStartTime.HasValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (action != Action)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UpdateJudgement(true);
|
UpdateJudgement(true);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -10,30 +11,26 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject>
|
public abstract class DrawableManiaHitObject : DrawableHitObject<ManiaHitObject>
|
||||||
where TObject : ManiaHitObject
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key that will trigger input for this hit object.
|
/// The <see cref="ManiaAction"/> which causes this <see cref="DrawableManiaHitObject{TObject}"/> to be hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ManiaAction Action { get; }
|
protected readonly IBindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||||
|
|
||||||
public new TObject HitObject;
|
|
||||||
|
|
||||||
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null)
|
protected DrawableManiaHitObject(ManiaHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
|
||||||
|
|
||||||
if (action != null)
|
|
||||||
Action = action.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
private void load([CanBeNull] IBindable<ManiaAction> action, [NotNull] IScrollingInfo scrollingInfo)
|
||||||
{
|
{
|
||||||
|
if (action != null)
|
||||||
|
Action.BindTo(action);
|
||||||
|
|
||||||
Direction.BindTo(scrollingInfo.Direction);
|
Direction.BindTo(scrollingInfo.Direction);
|
||||||
Direction.BindValueChanged(OnDirectionChanged, true);
|
Direction.BindValueChanged(OnDirectionChanged, true);
|
||||||
}
|
}
|
||||||
@ -42,6 +39,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
|
||||||
|
where TObject : ManiaHitObject
|
||||||
|
{
|
||||||
|
public new readonly TObject HitObject;
|
||||||
|
|
||||||
|
protected DrawableManiaHitObject(TObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
HitObject = hitObject;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
|
@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
private readonly NotePiece headPiece;
|
||||||
|
|
||||||
public DrawableNote(Note hitObject, ManiaAction action)
|
public DrawableNote(Note hitObject)
|
||||||
: base(hitObject, action)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
public virtual bool OnPressed(ManiaAction action)
|
public virtual bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (action != Action)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return UpdateJudgement(true);
|
return UpdateJudgement(true);
|
||||||
|
@ -1,103 +1,132 @@
|
|||||||
{
|
{
|
||||||
"Mappings": [{
|
"Mappings": [{
|
||||||
"StartTime": 500,
|
"RandomW": 2659373485,
|
||||||
"Objects": [{
|
"RandomX": 3579807591,
|
||||||
"StartTime": 500,
|
"RandomY": 273326509,
|
||||||
"EndTime": 2500,
|
"RandomZ": 272969173,
|
||||||
"Column": 0
|
"StartTime": 500.0,
|
||||||
},
|
"Objects": [{
|
||||||
{
|
"StartTime": 500.0,
|
||||||
"StartTime": 1500,
|
"EndTime": 2500.0,
|
||||||
"EndTime": 2500,
|
"Column": 0
|
||||||
"Column": 1
|
}, {
|
||||||
}
|
"StartTime": 1500.0,
|
||||||
]
|
"EndTime": 2500.0,
|
||||||
},
|
"Column": 1
|
||||||
{
|
}]
|
||||||
"StartTime": 3000,
|
}, {
|
||||||
"Objects": [{
|
"RandomW": 3083803045,
|
||||||
"StartTime": 3000,
|
"RandomX": 273326509,
|
||||||
"EndTime": 4000,
|
"RandomY": 272969173,
|
||||||
"Column": 2
|
"RandomZ": 2659373485,
|
||||||
}]
|
"StartTime": 3000.0,
|
||||||
},
|
"Objects": [{
|
||||||
{
|
"StartTime": 3000.0,
|
||||||
"StartTime": 4500,
|
"EndTime": 4000.0,
|
||||||
"Objects": [{
|
"Column": 2
|
||||||
"StartTime": 4500,
|
}]
|
||||||
"EndTime": 5500,
|
}, {
|
||||||
"Column": 4
|
"RandomW": 4073554232,
|
||||||
}]
|
"RandomX": 272969173,
|
||||||
},
|
"RandomY": 2659373485,
|
||||||
{
|
"RandomZ": 3083803045,
|
||||||
"StartTime": 6000,
|
"StartTime": 4500.0,
|
||||||
"Objects": [{
|
"Objects": [{
|
||||||
"StartTime": 6000,
|
"StartTime": 4500.0,
|
||||||
"EndTime": 6500,
|
"EndTime": 5500.0,
|
||||||
"Column": 2
|
"Column": 4
|
||||||
}]
|
}]
|
||||||
},
|
}, {
|
||||||
{
|
"RandomW": 3420401969,
|
||||||
"StartTime": 7000,
|
"RandomX": 2659373485,
|
||||||
"Objects": [{
|
"RandomY": 3083803045,
|
||||||
"StartTime": 7000,
|
"RandomZ": 4073554232,
|
||||||
"EndTime": 8000,
|
"StartTime": 6000.0,
|
||||||
"Column": 2
|
"Objects": [{
|
||||||
}]
|
"StartTime": 6000.0,
|
||||||
},
|
"EndTime": 6500.0,
|
||||||
{
|
"Column": 2
|
||||||
"StartTime": 8500,
|
}]
|
||||||
"Objects": [{
|
}, {
|
||||||
"StartTime": 8500,
|
"RandomW": 1129881182,
|
||||||
"EndTime": 11000,
|
"RandomX": 3083803045,
|
||||||
"Column": 0
|
"RandomY": 4073554232,
|
||||||
}]
|
"RandomZ": 3420401969,
|
||||||
},
|
"StartTime": 7000.0,
|
||||||
{
|
"Objects": [{
|
||||||
"StartTime": 11500,
|
"StartTime": 7000.0,
|
||||||
"Objects": [{
|
"EndTime": 8000.0,
|
||||||
"StartTime": 11500,
|
"Column": 2
|
||||||
"EndTime": 12000,
|
}]
|
||||||
"Column": 1
|
}, {
|
||||||
}]
|
"RandomW": 315568458,
|
||||||
},
|
"RandomX": 3420401969,
|
||||||
{
|
"RandomY": 1129881182,
|
||||||
"StartTime": 12500,
|
"RandomZ": 2358617505,
|
||||||
"Objects": [{
|
"StartTime": 8500.0,
|
||||||
"StartTime": 12500,
|
"Objects": [{
|
||||||
"EndTime": 16500,
|
"StartTime": 8500.0,
|
||||||
"Column": 4
|
"EndTime": 11000.0,
|
||||||
}]
|
"Column": 0
|
||||||
},
|
}]
|
||||||
{
|
}, {
|
||||||
"StartTime": 17000,
|
"RandomW": 548134043,
|
||||||
"Objects": [{
|
"RandomX": 1129881182,
|
||||||
"StartTime": 17000,
|
"RandomY": 2358617505,
|
||||||
"EndTime": 18000,
|
"RandomZ": 315568458,
|
||||||
"Column": 2
|
"StartTime": 11500.0,
|
||||||
}]
|
"Objects": [{
|
||||||
},
|
"StartTime": 11500.0,
|
||||||
{
|
"EndTime": 12000.0,
|
||||||
"StartTime": 18500,
|
"Column": 1
|
||||||
"Objects": [{
|
}]
|
||||||
"StartTime": 18500,
|
}, {
|
||||||
"EndTime": 19450,
|
"RandomW": 3979422122,
|
||||||
"Column": 0
|
"RandomX": 548134043,
|
||||||
}]
|
"RandomY": 2810584254,
|
||||||
},
|
"RandomZ": 2250186050,
|
||||||
{
|
"StartTime": 12500.0,
|
||||||
"StartTime": 19875,
|
"Objects": [{
|
||||||
"Objects": [{
|
"StartTime": 12500.0,
|
||||||
"StartTime": 19875,
|
"EndTime": 16500.0,
|
||||||
"EndTime": 23875,
|
"Column": 4
|
||||||
"Column": 1
|
}]
|
||||||
},
|
}, {
|
||||||
{
|
"RandomW": 2466283411,
|
||||||
"StartTime": 19875,
|
"RandomX": 2810584254,
|
||||||
"EndTime": 23875,
|
"RandomY": 2250186050,
|
||||||
"Column": 0
|
"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
|
||||||
|
}]
|
||||||
|
}]
|
||||||
}
|
}
|
@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.UI.Components;
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
@ -19,21 +21,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
private const float column_width = 45;
|
private const float column_width = 45;
|
||||||
private const float special_column_width = 70;
|
private const float special_column_width = 70;
|
||||||
|
|
||||||
private ManiaAction action;
|
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||||
|
|
||||||
public ManiaAction Action
|
|
||||||
{
|
|
||||||
get => action;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (action == value)
|
|
||||||
return;
|
|
||||||
action = value;
|
|
||||||
|
|
||||||
background.Action = value;
|
|
||||||
keyArea.Action = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ColumnBackground background;
|
private readonly ColumnBackground background;
|
||||||
private readonly ColumnKeyArea keyArea;
|
private readonly ColumnKeyArea keyArea;
|
||||||
@ -130,6 +118,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
{
|
||||||
|
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||||
|
dependencies.CacheAs<IBindable<ManiaAction>>(Action);
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a DrawableHitObject to this Playfield.
|
/// Adds a DrawableHitObject to this Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
{
|
{
|
||||||
public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||||
{
|
{
|
||||||
public ManiaAction Action;
|
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
|
||||||
|
|
||||||
private Box background;
|
private Box background;
|
||||||
private Box backgroundOverlay;
|
private Box backgroundOverlay;
|
||||||
@ -25,8 +25,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
|
||||||
{
|
{
|
||||||
|
this.action.BindTo(action);
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
background = new Box
|
background = new Box
|
||||||
@ -91,14 +93,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (action == Action)
|
if (action == this.action.Value)
|
||||||
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnReleased(ManiaAction action)
|
public bool OnReleased(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (action == Action)
|
if (action == this.action.Value)
|
||||||
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -21,15 +21,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
private const float key_icon_size = 10;
|
private const float key_icon_size = 10;
|
||||||
private const float key_icon_corner_radius = 3;
|
private const float key_icon_corner_radius = 3;
|
||||||
|
|
||||||
public ManiaAction Action;
|
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
|
||||||
|
|
||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
private Container keyIcon;
|
private Container keyIcon;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
|
||||||
{
|
{
|
||||||
|
this.action.BindTo(action);
|
||||||
|
|
||||||
Drawable gradient;
|
Drawable gradient;
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
@ -107,14 +108,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (action == Action)
|
if (action == this.action.Value)
|
||||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnReleased(ManiaAction action)
|
public bool OnReleased(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (action == Action)
|
if (action == this.action.Value)
|
||||||
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -101,17 +101,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
||||||
{
|
{
|
||||||
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
|
switch (h)
|
||||||
|
{
|
||||||
var holdNote = h as HoldNote;
|
case HoldNote holdNote:
|
||||||
if (holdNote != null)
|
return new DrawableHoldNote(holdNote);
|
||||||
return new DrawableHoldNote(holdNote, action);
|
case Note note:
|
||||||
|
return new DrawableNote(note);
|
||||||
var note = h as Note;
|
default:
|
||||||
if (note != null)
|
return null;
|
||||||
return new DrawableNote(note, action);
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
|
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
|
||||||
|
@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
var column = new Column(direction)
|
var column = new Column(direction)
|
||||||
{
|
{
|
||||||
IsSpecial = isSpecial,
|
IsSpecial = isSpecial,
|
||||||
Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++
|
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
|
||||||
};
|
};
|
||||||
|
|
||||||
AddColumn(column);
|
AddColumn(column);
|
||||||
|
@ -15,10 +15,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostProcess()
|
public override void PreProcess()
|
||||||
{
|
{
|
||||||
|
base.PreProcess();
|
||||||
applyStacking((Beatmap<OsuHitObject>)Beatmap);
|
applyStacking((Beatmap<OsuHitObject>)Beatmap);
|
||||||
base.PostProcess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyStacking(Beatmap<OsuHitObject> beatmap)
|
private void applyStacking(Beatmap<OsuHitObject> beatmap)
|
||||||
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
|
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
|
||||||
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
||||||
|
|
||||||
if (objectN.StartTime - endTime > stackThreshold)
|
if (objectN.StartTime - endTime > stackThreshold)
|
||||||
//We are no longer within stacking range of the next object.
|
//We are no longer within stacking range of the next object.
|
||||||
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
OsuHitObject objectI = beatmap.HitObjects[i];
|
OsuHitObject objectI = beatmap.HitObjects[i];
|
||||||
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
||||||
|
|
||||||
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
||||||
|
|
||||||
/* If this object is a hitcircle, then we enter this "special" case.
|
/* If this object is a hitcircle, then we enter this "special" case.
|
||||||
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
||||||
|
@ -93,9 +93,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
base.AccentColour = value;
|
base.AccentColour = value;
|
||||||
Body.AccentColour = AccentColour;
|
Body.AccentColour = AccentColour;
|
||||||
Ball.AccentColour = AccentColour;
|
Ball.AccentColour = AccentColour;
|
||||||
if (HasNestedHitObjects)
|
|
||||||
foreach (var drawableHitObject in NestedHitObjects)
|
foreach (var drawableHitObject in NestedHitObjects)
|
||||||
drawableHitObject.AccentColour = AccentColour;
|
drawableHitObject.AccentColour = AccentColour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
if (!userTriggered && Time.Current >= slider.EndTime)
|
if (!userTriggered && Time.Current >= slider.EndTime)
|
||||||
{
|
{
|
||||||
var judgementsCount = NestedHitObjects.Count;
|
var judgementsCount = NestedHitObjects.Count();
|
||||||
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
||||||
|
|
||||||
var hitFraction = (double)judgementsHit / judgementsCount;
|
var hitFraction = (double)judgementsHit / judgementsCount;
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
private void loadBarLines()
|
private void loadBarLines()
|
||||||
{
|
{
|
||||||
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
|
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
|
||||||
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
|
double lastHitTime = 1 + ((lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime);
|
||||||
|
|
||||||
var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList();
|
var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList();
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ using osu.Game.Audio;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.Formats
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
@ -211,5 +212,41 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
|
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("hitnormal", getTestableSampleInfo(hitObjects[0]).Name);
|
||||||
|
Assert.AreEqual("hitnormal", getTestableSampleInfo(hitObjects[1]).Name);
|
||||||
|
Assert.AreEqual("hitnormal2", getTestableSampleInfo(hitObjects[2]).Name);
|
||||||
|
Assert.AreEqual("hitnormal", getTestableSampleInfo(hitObjects[3]).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
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("hitnormal2", getTestableSampleInfo(hitObjects[2]).Name);
|
||||||
|
Assert.AreEqual("hit_1.wav", hitObjects[3].Samples[0].LookupNames.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,11 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
public void TestParity(string beatmap)
|
public void TestParity(string beatmap)
|
||||||
{
|
{
|
||||||
var legacy = decode(beatmap, out Beatmap json);
|
var legacy = decode(beatmap, out Beatmap json);
|
||||||
json.WithDeepEqual(legacy).IgnoreProperty(r => r.DeclaringType == typeof(HitWindows)).Assert();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
16
osu.Game.Tests/Resources/custom-hitobject-samples.osu
Normal file
16
osu.Game.Tests/Resources/custom-hitobject-samples.osu
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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
|
16
osu.Game.Tests/Resources/custom-samples.osu
Normal file
16
osu.Game.Tests/Resources/custom-samples.osu
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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:
|
@ -65,17 +65,19 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
||||||
{
|
{
|
||||||
var ruleset = rulesetInfo.CreateInstance();
|
var instance = rulesetInfo.CreateInstance();
|
||||||
var testBeatmap = createTestBeatmap(rulesetInfo);
|
var testBeatmap = createTestBeatmap(rulesetInfo);
|
||||||
|
|
||||||
beatmaps.Add(testBeatmap);
|
beatmaps.Add(testBeatmap);
|
||||||
|
|
||||||
|
AddStep("set ruleset", () => Ruleset.Value = rulesetInfo);
|
||||||
|
|
||||||
selectBeatmap(testBeatmap);
|
selectBeatmap(testBeatmap);
|
||||||
|
|
||||||
testBeatmapLabels(ruleset);
|
testBeatmapLabels(instance);
|
||||||
|
|
||||||
// TODO: adjust cases once more info is shown for other gamemodes
|
// TODO: adjust cases once more info is shown for other gamemodes
|
||||||
switch (ruleset)
|
switch (instance)
|
||||||
{
|
{
|
||||||
case OsuRuleset _:
|
case OsuRuleset _:
|
||||||
testInfoLabels(5);
|
testInfoLabels(5);
|
||||||
|
@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
||||||
{
|
{
|
||||||
Ruleset ruleset = rulesetInfo.CreateInstance();
|
Ruleset ruleset = rulesetInfo.CreateInstance();
|
||||||
AddStep($"switch to {ruleset.Description}", () => modSelect.Ruleset.Value = rulesetInfo);
|
AddStep($"switch to {ruleset.Description}", () => Ruleset.Value = rulesetInfo);
|
||||||
|
|
||||||
switch (ruleset)
|
switch (ruleset)
|
||||||
{
|
{
|
||||||
|
@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
private class TestOnScreenDisplay : OnScreenDisplay
|
private class TestOnScreenDisplay : OnScreenDisplay
|
||||||
{
|
{
|
||||||
protected override void Display(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
|
||||||
JoinDate = DateTimeOffset.Now.AddDays(-1),
|
JoinDate = DateTimeOffset.Now.AddDays(-1),
|
||||||
LastVisit = DateTimeOffset.Now,
|
LastVisit = DateTimeOffset.Now,
|
||||||
Age = 1,
|
|
||||||
ProfileOrder = new[] { "me" },
|
ProfileOrder = new[] { "me" },
|
||||||
Statistics = new UserStatistics
|
Statistics = new UserStatistics
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace osu.Game.Audio
|
namespace osu.Game.Audio
|
||||||
{
|
{
|
||||||
@ -32,5 +33,21 @@ namespace osu.Game.Audio
|
|||||||
/// The sample volume.
|
/// The sample volume.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Volume;
|
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))
|
||||||
|
yield return $"{Namespace}/{Bank}-{Name}";
|
||||||
|
|
||||||
|
yield return $"{Bank}-{Name}"; // Without namespace as a fallback even when we have a namespace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SampleInfo Clone() => (SampleInfo)MemberwiseClone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,9 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public interface IBeatmapProcessor
|
|
||||||
{
|
|
||||||
IBeatmap Beatmap { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Post-processes <see cref="Beatmap"/> to add mode-specific components that aren't added during conversion.
|
|
||||||
/// <para>
|
|
||||||
/// An example of such a usage is for combo colours.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
void PostProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes a post-converted Beatmap.
|
/// Provides functionality to alter a <see cref="IBeatmap"/> after it has been converted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TObject">The type of HitObject contained in the Beatmap.</typeparam>
|
|
||||||
public class BeatmapProcessor : IBeatmapProcessor
|
public class BeatmapProcessor : IBeatmapProcessor
|
||||||
{
|
{
|
||||||
public IBeatmap Beatmap { get; }
|
public IBeatmap Beatmap { get; }
|
||||||
@ -32,13 +18,7 @@ namespace osu.Game.Beatmaps
|
|||||||
Beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public virtual void PreProcess()
|
||||||
/// Post-processes a Beatmap to add mode-specific components that aren't added during conversion.
|
|
||||||
/// <para>
|
|
||||||
/// An example of such a usage is for combo colours.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
public virtual void PostProcess()
|
|
||||||
{
|
{
|
||||||
IHasComboInformation lastObj = null;
|
IHasComboInformation lastObj = null;
|
||||||
|
|
||||||
@ -62,5 +42,9 @@ namespace osu.Game.Beatmaps
|
|||||||
lastObj = obj;
|
lastObj = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void PostProcess()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,15 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
|
|
||||||
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
|
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
|
||||||
|
|
||||||
public bool Equals(ControlPoint other) => Time.Equals(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,5 +17,10 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double speedMultiplier = 1;
|
private double speedMultiplier = 1;
|
||||||
|
|
||||||
|
public override bool EquivalentTo(ControlPoint other)
|
||||||
|
=> base.EquivalentTo(other)
|
||||||
|
&& other is DifficultyControlPoint difficulty
|
||||||
|
&& SpeedMultiplier.Equals(difficulty.SpeedMultiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,11 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// Whether the first bar line of this control point is ignored.
|
/// Whether the first bar line of this control point is ignored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool OmitFirstBarLine;
|
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,5 +30,25 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
Name = sampleName,
|
Name = sampleName,
|
||||||
Volume = SampleVolume,
|
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,5 +23,11 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double beatLength = 1000;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,9 +289,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (split.Length >= 4)
|
if (split.Length >= 4)
|
||||||
sampleSet = (LegacySampleBank)int.Parse(split[3]);
|
sampleSet = (LegacySampleBank)int.Parse(split[3]);
|
||||||
|
|
||||||
//SampleBank sampleBank = SampleBank.Default;
|
int customSampleBank = 0;
|
||||||
//if (split.Length >= 5)
|
if (split.Length >= 5)
|
||||||
// sampleBank = (SampleBank)int.Parse(split[4]);
|
customSampleBank = int.Parse(split[4]);
|
||||||
|
|
||||||
int sampleVolume = defaultSampleVolume;
|
int sampleVolume = defaultSampleVolume;
|
||||||
if (split.Length >= 6)
|
if (split.Length >= 6)
|
||||||
@ -314,13 +314,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (stringSampleSet == @"none")
|
if (stringSampleSet == @"none")
|
||||||
stringSampleSet = @"normal";
|
stringSampleSet = @"normal";
|
||||||
|
|
||||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time);
|
|
||||||
SampleControlPoint samplePoint = beatmap.ControlPointInfo.SamplePointAt(time);
|
|
||||||
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time);
|
|
||||||
|
|
||||||
if (timingChange)
|
if (timingChange)
|
||||||
{
|
{
|
||||||
beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint
|
handleTimingControlPoint(new TimingControlPoint
|
||||||
{
|
{
|
||||||
Time = time,
|
Time = time,
|
||||||
BeatLength = beatLength,
|
BeatLength = beatLength,
|
||||||
@ -328,41 +324,68 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (speedMultiplier != difficultyPoint.SpeedMultiplier)
|
handleDifficultyControlPoint(new DifficultyControlPoint
|
||||||
{
|
{
|
||||||
beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time);
|
Time = time,
|
||||||
beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint
|
SpeedMultiplier = speedMultiplier
|
||||||
{
|
});
|
||||||
Time = time,
|
|
||||||
SpeedMultiplier = speedMultiplier
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringSampleSet != samplePoint.SampleBank || sampleVolume != samplePoint.SampleVolume)
|
handleEffectControlPoint(new EffectControlPoint
|
||||||
{
|
{
|
||||||
beatmap.ControlPointInfo.SamplePoints.Add(new SampleControlPoint
|
Time = time,
|
||||||
{
|
KiaiMode = kiaiMode,
|
||||||
Time = time,
|
OmitFirstBarLine = omitFirstBarSignature
|
||||||
SampleBank = stringSampleSet,
|
});
|
||||||
SampleVolume = sampleVolume
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine)
|
handleSampleControlPoint(new LegacySampleControlPoint
|
||||||
{
|
{
|
||||||
beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint
|
Time = time,
|
||||||
{
|
SampleBank = stringSampleSet,
|
||||||
Time = time,
|
SampleVolume = sampleVolume,
|
||||||
KiaiMode = kiaiMode,
|
CustomSampleBank = customSampleBank
|
||||||
OmitFirstBarLine = omitFirstBarSignature
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (FormatException e)
|
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)
|
private void handleHitObject(string line)
|
||||||
{
|
{
|
||||||
// If the ruleset wasn't specified, assume the osu!standard ruleset.
|
// If the ruleset wasn't specified, assume the osu!standard ruleset.
|
||||||
|
@ -5,6 +5,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
@ -167,5 +169,25 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
Pass = 2,
|
Pass = 2,
|
||||||
Foreground = 3
|
Foreground = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class LegacySampleControlPoint : SampleControlPoint
|
||||||
|
{
|
||||||
|
public int CustomSampleBank;
|
||||||
|
|
||||||
|
public override SampleInfo ApplyTo(SampleInfo sampleInfo)
|
||||||
|
{
|
||||||
|
var baseInfo = base.ApplyTo(sampleInfo);
|
||||||
|
|
||||||
|
if (CustomSampleBank > 1)
|
||||||
|
baseInfo.Name += CustomSampleBank;
|
||||||
|
|
||||||
|
return baseInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool EquivalentTo(ControlPoint other)
|
||||||
|
=> base.EquivalentTo(other)
|
||||||
|
&& other is LegacySampleControlPoint legacy
|
||||||
|
&& CustomSampleBank == legacy.CustomSampleBank;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ using osu.Game.Rulesets.Objects;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides functionality to convert a <see cref="IBeatmap"/> for a <see cref="Ruleset"/>.
|
||||||
|
/// </summary>
|
||||||
public interface IBeatmapConverter
|
public interface IBeatmapConverter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
40
osu.Game/Beatmaps/IBeatmapProcessor.cs
Normal file
40
osu.Game/Beatmaps/IBeatmapProcessor.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides functionality to alter a <see cref="IBeatmap"/> after it has been converted.
|
||||||
|
/// </summary>
|
||||||
|
public interface IBeatmapProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IBeatmap"/> to process. This should already be converted to the applicable <see cref="Ruleset"/>.
|
||||||
|
/// </summary>
|
||||||
|
IBeatmap Beatmap { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes the converted <see cref="Beatmap"/> prior to <see cref="HitObject.ApplyDefaults"/> being invoked.
|
||||||
|
/// <para>
|
||||||
|
/// Nested <see cref="HitObject"/>s generated during <see cref="HitObject.ApplyDefaults"/> will not be present by this point,
|
||||||
|
/// and no mods will have been applied to the <see cref="HitObject"/>s.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This can only be used to add alterations to <see cref="HitObject"/>s generated directly through the conversion process.
|
||||||
|
/// </remarks>
|
||||||
|
void PreProcess();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes the converted <see cref="Beatmap"/> after <see cref="HitObject.ApplyDefaults"/> has been invoked.
|
||||||
|
/// <para>
|
||||||
|
/// Nested <see cref="HitObject"/>s generated during <see cref="HitObject.ApplyDefaults"/> will be present by this point,
|
||||||
|
/// and mods will have been applied to all <see cref="HitObject"/>s.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This should be used to add alterations to <see cref="HitObject"/>s while they are in their most playable state.
|
||||||
|
/// </remarks>
|
||||||
|
void PostProcess();
|
||||||
|
}
|
||||||
|
}
|
@ -116,6 +116,10 @@ namespace osu.Game.Beatmaps
|
|||||||
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
|
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted);
|
||||||
|
|
||||||
|
processor?.PreProcess();
|
||||||
|
|
||||||
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
|
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
|
||||||
foreach (var obj in converted.HitObjects)
|
foreach (var obj in converted.HitObjects)
|
||||||
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
|
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
|
||||||
@ -124,8 +128,7 @@ namespace osu.Game.Beatmaps
|
|||||||
foreach (var obj in converted.HitObjects)
|
foreach (var obj in converted.HitObjects)
|
||||||
mod.ApplyToHitObject(obj);
|
mod.ApplyToHitObject(obj);
|
||||||
|
|
||||||
// Post-process
|
processor?.PostProcess();
|
||||||
rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess();
|
|
||||||
|
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,14 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner
|
public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private SampleChannel samplePopIn;
|
private SampleChannel samplePopIn;
|
||||||
private SampleChannel samplePopOut;
|
private SampleChannel samplePopOut;
|
||||||
@ -65,6 +67,19 @@ namespace osu.Game.Graphics.Containers
|
|||||||
return base.OnClick(state);
|
return base.OnClick(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action == GlobalAction.Back)
|
||||||
|
{
|
||||||
|
State = Visibility.Hidden;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
|
|
||||||
private void onStateChanged(Visibility visibility)
|
private void onStateChanged(Visibility visibility)
|
||||||
{
|
{
|
||||||
switch (visibility)
|
switch (visibility)
|
||||||
|
@ -11,9 +11,9 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
@ -22,12 +22,13 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
private readonly IBindable<bool> screenshotCursorVisibility = new Bindable<bool>(true);
|
private readonly IBindable<bool> screenshotCursorVisibility = new Bindable<bool>(true);
|
||||||
public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent;
|
public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent;
|
||||||
|
|
||||||
protected override Drawable CreateCursor() => new Cursor();
|
protected override Drawable CreateCursor() => activeCursor = new Cursor();
|
||||||
|
|
||||||
|
private Cursor activeCursor;
|
||||||
|
|
||||||
private Bindable<bool> cursorRotate;
|
private Bindable<bool> cursorRotate;
|
||||||
private bool dragging;
|
private DragRotationState dragRotationState;
|
||||||
|
private Vector2 positionMouseDown;
|
||||||
private bool startRotation;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager)
|
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager)
|
||||||
@ -40,46 +41,50 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
|
|
||||||
protected override bool OnMouseMove(InputState state)
|
protected override bool OnMouseMove(InputState state)
|
||||||
{
|
{
|
||||||
if (cursorRotate && dragging)
|
if (dragRotationState != DragRotationState.NotDragging)
|
||||||
{
|
{
|
||||||
Debug.Assert(state.Mouse.PositionMouseDown != null);
|
var position = state.Mouse.Position;
|
||||||
|
var distance = Vector2Extensions.Distance(position, positionMouseDown);
|
||||||
// don't start rotating until we're moved a minimum distance away from the mouse down location,
|
// don't start rotating until we're moved a minimum distance away from the mouse down location,
|
||||||
// else it can have an annoying effect.
|
// else it can have an annoying effect.
|
||||||
// ReSharper disable once PossibleInvalidOperationException
|
if (dragRotationState == DragRotationState.DragStarted && distance > 30)
|
||||||
startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30;
|
dragRotationState = DragRotationState.Rotating;
|
||||||
|
// don't rotate when distance is zero to avoid NaN
|
||||||
if (startRotation)
|
if (dragRotationState == DragRotationState.Rotating && distance > 0)
|
||||||
{
|
{
|
||||||
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value;
|
Vector2 offset = state.Mouse.Position - positionMouseDown;
|
||||||
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
|
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
|
||||||
|
|
||||||
// Always rotate in the direction of least distance
|
// 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;
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseMove(state);
|
return base.OnMouseMove(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
|
||||||
{
|
|
||||||
dragging = true;
|
|
||||||
return base.OnDragStart(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
{
|
{
|
||||||
ActiveCursor.Scale = new Vector2(1);
|
// only trigger animation for main mouse buttons
|
||||||
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
|
if (args.Button <= MouseButton.Right)
|
||||||
|
{
|
||||||
|
activeCursor.Scale = new Vector2(1);
|
||||||
|
activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
|
||||||
|
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
|
activeCursor.AdditiveLayer.Alpha = 0;
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
|
activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Button == MouseButton.Left && cursorRotate)
|
||||||
|
{
|
||||||
|
dragRotationState = DragRotationState.DragStarted;
|
||||||
|
positionMouseDown = state.Mouse.Position;
|
||||||
|
}
|
||||||
return base.OnMouseDown(state, args);
|
return base.OnMouseDown(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,34 +92,29 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
if (!state.Mouse.HasMainButtonPressed)
|
if (!state.Mouse.HasMainButtonPressed)
|
||||||
{
|
{
|
||||||
dragging = false;
|
activeCursor.AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
|
||||||
startRotation = false;
|
activeCursor.ScaleTo(1, 500, Easing.OutElastic);
|
||||||
|
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
|
|
||||||
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
|
|
||||||
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);
|
||||||
|
dragRotationState = DragRotationState.NotDragging;
|
||||||
|
}
|
||||||
return base.OnMouseUp(state, args);
|
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()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
|
activeCursor.FadeTo(1, 250, Easing.OutQuint);
|
||||||
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
|
activeCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
|
activeCursor.FadeTo(0, 250, Easing.OutQuint);
|
||||||
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
|
activeCursor.ScaleTo(0.6f, 250, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Cursor : Container
|
public class Cursor : Container
|
||||||
@ -160,5 +160,12 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
cursorScale.TriggerChange();
|
cursorScale.TriggerChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum DragRotationState
|
||||||
|
{
|
||||||
|
NotDragging,
|
||||||
|
DragStarted,
|
||||||
|
Rotating,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using System;
|
using System;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
@ -19,6 +20,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
public Action Exit;
|
public Action Exit;
|
||||||
|
|
||||||
private bool focus;
|
private bool focus;
|
||||||
|
|
||||||
public bool HoldFocus
|
public bool HoldFocus
|
||||||
{
|
{
|
||||||
get { return focus; }
|
get { return focus; }
|
||||||
@ -26,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
focus = value;
|
focus = value;
|
||||||
if (!focus && HasFocus)
|
if (!focus && HasFocus)
|
||||||
GetContainingInputManager().ChangeFocus(null);
|
base.KillFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,18 +43,34 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
if (!HasFocus) return false;
|
||||||
{
|
|
||||||
if (Text.Length > 0)
|
if (args.Key == Key.Escape)
|
||||||
Text = string.Empty;
|
return false; // disable the framework-level handling of escape key for confority (we use GlobalAction.Back).
|
||||||
else
|
|
||||||
Exit?.Invoke();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
return base.OnKeyDown(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action == GlobalAction.Back)
|
||||||
|
{
|
||||||
|
if (Text.Length > 0)
|
||||||
|
{
|
||||||
|
Text = string.Empty;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnPressed(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void KillFocus()
|
||||||
|
{
|
||||||
|
base.KillFocus();
|
||||||
|
Exit?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
public override bool RequestsFocus => HoldFocus;
|
public override bool RequestsFocus => HoldFocus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
|
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
|
||||||
|
|
||||||
public override bool AllowClipboardExport => false;
|
protected override bool AllowClipboardExport => false;
|
||||||
|
|
||||||
private readonly CapsWarning warning;
|
private readonly CapsWarning warning;
|
||||||
|
|
||||||
|
@ -9,10 +9,12 @@ using osu.Framework.Input;
|
|||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class OsuTextBox : TextBox
|
public class OsuTextBox : TextBox, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f);
|
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f);
|
||||||
protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f);
|
protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f);
|
||||||
@ -33,10 +35,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
TextContainer.Height = 0.5f;
|
TextContainer.Height = 0.5f;
|
||||||
CornerRadius = 5;
|
CornerRadius = 5;
|
||||||
|
|
||||||
Current.DisabledChanged += disabled =>
|
Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; };
|
||||||
{
|
|
||||||
Alpha = disabled ? 0.3f : 1;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -59,5 +58,18 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize };
|
protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize };
|
||||||
|
|
||||||
|
public virtual bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action == GlobalAction.Back)
|
||||||
|
{
|
||||||
|
KillFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (HandlePendingText(state)) return true;
|
|
||||||
|
|
||||||
if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed)
|
if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed)
|
||||||
{
|
{
|
||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
|
@ -39,13 +39,18 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
||||||
|
|
||||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||||
new KeyBinding(InputKey.MouseButton1, GlobalAction.Back)
|
new KeyBinding(InputKey.MouseButton1, GlobalAction.Back),
|
||||||
|
|
||||||
|
new KeyBinding(InputKey.Space, GlobalAction.Select),
|
||||||
|
new KeyBinding(InputKey.Enter, GlobalAction.Select),
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||||
{
|
{
|
||||||
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene),
|
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene),
|
||||||
new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry)
|
new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
||||||
@ -84,7 +89,16 @@ namespace osu.Game.Input.Bindings
|
|||||||
[Description("Toggle gameplay mouse buttons")]
|
[Description("Toggle gameplay mouse buttons")]
|
||||||
ToggleGameplayMouseButtons,
|
ToggleGameplayMouseButtons,
|
||||||
|
|
||||||
[Description("Go back")]
|
[Description("Back")]
|
||||||
Back
|
Back,
|
||||||
|
|
||||||
|
[Description("Increase scroll speed")]
|
||||||
|
IncreaseScrollSpeed,
|
||||||
|
|
||||||
|
[Description("Decrease scroll speed")]
|
||||||
|
DecreaseScrollSpeed,
|
||||||
|
|
||||||
|
[Description("Select")]
|
||||||
|
Select,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
private DateTimeOffset submitted { get; set; }
|
private DateTimeOffset submitted { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"ranked_date")]
|
[JsonProperty(@"ranked_date")]
|
||||||
private DateTimeOffset ranked { get; set; }
|
private DateTimeOffset? ranked { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"last_updated")]
|
[JsonProperty(@"last_updated")]
|
||||||
private DateTimeOffset lastUpdated { get; set; }
|
private DateTimeOffset lastUpdated { get; set; }
|
||||||
|
@ -250,7 +250,8 @@ namespace osu.Game
|
|||||||
new VolumeControlReceptor
|
new VolumeControlReceptor
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ActionRequested = action => volume.Adjust(action)
|
ActionRequested = action => volume.Adjust(action),
|
||||||
|
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
|
||||||
},
|
},
|
||||||
mainContent = new Container { RelativeSizeAxes = Axes.Both },
|
mainContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
|
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
|
||||||
|
@ -6,16 +6,17 @@ using System.Linq;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Dialog
|
namespace osu.Game.Overlays.Dialog
|
||||||
{
|
{
|
||||||
@ -23,6 +24,9 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
{
|
{
|
||||||
public static readonly float ENTER_DURATION = 500;
|
public static readonly float ENTER_DURATION = 500;
|
||||||
public static readonly float EXIT_DURATION = 200;
|
public static readonly float EXIT_DURATION = 200;
|
||||||
|
|
||||||
|
protected override bool BlockPassThroughMouse => false;
|
||||||
|
|
||||||
private readonly Vector2 ringSize = new Vector2(100f);
|
private readonly Vector2 ringSize = new Vector2(100f);
|
||||||
private readonly Vector2 ringMinifiedSize = new Vector2(20f);
|
private readonly Vector2 ringMinifiedSize = new Vector2(20f);
|
||||||
private readonly Vector2 buttonsEnterSpacing = new Vector2(0f, 50f);
|
private readonly Vector2 buttonsEnterSpacing = new Vector2(0f, 50f);
|
||||||
@ -34,26 +38,28 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
private readonly SpriteText header;
|
private readonly SpriteText header;
|
||||||
private readonly TextFlowContainer body;
|
private readonly TextFlowContainer body;
|
||||||
|
|
||||||
|
private bool actionInvoked;
|
||||||
|
|
||||||
public FontAwesome Icon
|
public FontAwesome Icon
|
||||||
{
|
{
|
||||||
get { return icon.Icon; }
|
get => icon.Icon;
|
||||||
set { icon.Icon = value; }
|
set => icon.Icon = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string HeaderText
|
public string HeaderText
|
||||||
{
|
{
|
||||||
get { return header.Text; }
|
get => header.Text;
|
||||||
set { header.Text = value; }
|
set => header.Text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BodyText
|
public string BodyText
|
||||||
{
|
{
|
||||||
set { body.Text = value; }
|
set => body.Text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<PopupDialogButton> Buttons
|
public IEnumerable<PopupDialogButton> Buttons
|
||||||
{
|
{
|
||||||
get { return buttonsContainer.Children; }
|
get => buttonsContainer.Children;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
buttonsContainer.ChildrenEnumerable = value;
|
buttonsContainer.ChildrenEnumerable = value;
|
||||||
@ -62,71 +68,17 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
var action = b.Action;
|
var action = b.Action;
|
||||||
b.Action = () =>
|
b.Action = () =>
|
||||||
{
|
{
|
||||||
Hide();
|
if (actionInvoked) return;
|
||||||
|
|
||||||
|
actionInvoked = true;
|
||||||
action?.Invoke();
|
action?.Invoke();
|
||||||
|
|
||||||
|
Hide();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pressButtonAtIndex(int index)
|
|
||||||
{
|
|
||||||
if (index < Buttons.Count())
|
|
||||||
Buttons.Skip(index).First().TriggerOnClick();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.Repeat) return false;
|
|
||||||
|
|
||||||
if (args.Key == Key.Enter || args.Key == Key.KeypadEnter)
|
|
||||||
{
|
|
||||||
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// press button at number if 1-9 on number row or keypad are pressed
|
|
||||||
var k = args.Key;
|
|
||||||
if (k >= Key.Number1 && k <= Key.Number9)
|
|
||||||
{
|
|
||||||
pressButtonAtIndex(k - Key.Number1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k >= Key.Keypad1 && k <= Key.Keypad9)
|
|
||||||
{
|
|
||||||
pressButtonAtIndex(k - Key.Keypad1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopIn()
|
|
||||||
{
|
|
||||||
base.PopIn();
|
|
||||||
|
|
||||||
// Reset various animations but only if the dialog animation fully completed
|
|
||||||
if (content.Alpha == 0)
|
|
||||||
{
|
|
||||||
buttonsContainer.TransformSpacingTo(buttonsEnterSpacing);
|
|
||||||
buttonsContainer.MoveToY(buttonsEnterSpacing.Y);
|
|
||||||
ring.ResizeTo(ringMinifiedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
content.FadeIn(ENTER_DURATION, Easing.OutQuint);
|
|
||||||
ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint);
|
|
||||||
buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint);
|
|
||||||
buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopOut()
|
|
||||||
{
|
|
||||||
base.PopOut();
|
|
||||||
|
|
||||||
content.FadeOut(EXIT_DURATION, Easing.InSine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PopupDialog()
|
public PopupDialog()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -136,9 +88,6 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
content = new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Width = 0.4f,
|
|
||||||
Alpha = 0f,
|
Alpha = 0f,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -243,5 +192,75 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.Select:
|
||||||
|
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnPressed(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Repeat) return false;
|
||||||
|
|
||||||
|
// press button at number if 1-9 on number row or keypad are pressed
|
||||||
|
var k = args.Key;
|
||||||
|
if (k >= Key.Number1 && k <= Key.Number9)
|
||||||
|
{
|
||||||
|
pressButtonAtIndex(k - Key.Number1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k >= Key.Keypad1 && k <= Key.Keypad9)
|
||||||
|
{
|
||||||
|
pressButtonAtIndex(k - Key.Keypad1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnKeyDown(state, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
base.PopIn();
|
||||||
|
|
||||||
|
actionInvoked = false;
|
||||||
|
|
||||||
|
// Reset various animations but only if the dialog animation fully completed
|
||||||
|
if (content.Alpha == 0)
|
||||||
|
{
|
||||||
|
buttonsContainer.TransformSpacingTo(buttonsEnterSpacing);
|
||||||
|
buttonsContainer.MoveToY(buttonsEnterSpacing.Y);
|
||||||
|
ring.ResizeTo(ringMinifiedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
content.FadeIn(ENTER_DURATION, Easing.OutQuint);
|
||||||
|
ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint);
|
||||||
|
buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint);
|
||||||
|
buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
if (!actionInvoked)
|
||||||
|
// In the case a user did not choose an action before a hide was triggered, press the last button.
|
||||||
|
// This is presumed to always be a sane default "cancel" action.
|
||||||
|
buttonsContainer.Last().TriggerOnClick();
|
||||||
|
|
||||||
|
base.PopOut();
|
||||||
|
content.FadeOut(EXIT_DURATION, Easing.InSine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pressButtonAtIndex(int index)
|
||||||
|
{
|
||||||
|
if (index < Buttons.Count())
|
||||||
|
Buttons.Skip(index).First().TriggerOnClick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Overlays.Dialog;
|
using osu.Game.Overlays.Dialog;
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
@ -16,6 +13,20 @@ namespace osu.Game.Overlays
|
|||||||
private readonly Container dialogContainer;
|
private readonly Container dialogContainer;
|
||||||
private PopupDialog currentDialog;
|
private PopupDialog currentDialog;
|
||||||
|
|
||||||
|
public DialogOverlay()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Child = dialogContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
|
||||||
|
Width = 0.4f;
|
||||||
|
Anchor = Anchor.BottomCentre;
|
||||||
|
Origin = Anchor.BottomCentre;
|
||||||
|
}
|
||||||
|
|
||||||
public void Push(PopupDialog dialog)
|
public void Push(PopupDialog dialog)
|
||||||
{
|
{
|
||||||
if (dialog == currentDialog) return;
|
if (dialog == currentDialog) return;
|
||||||
@ -32,6 +43,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
protected override bool PlaySamplesOnStateChange => false;
|
protected override bool PlaySamplesOnStateChange => false;
|
||||||
|
|
||||||
|
protected override bool BlockPassThroughKeyboard => true;
|
||||||
|
|
||||||
private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v)
|
private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v)
|
||||||
{
|
{
|
||||||
if (v != Visibility.Hidden) return;
|
if (v != Visibility.Hidden) return;
|
||||||
@ -52,32 +65,14 @@ namespace osu.Game.Overlays
|
|||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
base.PopOut();
|
base.PopOut();
|
||||||
this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DialogOverlay()
|
if (currentDialog?.State == Visibility.Visible)
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Container
|
currentDialog.Hide();
|
||||||
{
|
return;
|
||||||
RelativeSizeAxes = Axes.Both,
|
}
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine);
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4.Black.Opacity(0.5f),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dialogContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
{
|
{
|
||||||
if (bindTarget.IsHovered)
|
if (bindTarget.IsHovered)
|
||||||
{
|
{
|
||||||
bindTarget.UpdateKeyCombination(new KeyCombination(KeyCombination.FromInputState(state).Keys.Append(state.Mouse.ScrollDelta.Y > 0 ? InputKey.MouseWheelUp : InputKey.MouseWheelDown)));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state, state.Mouse.ScrollDelta));
|
||||||
finalise();
|
finalise();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -202,9 +202,6 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
|
|
||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.Escape:
|
|
||||||
finalise();
|
|
||||||
return true;
|
|
||||||
case Key.Delete:
|
case Key.Delete:
|
||||||
{
|
{
|
||||||
if (state.Keyboard.ShiftPressed)
|
if (state.Keyboard.ShiftPressed)
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>();
|
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>();
|
||||||
|
|
||||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
public readonly IBindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
private void rulesetChanged(RulesetInfo newRuleset)
|
private void rulesetChanged(RulesetInfo newRuleset)
|
||||||
{
|
{
|
||||||
@ -51,8 +51,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
refreshSelectedMods();
|
refreshSelectedMods();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, Bindable<RulesetInfo> ruleset, RulesetStore rulesets, AudioManager audio)
|
private void load(OsuColour colours, IBindable<RulesetInfo> ruleset, AudioManager audio)
|
||||||
{
|
{
|
||||||
SelectedMods.ValueChanged += selectedModsChanged;
|
SelectedMods.ValueChanged += selectedModsChanged;
|
||||||
|
|
||||||
@ -60,13 +60,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
HighMultiplierColour = colours.Green;
|
HighMultiplierColour = colours.Green;
|
||||||
UnrankedLabel.Colour = colours.Blue;
|
UnrankedLabel.Colour = colours.Blue;
|
||||||
|
|
||||||
if (ruleset != null)
|
Ruleset.BindTo(ruleset);
|
||||||
Ruleset.BindTo(ruleset);
|
Ruleset.BindValueChanged(rulesetChanged, true);
|
||||||
else
|
|
||||||
Ruleset.Value = rulesets.AvailableRulesets.First();
|
|
||||||
|
|
||||||
Ruleset.ValueChanged += rulesetChanged;
|
|
||||||
Ruleset.TriggerChange();
|
|
||||||
|
|
||||||
sampleOn = audio.Sample.Get(@"UI/check-on");
|
sampleOn = audio.Sample.Get(@"UI/check-on");
|
||||||
sampleOff = audio.Sample.Get(@"UI/check-off");
|
sampleOff = audio.Sample.Get(@"UI/check-off");
|
||||||
|
@ -14,6 +14,8 @@ using osu.Game.Graphics;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics.Transforms;
|
||||||
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
@ -135,7 +137,7 @@ namespace osu.Game.Overlays
|
|||||||
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
|
/// <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)
|
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)))
|
if (trackedConfigManagers.ContainsKey((source, configManager)))
|
||||||
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
|
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
|
||||||
@ -159,7 +161,7 @@ namespace osu.Game.Overlays
|
|||||||
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <see cref="source"/>.</exception>
|
/// <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)
|
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))
|
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
|
||||||
throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
|
throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
|
||||||
@ -181,7 +183,7 @@ namespace osu.Game.Overlays
|
|||||||
if (string.IsNullOrEmpty(textLine3.Text))
|
if (string.IsNullOrEmpty(textLine3.Text))
|
||||||
textLine3.Text = "NO KEY BOUND";
|
textLine3.Text = "NO KEY BOUND";
|
||||||
|
|
||||||
Display(box);
|
DisplayTemporarily(box);
|
||||||
|
|
||||||
int optionCount = 0;
|
int optionCount = 0;
|
||||||
int selectedOption = -1;
|
int selectedOption = -1;
|
||||||
@ -213,15 +215,29 @@ namespace osu.Game.Overlays
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Display(Drawable toDisplay)
|
private TransformSequence<Drawable> fadeIn;
|
||||||
|
private ScheduledDelegate fadeOut;
|
||||||
|
|
||||||
|
protected virtual void DisplayTemporarily(Drawable toDisplay)
|
||||||
{
|
{
|
||||||
toDisplay.Animate(
|
// avoid starting a new fade-in if one is already active.
|
||||||
b => b.FadeIn(500, Easing.OutQuint),
|
if (fadeIn == null)
|
||||||
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
|
{
|
||||||
).Then(
|
fadeIn = toDisplay.Animate(
|
||||||
b => b.FadeOutFromOne(1500, Easing.InQuint),
|
b => b.FadeIn(500, Easing.OutQuint),
|
||||||
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OptionLight : Container
|
private class OptionLight : Container
|
||||||
|
@ -360,11 +360,6 @@ namespace osu.Game.Overlays.Profile
|
|||||||
Text = text
|
Text = text
|
||||||
};
|
};
|
||||||
|
|
||||||
if (user.Age != null)
|
|
||||||
{
|
|
||||||
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.Country != null)
|
if (user.Country != null)
|
||||||
{
|
{
|
||||||
infoTextLeft.AddText("From ", lightText);
|
infoTextLeft.AddText("From ", lightText);
|
||||||
|
@ -56,7 +56,13 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
|
|
||||||
reloadSkins();
|
reloadSkins();
|
||||||
|
|
||||||
skinDropdown.Bindable = config.GetBindable<int>(OsuSetting.Skin);
|
var skinBindable = config.GetBindable<int>(OsuSetting.Skin);
|
||||||
|
|
||||||
|
// Todo: This should not be necessary when OsuConfigManager is databased
|
||||||
|
if (skinDropdown.Items.All(s => s.Value != skinBindable.Value))
|
||||||
|
skinBindable.Value = 0;
|
||||||
|
|
||||||
|
skinDropdown.Bindable = skinBindable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
|
private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetStore rulesets, Bindable<RulesetInfo> parentRuleset)
|
private void load(RulesetStore rulesets, Bindable<RulesetInfo> parentRuleset)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
@ -82,11 +82,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
ruleset.ValueChanged += rulesetChanged;
|
ruleset.ValueChanged += rulesetChanged;
|
||||||
ruleset.DisabledChanged += disabledChanged;
|
ruleset.DisabledChanged += disabledChanged;
|
||||||
|
ruleset.BindTo(parentRuleset);
|
||||||
if (parentRuleset != null)
|
|
||||||
ruleset.BindTo(parentRuleset);
|
|
||||||
else
|
|
||||||
ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
@ -9,11 +9,13 @@ using osu.Game.Input.Bindings;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.Volume
|
namespace osu.Game.Overlays.Volume
|
||||||
{
|
{
|
||||||
public class VolumeControlReceptor : Container, IKeyBindingHandler<GlobalAction>, IHandleGlobalInput
|
public class VolumeControlReceptor : Container, IScrollBindingHandler<GlobalAction>, IHandleGlobalInput
|
||||||
{
|
{
|
||||||
public Func<GlobalAction, bool> ActionRequested;
|
public Func<GlobalAction, bool> ActionRequested;
|
||||||
|
public Func<GlobalAction, float, bool, bool> ScrollActionRequested;
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action) => ActionRequested?.Invoke(action) ?? false;
|
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;
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,15 @@ using osu.Framework.Graphics.Effects;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Input.Bindings;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Volume
|
namespace osu.Game.Overlays.Volume
|
||||||
{
|
{
|
||||||
public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
|
public class VolumeMeter : Container
|
||||||
{
|
{
|
||||||
private CircularProgress volumeCircle;
|
private CircularProgress volumeCircle;
|
||||||
private CircularProgress volumeCircleGlow;
|
private CircularProgress volumeCircleGlow;
|
||||||
@ -226,59 +224,27 @@ namespace osu.Game.Overlays.Volume
|
|||||||
|
|
||||||
private const float adjust_step = 0.05f;
|
private const float adjust_step = 0.05f;
|
||||||
|
|
||||||
public void Increase() => adjust(1);
|
public void Increase(double amount = 1, bool isPrecise = false) => adjust(amount, isPrecise);
|
||||||
public void Decrease() => adjust(-1);
|
public void Decrease(double amount = 1, bool isPrecise = false) => adjust(-amount, isPrecise);
|
||||||
|
|
||||||
private void adjust(int direction)
|
|
||||||
{
|
|
||||||
float amount = adjust_step * direction;
|
|
||||||
|
|
||||||
// handle the case where the OnPressed action was actually a mouse wheel.
|
|
||||||
// this allows for precise wheel handling.
|
|
||||||
var state = GetContainingInputManager().CurrentState;
|
|
||||||
if (state.Mouse?.ScrollDelta.Y != 0)
|
|
||||||
{
|
|
||||||
OnScroll(state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Volume += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
|
||||||
{
|
|
||||||
if (!IsHovered) return false;
|
|
||||||
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case GlobalAction.DecreaseVolume:
|
|
||||||
Decrease();
|
|
||||||
return true;
|
|
||||||
case GlobalAction.IncreaseVolume:
|
|
||||||
Increase();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// because volume precision is set to 0.01, this local is required to keep track of more precise adjustments and only apply when possible.
|
// because volume precision is set to 0.01, this local is required to keep track of more precise adjustments and only apply when possible.
|
||||||
private double scrollAmount;
|
private double adjustAccumulator;
|
||||||
|
|
||||||
|
private void adjust(double delta, bool isPrecise)
|
||||||
|
{
|
||||||
|
adjustAccumulator += delta * adjust_step * (isPrecise ? 0.1 : 1);
|
||||||
|
if (Math.Abs(adjustAccumulator) < Bindable.Precision)
|
||||||
|
return;
|
||||||
|
Volume += adjustAccumulator;
|
||||||
|
adjustAccumulator = 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnScroll(InputState state)
|
protected override bool OnScroll(InputState state)
|
||||||
{
|
{
|
||||||
scrollAmount += adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.1f : 1);
|
adjust(state.Mouse.ScrollDelta.Y, state.Mouse.HasPreciseScroll);
|
||||||
|
|
||||||
if (Math.Abs(scrollAmount) < Bindable.Precision)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Volume += scrollAmount;
|
|
||||||
scrollAmount = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnReleased(GlobalAction action) => false;
|
|
||||||
|
|
||||||
private const float transition_length = 500;
|
private const float transition_length = 500;
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
|
@ -93,7 +93,7 @@ namespace osu.Game.Overlays
|
|||||||
muteButton.Current.ValueChanged += _ => Show();
|
muteButton.Current.ValueChanged += _ => Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Adjust(GlobalAction action)
|
public bool Adjust(GlobalAction action, float amount = 1, bool isPrecise = false)
|
||||||
{
|
{
|
||||||
if (!IsLoaded) return false;
|
if (!IsLoaded) return false;
|
||||||
|
|
||||||
@ -103,13 +103,13 @@ namespace osu.Game.Overlays
|
|||||||
if (State == Visibility.Hidden)
|
if (State == Visibility.Hidden)
|
||||||
Show();
|
Show();
|
||||||
else
|
else
|
||||||
volumeMeterMaster.Decrease();
|
volumeMeterMaster.Decrease(amount, isPrecise);
|
||||||
return true;
|
return true;
|
||||||
case GlobalAction.IncreaseVolume:
|
case GlobalAction.IncreaseVolume:
|
||||||
if (State == Visibility.Hidden)
|
if (State == Visibility.Hidden)
|
||||||
Show();
|
Show();
|
||||||
else
|
else
|
||||||
volumeMeterMaster.Increase();
|
volumeMeterMaster.Increase(amount, isPrecise);
|
||||||
return true;
|
return true;
|
||||||
case GlobalAction.ToggleMute:
|
case GlobalAction.ToggleMute:
|
||||||
Show();
|
Show();
|
||||||
|
@ -33,8 +33,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
protected virtual IEnumerable<SampleInfo> GetSamples() => HitObject.Samples;
|
protected virtual IEnumerable<SampleInfo> GetSamples() => HitObject.Samples;
|
||||||
|
|
||||||
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
|
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
|
||||||
public bool HasNestedHitObjects => nestedHitObjects.IsValueCreated;
|
public IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty<DrawableHitObject>();
|
||||||
public IReadOnlyList<DrawableHitObject> NestedHitObjects => nestedHitObjects.Value;
|
|
||||||
|
|
||||||
public event Action<DrawableHitObject, Judgement> OnJudgement;
|
public event Action<DrawableHitObject, Judgement> OnJudgement;
|
||||||
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved;
|
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved;
|
||||||
@ -50,12 +49,12 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been hit.
|
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && (!HasNestedHitObjects || NestedHitObjects.All(n => n.IsHit));
|
public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && NestedHitObjects.All(n => n.IsHit);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (!HasNestedHitObjects || NestedHitObjects.All(h => h.AllJudged));
|
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && NestedHitObjects.All(h => h.AllJudged);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableHitObject"/> can be judged.
|
/// Whether this <see cref="DrawableHitObject"/> can be judged.
|
||||||
@ -90,13 +89,12 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
if (HitObject.SampleControlPoint == null)
|
if (HitObject.SampleControlPoint == null)
|
||||||
throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
|
throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
|
||||||
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
||||||
AddInternal(Samples = new SkinnableSound(samples.Select(s => new SampleInfo
|
|
||||||
{
|
samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray();
|
||||||
Bank = s.Bank ?? HitObject.SampleControlPoint.SampleBank,
|
foreach (var s in samples)
|
||||||
Name = s.Name,
|
s.Namespace = SampleNamespace;
|
||||||
Volume = s.Volume > 0 ? s.Volume : HitObject.SampleControlPoint.SampleVolume,
|
|
||||||
Namespace = SampleNamespace
|
AddInternal(Samples = new SkinnableSound(samples));
|
||||||
}).ToArray()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,9 +204,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
if (AllJudged)
|
if (AllJudged)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (HasNestedHitObjects)
|
foreach (var d in NestedHitObjects)
|
||||||
foreach (var d in NestedHitObjects)
|
judgementOccurred |= d.UpdateJudgement(userTriggered);
|
||||||
judgementOccurred |= d.UpdateJudgement(userTriggered);
|
|
||||||
|
|
||||||
if (!ProvidesJudgement || judgementFinalized || judgementOccurred)
|
if (!ProvidesJudgement || judgementFinalized || judgementOccurred)
|
||||||
return judgementOccurred;
|
return judgementOccurred;
|
||||||
|
@ -6,6 +6,7 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -196,9 +197,6 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
|
var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
|
||||||
var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
|
var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
|
||||||
|
|
||||||
// Let's not implement this for now, because this doesn't fit nicely into the bank structure
|
|
||||||
//string sampleFile = split2.Length > 4 ? split2[4] : string.Empty;
|
|
||||||
|
|
||||||
string stringBank = bank.ToString().ToLower();
|
string stringBank = bank.ToString().ToLower();
|
||||||
if (stringBank == @"none")
|
if (stringBank == @"none")
|
||||||
stringBank = null;
|
stringBank = null;
|
||||||
@ -211,6 +209,8 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
|
|
||||||
if (split.Length > 3)
|
if (split.Length > 3)
|
||||||
bankInfo.Volume = int.Parse(split[3]);
|
bankInfo.Volume = int.Parse(split[3]);
|
||||||
|
|
||||||
|
bankInfo.Filename = split.Length > 4 ? split[4] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -252,6 +252,10 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
|
|
||||||
private List<SampleInfo> convertSoundType(LegacySoundType type, SampleBankInfo bankInfo)
|
private List<SampleInfo> convertSoundType(LegacySoundType type, SampleBankInfo bankInfo)
|
||||||
{
|
{
|
||||||
|
// Todo: This should return the normal SampleInfos if the specified sample file isn't found, but that's a pretty edge-case scenario
|
||||||
|
if (!string.IsNullOrEmpty(bankInfo.Filename))
|
||||||
|
return new List<SampleInfo> { new FileSampleInfo { Filename = bankInfo.Filename } };
|
||||||
|
|
||||||
var soundTypes = new List<SampleInfo>
|
var soundTypes = new List<SampleInfo>
|
||||||
{
|
{
|
||||||
new SampleInfo
|
new SampleInfo
|
||||||
@ -297,14 +301,24 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
|
|
||||||
private class SampleBankInfo
|
private class SampleBankInfo
|
||||||
{
|
{
|
||||||
|
public string Filename;
|
||||||
|
|
||||||
public string Normal;
|
public string Normal;
|
||||||
public string Add;
|
public string Add;
|
||||||
public int Volume;
|
public int Volume;
|
||||||
|
|
||||||
public SampleBankInfo Clone()
|
public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FileSampleInfo : SampleInfo
|
||||||
|
{
|
||||||
|
public string Filename;
|
||||||
|
|
||||||
|
public override IEnumerable<string> LookupNames => new[]
|
||||||
{
|
{
|
||||||
return (SampleBankInfo)MemberwiseClone();
|
Filename,
|
||||||
}
|
Path.ChangeExtension(Filename, null)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
@ -57,8 +57,18 @@ namespace osu.Game.Rulesets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap);
|
public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to be converted.</param>
|
||||||
|
/// <returns>The <see cref="IBeatmapConverter"/>.</returns>
|
||||||
public abstract IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap);
|
public abstract IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="IBeatmapProcessor"/> to alter a <see cref="IBeatmap"/> after it has been converted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to be processed.</param>
|
||||||
|
/// <returns>The <see cref="IBeatmapProcessor"/>.</returns>
|
||||||
public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null;
|
public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null;
|
||||||
|
|
||||||
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
||||||
|
@ -84,7 +84,13 @@ namespace osu.Game.Rulesets
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var instanceInfo = ((Ruleset)Activator.CreateInstance(Type.GetType(r.InstantiationInfo), (RulesetInfo)null)).RulesetInfo;
|
var instanceInfo = ((Ruleset)Activator.CreateInstance(Type.GetType(r.InstantiationInfo, asm =>
|
||||||
|
{
|
||||||
|
// for the time being, let's ignore the version being loaded.
|
||||||
|
// this allows for debug builds to successfully load rulesets (even though debug rulesets have a 0.0.0 version).
|
||||||
|
asm.Version = null;
|
||||||
|
return Assembly.Load(asm);
|
||||||
|
}, null), (RulesetInfo)null)).RulesetInfo;
|
||||||
|
|
||||||
r.Name = instanceInfo.Name;
|
r.Name = instanceInfo.Name;
|
||||||
r.ShortName = instanceInfo.ShortName;
|
r.ShortName = instanceInfo.ShortName;
|
||||||
|
@ -4,30 +4,33 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using OpenTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.UI.Scrolling
|
namespace osu.Game.Rulesets.UI.Scrolling
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A type of <see cref="Playfield"/> specialized towards scrolling <see cref="DrawableHitObject"/>s.
|
/// A type of <see cref="Playfield"/> specialized towards scrolling <see cref="DrawableHitObject"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ScrollingPlayfield : Playfield
|
public abstract class ScrollingPlayfield : Playfield, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default span of time visible by the length of the scrolling axes.
|
/// The default span of time visible by the length of the scrolling axes.
|
||||||
/// This is clamped between <see cref="time_span_min"/> and <see cref="time_span_max"/>.
|
/// This is clamped between <see cref="time_span_min"/> and <see cref="time_span_max"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double time_span_default = 1500;
|
private const double time_span_default = 1500;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The minimum span of time that may be visible by the length of the scrolling axes.
|
/// The minimum span of time that may be visible by the length of the scrolling axes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double time_span_min = 50;
|
private const double time_span_min = 50;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum span of time that may be visible by the length of the scrolling axes.
|
/// The maximum span of time that may be visible by the length of the scrolling axes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double time_span_max = 10000;
|
private const double time_span_max = 10000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The step increase/decrease of the span of time visible by the length of the scrolling axes.
|
/// The step increase/decrease of the span of time visible by the length of the scrolling axes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -78,27 +81,26 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
HitObjects.TimeRange.BindTo(VisibleTimeRange);
|
HitObjects.TimeRange.BindTo(VisibleTimeRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
public bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (!UserScrollSpeedAdjustment)
|
if (!UserScrollSpeedAdjustment)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (state.Keyboard.ControlPressed)
|
switch (action)
|
||||||
{
|
{
|
||||||
switch (args.Key)
|
case GlobalAction.IncreaseScrollSpeed:
|
||||||
{
|
this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 200, Easing.OutQuint);
|
||||||
case Key.Minus:
|
return true;
|
||||||
this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 600, Easing.OutQuint);
|
case GlobalAction.DecreaseScrollSpeed:
|
||||||
break;
|
this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 200, Easing.OutQuint);
|
||||||
case Key.Plus:
|
return true;
|
||||||
this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 600, Easing.OutQuint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
|
|
||||||
protected sealed override HitObjectContainer CreateHitObjectContainer()
|
protected sealed override HitObjectContainer CreateHitObjectContainer()
|
||||||
{
|
{
|
||||||
var container = new ScrollingHitObjectContainer();
|
var container = new ScrollingHitObjectContainer();
|
||||||
|
@ -47,13 +47,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.HasNestedHitObjects)
|
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
||||||
{
|
|
||||||
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
|
||||||
|
|
||||||
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
||||||
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,13 +48,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.HasNestedHitObjects)
|
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
||||||
{
|
|
||||||
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
|
||||||
|
|
||||||
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
||||||
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,14 @@ namespace osu.Game.Screens
|
|||||||
while (screen.LoadState < LoadState.Ready)
|
while (screen.LoadState < LoadState.Ready)
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
|
|
||||||
base.Push(screen);
|
try
|
||||||
|
{
|
||||||
|
base.Push(screen);
|
||||||
|
}
|
||||||
|
catch (ScreenAlreadyExitedException)
|
||||||
|
{
|
||||||
|
// screen may have exited before the push was successful.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -139,28 +138,15 @@ namespace osu.Game.Screens.Menu
|
|||||||
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
|
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.Repeat) return false;
|
|
||||||
|
|
||||||
switch (args.Key)
|
|
||||||
{
|
|
||||||
case Key.Space:
|
|
||||||
logo?.TriggerOnClick(state);
|
|
||||||
return true;
|
|
||||||
case Key.Escape:
|
|
||||||
return goBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
public bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case GlobalAction.Back:
|
case GlobalAction.Back:
|
||||||
return goBack();
|
return goBack();
|
||||||
|
case GlobalAction.Select:
|
||||||
|
logo?.TriggerOnClick();
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -181,16 +167,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnReleased(GlobalAction action)
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
{
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case GlobalAction.Back:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onPlay()
|
private void onPlay()
|
||||||
{
|
{
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using OpenTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Menu
|
namespace osu.Game.Screens.Menu
|
||||||
{
|
{
|
||||||
public class ExitConfirmOverlay : HoldToConfirmOverlay
|
public class ExitConfirmOverlay : HoldToConfirmOverlay, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
public bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (args.Key == Key.Escape && !args.Repeat)
|
if (action == GlobalAction.Back)
|
||||||
{
|
{
|
||||||
BeginConfirm();
|
BeginConfirm();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
public bool OnReleased(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (args.Key == Key.Escape)
|
if (action == GlobalAction.Back)
|
||||||
{
|
{
|
||||||
AbortConfirm();
|
AbortConfirm();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnKeyUp(state, args);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.Audio;
|
|||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -17,7 +16,6 @@ using osu.Game.Input.Bindings;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
@ -84,11 +82,8 @@ namespace osu.Game.Screens
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset)
|
private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset)
|
||||||
{
|
{
|
||||||
if (beatmap != null)
|
Beatmap.BindTo(beatmap);
|
||||||
Beatmap.BindTo(beatmap);
|
Ruleset.BindTo(ruleset);
|
||||||
|
|
||||||
if (ruleset != null)
|
|
||||||
Ruleset.BindTo(ruleset);
|
|
||||||
|
|
||||||
if (osu != null)
|
if (osu != null)
|
||||||
{
|
{
|
||||||
@ -106,8 +101,10 @@ namespace osu.Game.Screens
|
|||||||
sampleExit = audio.Sample.Get(@"UI/screen-back");
|
sampleExit = audio.Sample.Get(@"UI/screen-back");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
public virtual bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
|
if (!IsCurrentScreen) return false;
|
||||||
|
|
||||||
if (action == GlobalAction.Back && AllowBackButton)
|
if (action == GlobalAction.Back && AllowBackButton)
|
||||||
{
|
{
|
||||||
Exit();
|
Exit();
|
||||||
@ -119,20 +116,6 @@ namespace osu.Game.Screens
|
|||||||
|
|
||||||
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
|
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.Repeat || !IsCurrentScreen) return false;
|
|
||||||
|
|
||||||
switch (args.Key)
|
|
||||||
{
|
|
||||||
case Key.Escape:
|
|
||||||
Exit();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnResuming(Screen last)
|
protected override void OnResuming(Screen last)
|
||||||
{
|
{
|
||||||
sampleExit?.Play();
|
sampleExit?.Play();
|
||||||
@ -197,11 +180,10 @@ namespace osu.Game.Screens
|
|||||||
|
|
||||||
if (Background != null && !Background.Equals(nextOsu?.Background))
|
if (Background != null && !Background.Equals(nextOsu?.Background))
|
||||||
{
|
{
|
||||||
if (nextOsu != null)
|
Background.Exit();
|
||||||
//We need to use MakeCurrent in case we are jumping up multiple game screens.
|
|
||||||
nextOsu.Background?.MakeCurrent();
|
//We need to use MakeCurrent in case we are jumping up multiple game screens.
|
||||||
else
|
nextOsu?.Background?.MakeCurrent();
|
||||||
Background.Exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base.OnExiting(next))
|
if (base.OnExiting(next))
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
@ -21,16 +18,5 @@ namespace osu.Game.Screens.Play
|
|||||||
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
|
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
|
||||||
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
|
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
|
||||||
{
|
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
|
||||||
{
|
|
||||||
InternalButtons.Children.Last().TriggerOnClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,13 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
public abstract class GameplayMenuOverlay : OverlayContainer
|
public abstract class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private const int transition_duration = 200;
|
private const int transition_duration = 200;
|
||||||
private const int button_height = 70;
|
private const int button_height = 70;
|
||||||
@ -31,6 +34,11 @@ namespace osu.Game.Screens.Play
|
|||||||
public Action OnRetry;
|
public Action OnRetry;
|
||||||
public Action OnQuit;
|
public Action OnQuit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action that is invoked when <see cref="GlobalAction.Back"/> is triggered.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual Action BackAction => () => InternalButtons.Children.Last().TriggerOnClick();
|
||||||
|
|
||||||
public abstract string Header { get; }
|
public abstract string Header { get; }
|
||||||
public abstract string Description { get; }
|
public abstract string Description { get; }
|
||||||
|
|
||||||
@ -219,6 +227,19 @@ namespace osu.Game.Screens.Play
|
|||||||
return base.OnKeyDown(state, args);
|
return base.OnKeyDown(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action == GlobalAction.Back)
|
||||||
|
{
|
||||||
|
BackAction.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back;
|
||||||
|
|
||||||
private void buttonSelectionChanged(DialogButton button, bool isSelected)
|
private void buttonSelectionChanged(DialogButton button, bool isSelected)
|
||||||
{
|
{
|
||||||
if (!isSelected)
|
if (!isSelected)
|
||||||
|
@ -6,11 +6,9 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
@ -138,16 +136,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public override string Header => "paused";
|
public override string Header => "paused";
|
||||||
public override string Description => "you're not going to do what i think you're going to do, are ya?";
|
public override string Description => "you're not going to do what i think you're going to do, are ya?";
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override Action BackAction => () => InternalButtons.Children.First().TriggerOnClick();
|
||||||
{
|
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
|
||||||
{
|
|
||||||
InternalButtons.Children.First().TriggerOnClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
|
@ -49,8 +49,6 @@ namespace osu.Game.Screens.Play
|
|||||||
public bool AllowLeadIn { get; set; } = true;
|
public bool AllowLeadIn { get; set; } = true;
|
||||||
public bool AllowResults { get; set; } = true;
|
public bool AllowResults { get; set; } = true;
|
||||||
|
|
||||||
protected override bool AllowBackButton => false;
|
|
||||||
|
|
||||||
private Bindable<bool> mouseWheelDisabled;
|
private Bindable<bool> mouseWheelDisabled;
|
||||||
private Bindable<double> userAudioOffset;
|
private Bindable<double> userAudioOffset;
|
||||||
|
|
||||||
|
@ -55,8 +55,7 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load([CanBeNull] Bindable<RulesetInfo> parentRuleset)
|
private void load([CanBeNull] Bindable<RulesetInfo> parentRuleset)
|
||||||
{
|
{
|
||||||
if (parentRuleset != null)
|
ruleset.BindTo(parentRuleset);
|
||||||
ruleset.BindTo(parentRuleset);
|
|
||||||
ruleset.ValueChanged += _ => updateDisplay();
|
ruleset.ValueChanged += _ => updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ namespace osu.Game.Screens.Select
|
|||||||
private readonly TabControl<GroupMode> groupTabs;
|
private readonly TabControl<GroupMode> groupTabs;
|
||||||
|
|
||||||
private SortMode sort = SortMode.Title;
|
private SortMode sort = SortMode.Title;
|
||||||
|
|
||||||
public SortMode Sort
|
public SortMode Sort
|
||||||
{
|
{
|
||||||
get { return sort; }
|
get { return sort; }
|
||||||
@ -43,6 +44,7 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
|
|
||||||
private GroupMode group = GroupMode.All;
|
private GroupMode group = GroupMode.All;
|
||||||
|
|
||||||
public GroupMode Group
|
public GroupMode Group
|
||||||
{
|
{
|
||||||
get { return group; }
|
get { return group; }
|
||||||
@ -69,7 +71,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private readonly SearchTextBox searchTextBox;
|
private readonly SearchTextBox searchTextBox;
|
||||||
|
|
||||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos);
|
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) =>
|
||||||
|
base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos);
|
||||||
|
|
||||||
public FilterControl()
|
public FilterControl()
|
||||||
{
|
{
|
||||||
@ -177,8 +180,7 @@ namespace osu.Game.Screens.Select
|
|||||||
showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps);
|
showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps);
|
||||||
showConverted.ValueChanged += val => updateCriteria();
|
showConverted.ValueChanged += val => updateCriteria();
|
||||||
|
|
||||||
if (parentRuleset != null)
|
ruleset.BindTo(parentRuleset);
|
||||||
ruleset.BindTo(parentRuleset);
|
|
||||||
ruleset.BindValueChanged(val => updateCriteria(), true);
|
ruleset.BindValueChanged(val => updateCriteria(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,8 @@ namespace osu.Game.Screens.Select
|
|||||||
private readonly Box box;
|
private readonly Box box;
|
||||||
private readonly Box light;
|
private readonly Box light;
|
||||||
|
|
||||||
|
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => box.ReceiveMouseInputAt(screenSpacePos);
|
||||||
|
|
||||||
public FooterButton()
|
public FooterButton()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -46,7 +46,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
public void UpdateRank(ScoreRank newRank)
|
public void UpdateRank(ScoreRank newRank)
|
||||||
{
|
{
|
||||||
Rank = newRank;
|
Rank = newRank;
|
||||||
updateTexture();
|
|
||||||
|
if (IsLoaded)
|
||||||
|
updateTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,10 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
|
|
||||||
private ScheduledDelegate showScoresDelegate;
|
private ScheduledDelegate showScoresDelegate;
|
||||||
|
|
||||||
|
private bool scoresLoadedOnce;
|
||||||
|
|
||||||
private IEnumerable<Score> scores;
|
private IEnumerable<Score> scores;
|
||||||
|
|
||||||
public IEnumerable<Score> Scores
|
public IEnumerable<Score> Scores
|
||||||
{
|
{
|
||||||
get { return scores; }
|
get { return scores; }
|
||||||
@ -48,6 +51,8 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
{
|
{
|
||||||
scores = value;
|
scores = value;
|
||||||
|
|
||||||
|
scoresLoadedOnce = true;
|
||||||
|
|
||||||
scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire();
|
scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire();
|
||||||
scrollFlow = null;
|
scrollFlow = null;
|
||||||
|
|
||||||
@ -196,9 +201,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
{
|
{
|
||||||
this.api = api;
|
this.api = api;
|
||||||
|
|
||||||
if (parentRuleset != null)
|
ruleset.BindTo(parentRuleset);
|
||||||
ruleset.BindTo(parentRuleset);
|
|
||||||
|
|
||||||
ruleset.ValueChanged += _ => updateScores();
|
ruleset.ValueChanged += _ => updateScores();
|
||||||
|
|
||||||
if (api != null)
|
if (api != null)
|
||||||
@ -227,6 +230,10 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
|
|
||||||
private void updateScores()
|
private void updateScores()
|
||||||
{
|
{
|
||||||
|
// don't display any scores or placeholder until the first Scores_Set has been called.
|
||||||
|
// this avoids scope changes flickering a "no scores" placeholder before initialisation of song select is finished.
|
||||||
|
if (!scoresLoadedOnce) return;
|
||||||
|
|
||||||
getScoresRequest?.Cancel();
|
getScoresRequest?.Cancel();
|
||||||
getScoresRequest = null;
|
getScoresRequest = null;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Threading;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
@ -67,6 +68,7 @@ namespace osu.Game.Screens.Select
|
|||||||
protected new readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
protected new readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||||
|
|
||||||
@ -136,7 +138,11 @@ namespace osu.Game.Screens.Select
|
|||||||
Height = filter_height,
|
Height = filter_height,
|
||||||
FilterChanged = c => Carousel.Filter(c),
|
FilterChanged = c => Carousel.Filter(c),
|
||||||
Background = { Width = 2 },
|
Background = { Width = 2 },
|
||||||
Exit = Exit,
|
Exit = () =>
|
||||||
|
{
|
||||||
|
if (IsCurrentScreen)
|
||||||
|
Exit();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -229,6 +235,10 @@ namespace osu.Game.Screens.Select
|
|||||||
/// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param>
|
/// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param>
|
||||||
public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true)
|
public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true)
|
||||||
{
|
{
|
||||||
|
// avoid attempting to continue before a selection has been obtained.
|
||||||
|
// this could happen via a user interaction while the carousel is still in a loading state.
|
||||||
|
if (Carousel.SelectedBeatmap == null) return;
|
||||||
|
|
||||||
// if we have a pending filter operation, we want to run it now.
|
// if we have a pending filter operation, we want to run it now.
|
||||||
// it could change selection (ie. if the ruleset has been changed).
|
// it could change selection (ie. if the ruleset has been changed).
|
||||||
Carousel.FlushPendingFilterOperations();
|
Carousel.FlushPendingFilterOperations();
|
||||||
@ -464,7 +474,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private void carouselBeatmapsLoaded()
|
private void carouselBeatmapsLoaded()
|
||||||
{
|
{
|
||||||
if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false))
|
if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false
|
||||||
|
&& Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom())
|
if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom())
|
||||||
@ -481,16 +492,26 @@ namespace osu.Game.Screens.Select
|
|||||||
dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap));
|
dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (!IsCurrentScreen) return false;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.Select:
|
||||||
|
FinaliseSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnPressed(action);
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Repeat) return false;
|
if (args.Repeat) return false;
|
||||||
|
|
||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.KeypadEnter:
|
|
||||||
case Key.Enter:
|
|
||||||
FinaliseSelection();
|
|
||||||
return true;
|
|
||||||
case Key.Delete:
|
case Key.Delete:
|
||||||
if (state.Keyboard.ShiftPressed)
|
if (state.Keyboard.ShiftPressed)
|
||||||
{
|
{
|
||||||
|
@ -44,19 +44,17 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
private SampleChannel loadChannel(SampleInfo info, Func<string, SampleChannel> getSampleFunction)
|
private SampleChannel loadChannel(SampleInfo info, Func<string, SampleChannel> getSampleFunction)
|
||||||
{
|
{
|
||||||
SampleChannel ch = null;
|
foreach (var lookup in info.LookupNames)
|
||||||
|
{
|
||||||
|
var ch = getSampleFunction($"Gameplay/{lookup}");
|
||||||
|
if (ch == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (info.Namespace != null)
|
|
||||||
ch = getSampleFunction($"Gameplay/{info.Namespace}/{info.Bank}-{info.Name}");
|
|
||||||
|
|
||||||
// try without namespace as a fallback.
|
|
||||||
if (ch == null)
|
|
||||||
ch = getSampleFunction($"Gameplay/{info.Bank}-{info.Name}");
|
|
||||||
|
|
||||||
if (ch != null)
|
|
||||||
ch.Volume.Value = info.Volume / 100.0;
|
ch.Volume.Value = info.Volume / 100.0;
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
return ch;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
protected abstract string ResourceAssembly { get; }
|
protected abstract string ResourceAssembly { get; }
|
||||||
|
|
||||||
|
protected IBeatmapConverter Converter { get; private set; }
|
||||||
|
|
||||||
protected void Test(string name)
|
protected void Test(string name)
|
||||||
{
|
{
|
||||||
var ourResult = convert(name);
|
var ourResult = convert(name);
|
||||||
@ -41,14 +43,22 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
Assert.Fail($"A conversion did not generate any hitobjects, but should have, for hitobject at time: {expectedResult.Mappings[mappingCounter].StartTime}\n");
|
Assert.Fail($"A conversion did not generate any hitobjects, but should have, for hitobject at time: {expectedResult.Mappings[mappingCounter].StartTime}\n");
|
||||||
else if (mappingCounter >= expectedResult.Mappings.Count)
|
else if (mappingCounter >= expectedResult.Mappings.Count)
|
||||||
Assert.Fail($"A conversion generated hitobjects, but should not have, for hitobject at time: {ourResult.Mappings[mappingCounter].StartTime}\n");
|
Assert.Fail($"A conversion generated hitobjects, but should not have, for hitobject at time: {ourResult.Mappings[mappingCounter].StartTime}\n");
|
||||||
|
else if (!expectedResult.Mappings[mappingCounter].Equals(ourResult.Mappings[mappingCounter]))
|
||||||
|
{
|
||||||
|
var expectedMapping = expectedResult.Mappings[mappingCounter];
|
||||||
|
var ourMapping = ourResult.Mappings[mappingCounter];
|
||||||
|
|
||||||
|
Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n"
|
||||||
|
+ $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n"
|
||||||
|
+ $"Received: {JsonConvert.SerializeObject(ourMapping)}\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var counter = mappingCounter;
|
var ourMapping = ourResult.Mappings[mappingCounter];
|
||||||
|
var expectedMapping = expectedResult.Mappings[mappingCounter];
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
var ourMapping = ourResult.Mappings[counter];
|
|
||||||
var expectedMapping = expectedResult.Mappings[counter];
|
|
||||||
|
|
||||||
int objectCounter = 0;
|
int objectCounter = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -60,10 +70,6 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
else if (objectCounter >= expectedMapping.Objects.Count)
|
else if (objectCounter >= expectedMapping.Objects.Count)
|
||||||
Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n"
|
Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n"
|
||||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
|
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
|
||||||
else if (!expectedMapping.Equals(ourMapping))
|
|
||||||
Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n"
|
|
||||||
+ $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n"
|
|
||||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping)}\n");
|
|
||||||
else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter]))
|
else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter]))
|
||||||
{
|
{
|
||||||
Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n"
|
Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n"
|
||||||
@ -88,10 +94,11 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
var rulesetInstance = CreateRuleset();
|
var rulesetInstance = CreateRuleset();
|
||||||
beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo();
|
beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo();
|
||||||
|
|
||||||
var result = new ConvertResult();
|
Converter = rulesetInstance.CreateBeatmapConverter(beatmap);
|
||||||
var converter = rulesetInstance.CreateBeatmapConverter(beatmap);
|
|
||||||
|
|
||||||
converter.ObjectConverted += (orig, converted) =>
|
var result = new ConvertResult();
|
||||||
|
|
||||||
|
Converter.ObjectConverted += (orig, converted) =>
|
||||||
{
|
{
|
||||||
converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty));
|
converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty));
|
||||||
|
|
||||||
@ -103,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
result.Mappings.Add(mapping);
|
result.Mappings.Add(mapping);
|
||||||
};
|
};
|
||||||
|
|
||||||
IBeatmap convertedBeatmap = converter.Convert();
|
IBeatmap convertedBeatmap = Converter.Convert();
|
||||||
rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess();
|
rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
@ -13,6 +16,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap());
|
private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap());
|
||||||
protected BindableBeatmap Beatmap => beatmap;
|
protected BindableBeatmap Beatmap => beatmap;
|
||||||
|
|
||||||
|
protected readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
protected DependencyContainer Dependencies { get; private set; }
|
protected DependencyContainer Dependencies { get; private set; }
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
@ -22,13 +27,18 @@ namespace osu.Game.Tests.Visual
|
|||||||
Dependencies.CacheAs<BindableBeatmap>(beatmap);
|
Dependencies.CacheAs<BindableBeatmap>(beatmap);
|
||||||
Dependencies.CacheAs<IBindableBeatmap>(beatmap);
|
Dependencies.CacheAs<IBindableBeatmap>(beatmap);
|
||||||
|
|
||||||
|
Dependencies.CacheAs(Ruleset);
|
||||||
|
Dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset);
|
||||||
|
|
||||||
return Dependencies;
|
return Dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audioManager)
|
private void load(AudioManager audioManager, RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
beatmap.SetAudioManager(audioManager);
|
beatmap.SetAudioManager(audioManager);
|
||||||
|
|
||||||
|
Ruleset.Value = rulesets.AvailableRulesets.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -86,7 +86,11 @@ namespace osu.Game.Tests.Visual
|
|||||||
private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>();
|
private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>();
|
||||||
private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>();
|
private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>();
|
||||||
|
|
||||||
private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance());
|
private Player loadPlayerFor(RulesetInfo ri)
|
||||||
|
{
|
||||||
|
Ruleset.Value = ri;
|
||||||
|
return loadPlayerFor(ri.CreateInstance());
|
||||||
|
}
|
||||||
|
|
||||||
private Player loadPlayerFor(Ruleset r)
|
private Player loadPlayerFor(Ruleset r)
|
||||||
{
|
{
|
||||||
|
@ -42,7 +42,9 @@ namespace osu.Game.Users
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
country = value;
|
country = value;
|
||||||
sprite.Texture = getFlagTexture();
|
|
||||||
|
if (IsLoaded)
|
||||||
|
sprite.Texture = getFlagTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,9 +23,6 @@ namespace osu.Game.Users
|
|||||||
|
|
||||||
public Bindable<UserStatus> Status = new Bindable<UserStatus>();
|
public Bindable<UserStatus> Status = new Bindable<UserStatus>();
|
||||||
|
|
||||||
[JsonProperty(@"age")]
|
|
||||||
public int? Age;
|
|
||||||
|
|
||||||
//public Team Team;
|
//public Team Team;
|
||||||
|
|
||||||
[JsonProperty(@"profile_colour")]
|
[JsonProperty(@"profile_colour")]
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2018.626.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2018.709.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.17.1" />
|
<PackageReference Include="SharpCompress" Version="0.17.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user