mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 12:33:01 +08:00
Merge branch 'master' into generic-update-notifier
This commit is contained in:
commit
36552478e8
26
README.md
26
README.md
@ -1,18 +1,32 @@
|
||||
# osu! [![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu) [![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu) [![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy)
|
||||
|
||||
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era!
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
- 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
|
||||
- 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`)
|
||||
# Building and running
|
||||
|
||||
If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled (download and run the install executable for your platform).
|
||||
|
||||
Clone the repository including submodules
|
||||
|
||||
`git clone --recurse-submodules https://github.com/ppy/osu`
|
||||
|
||||
Build and run
|
||||
|
||||
- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
|
||||
- From command line using `dotnet run --project osu.Desktop --framework netcoreapp2.1`
|
||||
|
||||
The above methods should automatically do so, but if you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`).
|
||||
|
||||
# Contributing
|
||||
|
||||
|
@ -5,6 +5,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@ -13,11 +15,10 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||
|
||||
[NonParallelizable]
|
||||
[TestCase("basic")]
|
||||
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();
|
||||
}
|
||||
|
||||
public class ManiaConvertMapping : ConvertMapping<ConvertValue>, IEquatable<ManiaConvertMapping>
|
||||
{
|
||||
public uint RandomW;
|
||||
public uint RandomX;
|
||||
public uint RandomY;
|
||||
public uint RandomZ;
|
||||
|
||||
public ManiaConvertMapping()
|
||||
{
|
||||
}
|
||||
|
||||
public ManiaConvertMapping(IBeatmapConverter converter)
|
||||
{
|
||||
var maniaConverter = (ManiaBeatmapConverter)converter;
|
||||
RandomW = maniaConverter.Random.W;
|
||||
RandomX = maniaConverter.Random.X;
|
||||
RandomY = maniaConverter.Random.Y;
|
||||
RandomZ = maniaConverter.Random.Z;
|
||||
}
|
||||
|
||||
public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
|
||||
public override bool Equals(ConvertMapping<ConvertValue> other) => base.Equals(other) && Equals(other as ManiaConvertMapping);
|
||||
}
|
||||
|
||||
public struct ConvertValue : IEquatable<ConvertValue>
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -5,6 +5,7 @@ using osu.Game.Rulesets.Mania.Objects;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@ -28,8 +29,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
public int TargetColumns;
|
||||
public readonly bool IsForCurrentRuleset;
|
||||
|
||||
// Internal for testing purposes
|
||||
internal FastRandom Random { get; private set; }
|
||||
|
||||
private Pattern lastPattern = new Pattern();
|
||||
private FastRandom random;
|
||||
|
||||
private ManiaBeatmap beatmap;
|
||||
|
||||
@ -62,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
||||
|
||||
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
|
||||
random = new FastRandom(seed);
|
||||
Random = new FastRandom(seed);
|
||||
|
||||
return base.ConvertBeatmap(original);
|
||||
}
|
||||
@ -100,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
|
||||
private double lastTime;
|
||||
private Vector2 lastPosition;
|
||||
private PatternType lastStair;
|
||||
private PatternType lastStair = PatternType.Stair;
|
||||
private void recordNote(double time, Vector2 position)
|
||||
{
|
||||
lastTime = time;
|
||||
@ -115,12 +118,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// <returns>The hit objects generated.</returns>
|
||||
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap)
|
||||
{
|
||||
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
|
||||
var generator = new SpecificBeatmapPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap);
|
||||
|
||||
Pattern newPattern = generator.Generate();
|
||||
lastPattern = newPattern;
|
||||
foreach (var newPattern in generator.Generate())
|
||||
{
|
||||
lastPattern = newPattern;
|
||||
|
||||
return newPattern.HitObjects;
|
||||
foreach (var obj in newPattern.HitObjects)
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -138,27 +144,44 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
Patterns.PatternGenerator conversion = 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)
|
||||
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)
|
||||
{
|
||||
computeDensity(original.StartTime);
|
||||
|
||||
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
|
||||
conversion = new HitObjectPatternGenerator(Random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
|
||||
|
||||
recordNote(original.StartTime, positionData.Position);
|
||||
}
|
||||
|
||||
if (conversion == null)
|
||||
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;
|
||||
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
|
||||
foreach (var obj in newPattern.HitObjects)
|
||||
yield return obj;
|
||||
|
||||
return newPattern.HitObjects;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 positionData = HitObject as IHasXPosition;
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
@ -24,8 +25,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
/// </summary>
|
||||
private const float osu_base_scoring_distance = 100;
|
||||
|
||||
private readonly double endTime;
|
||||
private readonly double segmentDuration;
|
||||
public readonly double EndTime;
|
||||
public readonly double SegmentDuration;
|
||||
|
||||
private readonly int spanCount;
|
||||
|
||||
private PatternType convertType;
|
||||
@ -52,53 +54,81 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
// The duration of the osu! hit object
|
||||
double osuDuration = distance / osuVelocity;
|
||||
|
||||
endTime = hitObject.StartTime + osuDuration;
|
||||
segmentDuration = (endTime - HitObject.StartTime) / spanCount;
|
||||
EndTime = hitObject.StartTime + osuDuration;
|
||||
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
|
||||
}
|
||||
|
||||
public override 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)
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
addToPattern(pattern, 0, HitObject.StartTime, endTime);
|
||||
addToPattern(pattern, 0, HitObject.StartTime, EndTime);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (spanCount > 1)
|
||||
{
|
||||
if (segmentDuration <= 90)
|
||||
if (SegmentDuration <= 90)
|
||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||
|
||||
if (segmentDuration <= 120)
|
||||
if (SegmentDuration <= 120)
|
||||
{
|
||||
convertType |= PatternType.ForceNotStack;
|
||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
||||
}
|
||||
|
||||
if (segmentDuration <= 160)
|
||||
if (SegmentDuration <= 160)
|
||||
return generateStair(HitObject.StartTime);
|
||||
|
||||
if (segmentDuration <= 200 && ConversionDifficulty > 3)
|
||||
if (SegmentDuration <= 200 && ConversionDifficulty > 3)
|
||||
return generateRandomMultipleNotes(HitObject.StartTime);
|
||||
|
||||
double duration = endTime - HitObject.StartTime;
|
||||
double duration = EndTime - HitObject.StartTime;
|
||||
if (duration >= 4000)
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
||||
|
||||
if (segmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
||||
if (SegmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
||||
return generateTiledHoldNotes(HitObject.StartTime);
|
||||
|
||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||
}
|
||||
|
||||
if (segmentDuration <= 110)
|
||||
if (SegmentDuration <= 110)
|
||||
{
|
||||
if (PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
convertType |= PatternType.ForceNotStack;
|
||||
else
|
||||
convertType &= ~PatternType.ForceNotStack;
|
||||
return generateRandomNotes(HitObject.StartTime, segmentDuration < 80 ? 1 : 2);
|
||||
return generateRandomNotes(HitObject.StartTime, SegmentDuration < 80 ? 1 : 2);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 6.5)
|
||||
@ -148,7 +178,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
}
|
||||
|
||||
// This is can't be combined with the above loop due to RNG
|
||||
@ -156,7 +186,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@ -193,7 +223,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
|
||||
lastColumn = nextColumn;
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@ -223,7 +253,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
for (int i = 0; i <= spanCount; i++)
|
||||
{
|
||||
addToPattern(pattern, column, startTime, startTime);
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
|
||||
// Check if we're at the borders of the stage, and invert the pattern if so
|
||||
if (increasing)
|
||||
@ -284,7 +314,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@ -372,8 +402,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
|
||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
||||
startTime += segmentDuration;
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@ -402,7 +432,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
}
|
||||
|
||||
// Create the hold note
|
||||
addToPattern(pattern, holdColumn, startTime, endTime);
|
||||
addToPattern(pattern, holdColumn, startTime, EndTime);
|
||||
|
||||
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
int noteCount;
|
||||
@ -434,7 +464,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
pattern.Add(rowPattern);
|
||||
rowPattern.Clear();
|
||||
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@ -452,7 +482,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
if (curveData == null)
|
||||
return HitObject.Samples;
|
||||
|
||||
double segmentTime = (endTime - HitObject.StartTime) / spanCount;
|
||||
double segmentTime = (EndTime - HitObject.StartTime) / spanCount;
|
||||
|
||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||
return curveData.RepeatSamples[index];
|
||||
|
@ -24,7 +24,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
endTime = endtimeData?.EndTime ?? 0;
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
public override IEnumerable<Pattern> Generate()
|
||||
{
|
||||
yield return generate();
|
||||
}
|
||||
|
||||
private Pattern generate()
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
@ -82,127 +83,133 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
|
||||
convertType |= PatternType.Mirror;
|
||||
else
|
||||
else if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP))
|
||||
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();
|
||||
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)
|
||||
if (TotalColumns == 1)
|
||||
{
|
||||
targetColumn = RandomStart;
|
||||
StairType = PatternType.ReverseStair;
|
||||
addToPattern(pattern, 0);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
|
||||
|
||||
if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
|
||||
var pattern = new Pattern();
|
||||
|
||||
int targetColumn = lastColumn - 1;
|
||||
if (targetColumn == RandomStart - 1)
|
||||
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
targetColumn = TotalColumns - 1;
|
||||
StairType = PatternType.Stair;
|
||||
// Generate a new pattern by copying the last hit objects in reverse-column order
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
if (PreviousPattern.ColumnHasObject(i))
|
||||
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
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)
|
||||
int column = RandomStart + TotalColumns - lastColumn - 1;
|
||||
addToPattern(pattern, column);
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) > 0)
|
||||
return generateRandomNotes(1);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
// Generate a new pattern by placing on the already filled columns
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
if (PreviousPattern.ColumnHasObject(i))
|
||||
addToPattern(pattern, i);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (PreviousPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
if ((convertType & PatternType.Stair) > 0)
|
||||
{
|
||||
// Generate a new pattern by placing on the next column, cycling back to the start if there is no "next"
|
||||
int targetColumn = lastColumn + 1;
|
||||
if (targetColumn == TotalColumns)
|
||||
targetColumn = RandomStart;
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.ReverseStair) > 0)
|
||||
{
|
||||
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
|
||||
int targetColumn = lastColumn - 1;
|
||||
if (targetColumn == RandomStart - 1)
|
||||
targetColumn = TotalColumns - 1;
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) > 0)
|
||||
return pattern = generateRandomNotes(1);
|
||||
|
||||
if ((convertType & PatternType.Mirror) > 0)
|
||||
{
|
||||
if (ConversionDifficulty > 6.5)
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
|
||||
if (ConversionDifficulty > 4)
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0.17, 0);
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0, 0);
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.Mirror) > 0)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
return generateRandomPattern(0.78, 0.42, 0, 0);
|
||||
return generateRandomPattern(1, 0.62, 0, 0);
|
||||
foreach (var obj in pattern.HitObjects)
|
||||
{
|
||||
if ((convertType & PatternType.Stair) > 0 && obj.Column == TotalColumns - 1)
|
||||
StairType = PatternType.ReverseStair;
|
||||
if ((convertType & PatternType.ReverseStair) > 0 && obj.Column == RandomStart)
|
||||
StairType = PatternType.Stair;
|
||||
}
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 4)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
return generateRandomPattern(0.35, 0.08, 0, 0);
|
||||
return generateRandomPattern(0.52, 0.15, 0, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 2)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
return generateRandomPattern(0.18, 0, 0, 0);
|
||||
return generateRandomPattern(0.45, 0, 0, 0);
|
||||
}
|
||||
|
||||
return generateRandomPattern(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -103,17 +103,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault();
|
||||
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault();
|
||||
|
||||
double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0);
|
||||
drainTime -= OriginalBeatmap.TotalBreakTime;
|
||||
// Drain time in seconds
|
||||
int drainTime = (int)(((lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0) - OriginalBeatmap.TotalBreakTime) / 1000);
|
||||
|
||||
if (drainTime == 0)
|
||||
drainTime = 10000000;
|
||||
|
||||
// We need this in seconds
|
||||
drainTime /= 1000;
|
||||
drainTime = 10000;
|
||||
|
||||
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);
|
||||
|
||||
return conversionDifficulty.Value;
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
@ -42,9 +43,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
|
||||
public abstract Pattern Generate();
|
||||
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
||||
public abstract IEnumerable<Pattern> Generate();
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,15 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
private const uint y = 842502087;
|
||||
private const uint z = 3579807591;
|
||||
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)
|
||||
{
|
||||
_x = (uint)seed;
|
||||
X = (uint)seed;
|
||||
}
|
||||
|
||||
public FastRandom()
|
||||
@ -33,11 +37,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
/// <returns>The random value.</returns>
|
||||
public uint NextUInt()
|
||||
{
|
||||
uint t = _x ^ _x << 11;
|
||||
_x = _y;
|
||||
_y = _z;
|
||||
_z = _w;
|
||||
return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
|
||||
uint t = X ^ X << 11;
|
||||
X = Y;
|
||||
Y = Z;
|
||||
Z = W;
|
||||
return W = W ^ W >> 19 ^ t ^ t >> 8;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,103 +1,132 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 500,
|
||||
"Objects": [{
|
||||
"StartTime": 500,
|
||||
"EndTime": 2500,
|
||||
"Column": 0
|
||||
},
|
||||
{
|
||||
"StartTime": 1500,
|
||||
"EndTime": 2500,
|
||||
"Column": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"StartTime": 3000,
|
||||
"Objects": [{
|
||||
"StartTime": 3000,
|
||||
"EndTime": 4000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 4500,
|
||||
"Objects": [{
|
||||
"StartTime": 4500,
|
||||
"EndTime": 5500,
|
||||
"Column": 4
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 6000,
|
||||
"Objects": [{
|
||||
"StartTime": 6000,
|
||||
"EndTime": 6500,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 7000,
|
||||
"Objects": [{
|
||||
"StartTime": 7000,
|
||||
"EndTime": 8000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 8500,
|
||||
"Objects": [{
|
||||
"StartTime": 8500,
|
||||
"EndTime": 11000,
|
||||
"Column": 0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 11500,
|
||||
"Objects": [{
|
||||
"StartTime": 11500,
|
||||
"EndTime": 12000,
|
||||
"Column": 1
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 12500,
|
||||
"Objects": [{
|
||||
"StartTime": 12500,
|
||||
"EndTime": 16500,
|
||||
"Column": 4
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 17000,
|
||||
"Objects": [{
|
||||
"StartTime": 17000,
|
||||
"EndTime": 18000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 18500,
|
||||
"Objects": [{
|
||||
"StartTime": 18500,
|
||||
"EndTime": 19450,
|
||||
"Column": 0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 19875,
|
||||
"Objects": [{
|
||||
"StartTime": 19875,
|
||||
"EndTime": 23875,
|
||||
"Column": 1
|
||||
},
|
||||
{
|
||||
"StartTime": 19875,
|
||||
"EndTime": 23875,
|
||||
"Column": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"RandomW": 2659373485,
|
||||
"RandomX": 3579807591,
|
||||
"RandomY": 273326509,
|
||||
"RandomZ": 272969173,
|
||||
"StartTime": 500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 500.0,
|
||||
"EndTime": 2500.0,
|
||||
"Column": 0
|
||||
}, {
|
||||
"StartTime": 1500.0,
|
||||
"EndTime": 2500.0,
|
||||
"Column": 1
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 3083803045,
|
||||
"RandomX": 273326509,
|
||||
"RandomY": 272969173,
|
||||
"RandomZ": 2659373485,
|
||||
"StartTime": 3000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 3000.0,
|
||||
"EndTime": 4000.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 4073554232,
|
||||
"RandomX": 272969173,
|
||||
"RandomY": 2659373485,
|
||||
"RandomZ": 3083803045,
|
||||
"StartTime": 4500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 4500.0,
|
||||
"EndTime": 5500.0,
|
||||
"Column": 4
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 3420401969,
|
||||
"RandomX": 2659373485,
|
||||
"RandomY": 3083803045,
|
||||
"RandomZ": 4073554232,
|
||||
"StartTime": 6000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 6000.0,
|
||||
"EndTime": 6500.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 1129881182,
|
||||
"RandomX": 3083803045,
|
||||
"RandomY": 4073554232,
|
||||
"RandomZ": 3420401969,
|
||||
"StartTime": 7000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 7000.0,
|
||||
"EndTime": 8000.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 315568458,
|
||||
"RandomX": 3420401969,
|
||||
"RandomY": 1129881182,
|
||||
"RandomZ": 2358617505,
|
||||
"StartTime": 8500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 8500.0,
|
||||
"EndTime": 11000.0,
|
||||
"Column": 0
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 548134043,
|
||||
"RandomX": 1129881182,
|
||||
"RandomY": 2358617505,
|
||||
"RandomZ": 315568458,
|
||||
"StartTime": 11500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 11500.0,
|
||||
"EndTime": 12000.0,
|
||||
"Column": 1
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 3979422122,
|
||||
"RandomX": 548134043,
|
||||
"RandomY": 2810584254,
|
||||
"RandomZ": 2250186050,
|
||||
"StartTime": 12500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 12500.0,
|
||||
"EndTime": 16500.0,
|
||||
"Column": 4
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 2466283411,
|
||||
"RandomX": 2810584254,
|
||||
"RandomY": 2250186050,
|
||||
"RandomZ": 3979422122,
|
||||
"StartTime": 17000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 17000.0,
|
||||
"EndTime": 18000.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 83157665,
|
||||
"RandomX": 2250186050,
|
||||
"RandomY": 3979422122,
|
||||
"RandomZ": 2466283411,
|
||||
"StartTime": 18500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 18500.0,
|
||||
"EndTime": 19450.0,
|
||||
"Column": 0
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 2383087700,
|
||||
"RandomX": 83157665,
|
||||
"RandomY": 2055150192,
|
||||
"RandomZ": 510071020,
|
||||
"StartTime": 19875.0,
|
||||
"Objects": [{
|
||||
"StartTime": 19875.0,
|
||||
"EndTime": 23875.0,
|
||||
"Column": 1
|
||||
}, {
|
||||
"StartTime": 19875.0,
|
||||
"EndTime": 23875.0,
|
||||
"Column": 0
|
||||
}]
|
||||
}]
|
||||
}
|
@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
private class TestOnScreenDisplay : OnScreenDisplay
|
||||
{
|
||||
protected override void Display(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
||||
protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ namespace osu.Game.Tests.Visual
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ToolbarButton),
|
||||
typeof(ToolbarModeSelector),
|
||||
typeof(ToolbarModeButton),
|
||||
typeof(ToolbarRulesetSelector),
|
||||
typeof(ToolbarRulesetButton),
|
||||
typeof(ToolbarNotificationButton),
|
||||
};
|
||||
|
||||
|
@ -53,7 +53,6 @@ namespace osu.Game.Tests.Visual
|
||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
|
||||
JoinDate = DateTimeOffset.Now.AddDays(-1),
|
||||
LastVisit = DateTimeOffset.Now,
|
||||
Age = 1,
|
||||
ProfileOrder = new[] { "me" },
|
||||
Statistics = new UserStatistics
|
||||
{
|
||||
|
@ -339,6 +339,8 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var beatmapInfos = new List<BeatmapInfo>();
|
||||
|
||||
bool invalidateOnlineIDs = false;
|
||||
|
||||
foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu")))
|
||||
{
|
||||
using (var raw = reader.GetStream(name))
|
||||
@ -355,9 +357,18 @@ namespace osu.Game.Beatmaps
|
||||
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
||||
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
|
||||
|
||||
// check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence.
|
||||
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null)
|
||||
beatmap.BeatmapInfo.OnlineBeatmapID = null;
|
||||
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue)
|
||||
{
|
||||
var ourId = beatmap.BeatmapInfo.OnlineBeatmapID;
|
||||
|
||||
// check that no existing beatmap in database exists that is imported with the same online beatmap ID. if so, give it precedence.
|
||||
if (QueryBeatmap(b => b.OnlineBeatmapID.Value == ourId) != null)
|
||||
beatmap.BeatmapInfo.OnlineBeatmapID = null;
|
||||
|
||||
// check that no other beatmap in this imported set has a conflicting online beatmap ID. If so, presume *all* are incorrect.
|
||||
if (beatmapInfos.Any(b => b.OnlineBeatmapID == ourId))
|
||||
invalidateOnlineIDs = true;
|
||||
}
|
||||
|
||||
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
|
||||
|
||||
@ -375,6 +386,9 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidateOnlineIDs)
|
||||
beatmapInfos.ForEach(b => b.OnlineBeatmapID = null);
|
||||
|
||||
return beatmapInfos;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Graphics.Containers
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
public virtual bool OnPressed(GlobalAction action)
|
||||
{
|
||||
if (action == GlobalAction.Back)
|
||||
{
|
||||
|
@ -22,7 +22,9 @@ namespace osu.Game.Graphics.Cursor
|
||||
private readonly IBindable<bool> screenshotCursorVisibility = new Bindable<bool>(true);
|
||||
public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent;
|
||||
|
||||
protected override Drawable CreateCursor() => new Cursor();
|
||||
protected override Drawable CreateCursor() => activeCursor = new Cursor();
|
||||
|
||||
private Cursor activeCursor;
|
||||
|
||||
private Bindable<bool> cursorRotate;
|
||||
private DragRotationState dragRotationState;
|
||||
@ -54,12 +56,12 @@ namespace osu.Game.Graphics.Cursor
|
||||
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
|
||||
|
||||
// Always rotate in the direction of least distance
|
||||
float diff = (degrees - ActiveCursor.Rotation) % 360;
|
||||
float diff = (degrees - activeCursor.Rotation) % 360;
|
||||
if (diff < -180) diff += 360;
|
||||
if (diff > 180) diff -= 360;
|
||||
degrees = ActiveCursor.Rotation + diff;
|
||||
degrees = activeCursor.Rotation + diff;
|
||||
|
||||
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
|
||||
activeCursor.RotateTo(degrees, 600, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,11 +70,15 @@ namespace osu.Game.Graphics.Cursor
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
ActiveCursor.Scale = new Vector2(1);
|
||||
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
|
||||
// only trigger animation for main mouse buttons
|
||||
if (args.Button <= MouseButton.Right)
|
||||
{
|
||||
activeCursor.Scale = new Vector2(1);
|
||||
activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
|
||||
|
||||
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
|
||||
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
|
||||
activeCursor.AdditiveLayer.Alpha = 0;
|
||||
activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
|
||||
}
|
||||
|
||||
if (args.Button == MouseButton.Left && cursorRotate)
|
||||
{
|
||||
@ -86,36 +92,29 @@ namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
if (!state.Mouse.HasMainButtonPressed)
|
||||
{
|
||||
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
|
||||
activeCursor.AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
|
||||
activeCursor.ScaleTo(1, 500, Easing.OutElastic);
|
||||
}
|
||||
|
||||
if (args.Button == MouseButton.Left)
|
||||
{
|
||||
if (dragRotationState == DragRotationState.Rotating)
|
||||
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
|
||||
activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf);
|
||||
dragRotationState = DragRotationState.NotDragging;
|
||||
}
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
|
||||
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||
activeCursor.FadeTo(1, 250, Easing.OutQuint);
|
||||
activeCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
|
||||
activeCursor.FadeTo(0, 250, Easing.OutQuint);
|
||||
activeCursor.ScaleTo(0.6f, 250, Easing.In);
|
||||
}
|
||||
|
||||
public class Cursor : Container
|
||||
|
@ -39,7 +39,10 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
||||
|
||||
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[]
|
||||
@ -86,7 +89,7 @@ namespace osu.Game.Input.Bindings
|
||||
[Description("Toggle gameplay mouse buttons")]
|
||||
ToggleGameplayMouseButtons,
|
||||
|
||||
[Description("Go back")]
|
||||
[Description("Back")]
|
||||
Back,
|
||||
|
||||
[Description("Increase scroll speed")]
|
||||
@ -94,5 +97,8 @@ namespace osu.Game.Input.Bindings
|
||||
|
||||
[Description("Decrease scroll speed")]
|
||||
DecreaseScrollSpeed,
|
||||
|
||||
[Description("Select")]
|
||||
Select,
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Framework.Graphics.Performance;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Database;
|
||||
@ -30,6 +31,7 @@ using osu.Game.IO;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using OpenTK.Input;
|
||||
using DebugUtils = osu.Game.Utils.DebugUtils;
|
||||
|
||||
namespace osu.Game
|
||||
@ -98,6 +100,8 @@ namespace osu.Game
|
||||
|
||||
private DatabaseContextFactory contextFactory;
|
||||
|
||||
protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@ -267,5 +271,31 @@ namespace osu.Game
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
private class OsuUserInputManager : UserInputManager
|
||||
{
|
||||
protected override MouseButtonEventManager CreateButtonManagerFor(MouseButton button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case MouseButton.Right:
|
||||
return new RightMouseManager(button);
|
||||
}
|
||||
|
||||
return base.CreateButtonManagerFor(button);
|
||||
}
|
||||
|
||||
private class RightMouseManager : MouseButtonEventManager
|
||||
{
|
||||
public RightMouseManager(MouseButton button)
|
||||
: base(button)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers.
|
||||
public override bool EnableClick => false;
|
||||
public override bool ChangeFocusOnClick => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Input.Bindings;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
@ -192,16 +193,22 @@ 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;
|
||||
|
||||
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)
|
||||
|
@ -14,6 +14,8 @@ using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
@ -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>
|
||||
public void BeginTracking(object source, ITrackableConfigManager configManager)
|
||||
{
|
||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||
|
||||
if (trackedConfigManagers.ContainsKey((source, configManager)))
|
||||
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
|
||||
@ -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>
|
||||
public void StopTracking(object source, ITrackableConfigManager configManager)
|
||||
{
|
||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||
|
||||
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
|
||||
throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
|
||||
@ -181,7 +183,7 @@ namespace osu.Game.Overlays
|
||||
if (string.IsNullOrEmpty(textLine3.Text))
|
||||
textLine3.Text = "NO KEY BOUND";
|
||||
|
||||
Display(box);
|
||||
DisplayTemporarily(box);
|
||||
|
||||
int optionCount = 0;
|
||||
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(
|
||||
b => b.FadeIn(500, Easing.OutQuint),
|
||||
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
|
||||
).Then(
|
||||
b => b.FadeOutFromOne(1500, Easing.InQuint),
|
||||
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint)
|
||||
);
|
||||
// avoid starting a new fade-in if one is already active.
|
||||
if (fadeIn == null)
|
||||
{
|
||||
fadeIn = toDisplay.Animate(
|
||||
b => b.FadeIn(500, Easing.OutQuint),
|
||||
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
|
||||
);
|
||||
|
||||
fadeIn.Finally(_ => fadeIn = null);
|
||||
}
|
||||
|
||||
fadeOut?.Cancel();
|
||||
fadeOut = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
toDisplay.Animate(
|
||||
b => b.FadeOutFromOne(1500, Easing.InQuint),
|
||||
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint));
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private class OptionLight : Container
|
||||
|
@ -360,11 +360,6 @@ namespace osu.Game.Overlays.Profile
|
||||
Text = text
|
||||
};
|
||||
|
||||
if (user.Age != null)
|
||||
{
|
||||
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
|
||||
}
|
||||
|
||||
if (user.Country != null)
|
||||
{
|
||||
infoTextLeft.AddText("From ", lightText);
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
Action = () => OnHome?.Invoke()
|
||||
},
|
||||
new ToolbarModeSelector()
|
||||
new ToolbarRulesetSelector()
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
|
@ -7,7 +7,7 @@ using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarModeButton : ToolbarButton
|
||||
public class ToolbarRulesetButton : ToolbarButton
|
||||
{
|
||||
private RulesetInfo ruleset;
|
||||
public RulesetInfo Ruleset
|
@ -16,18 +16,18 @@ using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarModeSelector : Container
|
||||
public class ToolbarRulesetSelector : Container
|
||||
{
|
||||
private const float padding = 10;
|
||||
|
||||
private readonly FillFlowContainer modeButtons;
|
||||
private readonly Drawable modeButtonLine;
|
||||
private ToolbarModeButton activeButton;
|
||||
private ToolbarRulesetButton activeButton;
|
||||
|
||||
private RulesetStore rulesets;
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
public ToolbarModeSelector()
|
||||
public ToolbarRulesetSelector()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
|
||||
@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
this.rulesets = rulesets;
|
||||
foreach (var r in rulesets.AvailableRulesets)
|
||||
{
|
||||
modeButtons.Add(new ToolbarModeButton
|
||||
modeButtons.Add(new ToolbarRulesetButton
|
||||
{
|
||||
Ruleset = r,
|
||||
Action = delegate { ruleset.Value = r; }
|
||||
@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
|
||||
private void rulesetChanged(RulesetInfo ruleset)
|
||||
{
|
||||
foreach (ToolbarModeButton m in modeButtons.Children.Cast<ToolbarModeButton>())
|
||||
foreach (ToolbarRulesetButton m in modeButtons.Children.Cast<ToolbarRulesetButton>())
|
||||
{
|
||||
bool isActive = m.Ruleset.ID == ruleset.ID;
|
||||
m.Active = isActive;
|
@ -11,7 +11,6 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics;
|
||||
@ -139,26 +138,15 @@ namespace osu.Game.Screens.Menu
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.Back:
|
||||
return goBack();
|
||||
case GlobalAction.Select:
|
||||
logo?.TriggerOnClick();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace osu.Game.Screens
|
||||
sampleExit = audio.Sample.Get(@"UI/screen-back");
|
||||
}
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
public virtual bool OnPressed(GlobalAction action)
|
||||
{
|
||||
if (!IsCurrentScreen) return false;
|
||||
|
||||
|
@ -46,7 +46,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
public void UpdateRank(ScoreRank newRank)
|
||||
{
|
||||
Rank = newRank;
|
||||
updateTexture();
|
||||
|
||||
if (IsLoaded)
|
||||
updateTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
@ -67,6 +68,7 @@ namespace osu.Game.Screens.Select
|
||||
protected new readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
||||
@ -136,7 +138,11 @@ namespace osu.Game.Screens.Select
|
||||
Height = filter_height,
|
||||
FilterChanged = c => Carousel.Filter(c),
|
||||
Background = { Width = 2 },
|
||||
Exit = Exit,
|
||||
Exit = () =>
|
||||
{
|
||||
if (IsCurrentScreen)
|
||||
Exit();
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -187,8 +193,6 @@ namespace osu.Game.Screens.Select
|
||||
dependencies.CacheAs(Ruleset);
|
||||
dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset);
|
||||
|
||||
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
|
||||
|
||||
if (Footer != null)
|
||||
{
|
||||
Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
|
||||
@ -216,6 +220,12 @@ namespace osu.Game.Screens.Select
|
||||
Beatmap.BindValueChanged(workingBeatmapChanged);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
|
||||
}
|
||||
|
||||
public void Edit(BeatmapInfo beatmap)
|
||||
{
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
||||
@ -229,6 +239,10 @@ namespace osu.Game.Screens.Select
|
||||
/// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param>
|
||||
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.
|
||||
// it could change selection (ie. if the ruleset has been changed).
|
||||
Carousel.FlushPendingFilterOperations();
|
||||
@ -464,7 +478,8 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
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;
|
||||
|
||||
if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom())
|
||||
@ -481,16 +496,26 @@ namespace osu.Game.Screens.Select
|
||||
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)
|
||||
{
|
||||
if (args.Repeat) return false;
|
||||
|
||||
switch (args.Key)
|
||||
{
|
||||
case Key.KeypadEnter:
|
||||
case Key.Enter:
|
||||
FinaliseSelection();
|
||||
return true;
|
||||
case Key.Delete:
|
||||
if (state.Keyboard.ShiftPressed)
|
||||
{
|
||||
|
@ -25,6 +25,8 @@ namespace osu.Game.Tests.Beatmaps
|
||||
|
||||
protected abstract string ResourceAssembly { get; }
|
||||
|
||||
protected IBeatmapConverter Converter { get; private set; }
|
||||
|
||||
protected void Test(string 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");
|
||||
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");
|
||||
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
|
||||
{
|
||||
var counter = mappingCounter;
|
||||
var ourMapping = ourResult.Mappings[mappingCounter];
|
||||
var expectedMapping = expectedResult.Mappings[mappingCounter];
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
var ourMapping = ourResult.Mappings[counter];
|
||||
var expectedMapping = expectedResult.Mappings[counter];
|
||||
|
||||
int objectCounter = 0;
|
||||
while (true)
|
||||
{
|
||||
@ -60,10 +70,6 @@ namespace osu.Game.Tests.Beatmaps
|
||||
else if (objectCounter >= expectedMapping.Objects.Count)
|
||||
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");
|
||||
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]))
|
||||
{
|
||||
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();
|
||||
beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo();
|
||||
|
||||
var result = new ConvertResult();
|
||||
var converter = rulesetInstance.CreateBeatmapConverter(beatmap);
|
||||
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));
|
||||
|
||||
@ -103,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
result.Mappings.Add(mapping);
|
||||
};
|
||||
|
||||
IBeatmap convertedBeatmap = converter.Convert();
|
||||
IBeatmap convertedBeatmap = Converter.Convert();
|
||||
rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess();
|
||||
|
||||
return result;
|
||||
|
@ -42,7 +42,9 @@ namespace osu.Game.Users
|
||||
return;
|
||||
|
||||
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>();
|
||||
|
||||
[JsonProperty(@"age")]
|
||||
public int? Age;
|
||||
|
||||
//public Team Team;
|
||||
|
||||
[JsonProperty(@"profile_colour")]
|
||||
|
@ -18,7 +18,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.705.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.709.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.17.1" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user