mirror of
https://github.com/ppy/osu.git
synced 2025-03-06 05:53:11 +08:00
Merge branch 'master' into Private_Messages
This commit is contained in:
commit
ce92c8d2eb
@ -28,8 +28,8 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.5" />
|
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Resources">
|
<ItemGroup Label="Resources">
|
||||||
<EmbeddedResource Include="lazer.ico" />
|
<EmbeddedResource Include="lazer.ico" />
|
||||||
|
@ -173,26 +173,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
int usableColumns = TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects;
|
int usableColumns = TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects;
|
||||||
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
int nextColumn = GetRandomColumn();
|
||||||
for (int i = 0; i < Math.Min(usableColumns, noteCount); i++)
|
for (int i = 0; i < Math.Min(usableColumns, noteCount); i++)
|
||||||
{
|
{
|
||||||
// Find available column
|
// Find available column
|
||||||
RunWhile(() => pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn), () =>
|
nextColumn = FindAvailableColumn(nextColumn, pattern, PreviousPattern);
|
||||||
{
|
|
||||||
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
|
||||||
for (int i = 0; i < noteCount - usableColumns; i++)
|
for (int i = 0; i < noteCount - usableColumns; i++)
|
||||||
{
|
{
|
||||||
RunWhile(() => pattern.ColumnHasObject(nextColumn), () =>
|
nextColumn = FindAvailableColumn(nextColumn, pattern);
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
|
|
||||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,23 +209,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
{
|
nextColumn = FindAvailableColumn(nextColumn, PreviousPattern);
|
||||||
RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () =>
|
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int lastColumn = nextColumn;
|
int lastColumn = nextColumn;
|
||||||
for (int i = 0; i < noteCount; i++)
|
for (int i = 0; i < noteCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
nextColumn = FindAvailableColumn(nextColumn, validation: c => c != lastColumn);
|
||||||
RunWhile(() => nextColumn == lastColumn, () =>
|
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
|
|
||||||
lastColumn = nextColumn;
|
lastColumn = nextColumn;
|
||||||
startTime += SegmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
@ -325,7 +307,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (TotalColumns > 2)
|
if (TotalColumns > 2)
|
||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
nextColumn = GetRandomColumn();
|
||||||
startTime += SegmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,20 +386,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
{
|
nextColumn = FindAvailableColumn(nextColumn, PreviousPattern);
|
||||||
RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () =>
|
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < columnRepeat; i++)
|
for (int i = 0; i < columnRepeat; i++)
|
||||||
{
|
{
|
||||||
RunWhile(() => pattern.ColumnHasObject(nextColumn), () =>
|
nextColumn = FindAvailableColumn(nextColumn, pattern);
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
|
|
||||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||||
startTime += SegmentDuration;
|
startTime += SegmentDuration;
|
||||||
}
|
}
|
||||||
@ -442,17 +415,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
{
|
holdColumn = FindAvailableColumn(holdColumn, PreviousPattern);
|
||||||
RunWhile(() => PreviousPattern.ColumnHasObject(holdColumn), () =>
|
|
||||||
{
|
|
||||||
holdColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = GetRandomColumn();
|
||||||
int noteCount;
|
int noteCount;
|
||||||
if (ConversionDifficulty > 6.5)
|
if (ConversionDifficulty > 6.5)
|
||||||
noteCount = GetRandomNoteCount(0.63, 0);
|
noteCount = GetRandomNoteCount(0.63, 0);
|
||||||
@ -473,11 +441,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < noteCount; j++)
|
for (int j = 0; j < noteCount; j++)
|
||||||
{
|
{
|
||||||
RunWhile(() => rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn, () =>
|
nextColumn = FindAvailableColumn(nextColumn, validation: c => c != holdColumn, patterns: rowPattern);
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
|
|
||||||
addToPattern(rowPattern, nextColumn, startTime, startTime);
|
addToPattern(rowPattern, nextColumn, startTime, startTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,34 +39,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
addToPattern(pattern, 0, generateHold);
|
addToPattern(pattern, 0, generateHold);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold);
|
addToPattern(pattern, FindAvailableColumn(GetRandomColumn(), PreviousPattern), generateHold);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (TotalColumns > 0)
|
if (TotalColumns > 0)
|
||||||
addToPattern(pattern, getNextRandomColumn(0), generateHold);
|
addToPattern(pattern, GetRandomColumn(), generateHold);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Picks a random column after a column.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">The starting column.</param>
|
|
||||||
/// <returns>A random column after <paramref name="start"/>.</returns>
|
|
||||||
private int getNextRandomColumn(int start)
|
|
||||||
{
|
|
||||||
int nextColumn = Random.Next(start, TotalColumns);
|
|
||||||
|
|
||||||
RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () =>
|
|
||||||
{
|
|
||||||
nextColumn = Random.Next(start, TotalColumns);
|
|
||||||
});
|
|
||||||
|
|
||||||
return nextColumn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs and adds a note to a pattern.
|
/// Constructs and adds a note to a pattern.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -231,22 +231,27 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
for (int i = 0; i < noteCount; i++)
|
for (int i = 0; i < noteCount; i++)
|
||||||
{
|
{
|
||||||
RunWhile(() => pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking, () =>
|
nextColumn = allowStacking
|
||||||
{
|
? FindAvailableColumn(nextColumn, nextColumn: getNextColumn, patterns: pattern)
|
||||||
if (convertType.HasFlag(PatternType.Gathered))
|
: FindAvailableColumn(nextColumn, nextColumn: getNextColumn, patterns: new[] { pattern, PreviousPattern });
|
||||||
{
|
|
||||||
nextColumn++;
|
|
||||||
if (nextColumn == TotalColumns)
|
|
||||||
nextColumn = RandomStart;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
|
||||||
});
|
|
||||||
|
|
||||||
addToPattern(pattern, nextColumn);
|
addToPattern(pattern, nextColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
|
|
||||||
|
int getNextColumn(int last)
|
||||||
|
{
|
||||||
|
if (convertType.HasFlag(PatternType.Gathered))
|
||||||
|
{
|
||||||
|
last++;
|
||||||
|
if (last == TotalColumns)
|
||||||
|
last = RandomStart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
last = GetRandomColumn();
|
||||||
|
return last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -292,13 +297,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre);
|
int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre);
|
||||||
|
|
||||||
int columnLimit = (TotalColumns % 2 == 0 ? TotalColumns : TotalColumns - 1) / 2;
|
int columnLimit = (TotalColumns % 2 == 0 ? TotalColumns : TotalColumns - 1) / 2;
|
||||||
int nextColumn = Random.Next(RandomStart, columnLimit);
|
int nextColumn = GetRandomColumn(upperBound: columnLimit);
|
||||||
for (int i = 0; i < noteCount; i++)
|
for (int i = 0; i < noteCount; i++)
|
||||||
{
|
{
|
||||||
RunWhile(() => pattern.ColumnHasObject(nextColumn), () =>
|
nextColumn = FindAvailableColumn(nextColumn, upperBound: columnLimit, patterns: pattern);
|
||||||
{
|
|
||||||
nextColumn = Random.Next(RandomStart, columnLimit);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add normal note
|
// Add normal note
|
||||||
addToPattern(pattern, nextColumn);
|
addToPattern(pattern, nextColumn);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.MathUtils;
|
using osu.Game.Rulesets.Mania.MathUtils;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -90,6 +91,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double? conversionDifficulty;
|
private double? conversionDifficulty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A difficulty factor used for various conversion methods from osu!stable.
|
/// A difficulty factor used for various conversion methods from osu!stable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -116,5 +118,82 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
return conversionDifficulty.Value;
|
return conversionDifficulty.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a new column in which a <see cref="HitObject"/> can be placed.
|
||||||
|
/// This uses <see cref="GetRandomColumn"/> to pick the next candidate column.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="initialColumn">The initial column to test. This may be returned if it is already a valid column.</param>
|
||||||
|
/// <param name="patterns">A list of patterns for which the validity of a column should be checked against.
|
||||||
|
/// A column is not a valid candidate if a <see cref="HitObject"/> occupies the same column in any of the patterns.</param>
|
||||||
|
/// <returns>A column for which there are no <see cref="HitObject"/>s in any of <paramref name="patterns"/> occupying the same column.</returns>
|
||||||
|
/// <exception cref="NotEnoughColumnsException">If there are no valid candidate columns.</exception>
|
||||||
|
protected int FindAvailableColumn(int initialColumn, params Pattern[] patterns)
|
||||||
|
=> FindAvailableColumn(initialColumn, null, patterns: patterns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a new column in which a <see cref="HitObject"/> can be placed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="initialColumn">The initial column to test. This may be returned if it is already a valid column.</param>
|
||||||
|
/// <param name="nextColumn">A function to retrieve the next column. If null, a randomisation scheme will be used.</param>
|
||||||
|
/// <param name="validation">A function to perform additional validation checks to determine if a column is a valid candidate for a <see cref="HitObject"/>.</param>
|
||||||
|
/// <param name="lowerBound">The minimum column index. If null, <see cref="RandomStart"/> is used.</param>
|
||||||
|
/// <param name="upperBound">The maximum column index. If null, <see cref="PatternGenerator.TotalColumns"/> is used.</param>
|
||||||
|
/// <param name="patterns">A list of patterns for which the validity of a column should be checked against.
|
||||||
|
/// A column is not a valid candidate if a <see cref="HitObject"/> occupies the same column in any of the patterns.</param>
|
||||||
|
/// <returns>A column which has passed the <paramref name="validation"/> check and for which there are no
|
||||||
|
/// <see cref="HitObject"/>s in any of <paramref name="patterns"/> occupying the same column.</returns>
|
||||||
|
/// <exception cref="NotEnoughColumnsException">If there are no valid candidate columns.</exception>
|
||||||
|
protected int FindAvailableColumn(int initialColumn, int? lowerBound = null, int? upperBound = null, Func<int, int> nextColumn = null, [InstantHandle] Func<int, bool> validation = null,
|
||||||
|
params Pattern[] patterns)
|
||||||
|
{
|
||||||
|
lowerBound = lowerBound ?? RandomStart;
|
||||||
|
upperBound = upperBound ?? TotalColumns;
|
||||||
|
nextColumn = nextColumn ?? (_ => GetRandomColumn(lowerBound, upperBound));
|
||||||
|
|
||||||
|
// Check for the initial column
|
||||||
|
if (isValid(initialColumn))
|
||||||
|
return initialColumn;
|
||||||
|
|
||||||
|
// Ensure that we have at least one free column, so that an endless loop is avoided
|
||||||
|
bool hasValidColumns = false;
|
||||||
|
for (int i = lowerBound.Value; i < upperBound.Value; i++)
|
||||||
|
{
|
||||||
|
hasValidColumns = isValid(i);
|
||||||
|
if (hasValidColumns)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasValidColumns)
|
||||||
|
throw new NotEnoughColumnsException();
|
||||||
|
|
||||||
|
// Iterate until a valid column is found. This is a random iteration in the default case.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
initialColumn = nextColumn(initialColumn);
|
||||||
|
} while (!isValid(initialColumn));
|
||||||
|
|
||||||
|
return initialColumn;
|
||||||
|
|
||||||
|
bool isValid(int column) => validation?.Invoke(column) != false && !patterns.Any(p => p.ColumnHasObject(column));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a random column index in the range [<paramref name="lowerBound"/>, <paramref name="upperBound"/>).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lowerBound">The minimum column index. If null, <see cref="RandomStart"/> is used.</param>
|
||||||
|
/// <param name="upperBound">The maximum column index. If null, <see cref="PatternGenerator.TotalColumns"/> is used.</param>
|
||||||
|
protected int GetRandomColumn(int? lowerBound = null, int? upperBound = null) => Random.Next(lowerBound ?? RandomStart, upperBound ?? TotalColumns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when mania conversion is stuck in an infinite loop unable to find columns to place new hitobjects in.
|
||||||
|
/// </summary>
|
||||||
|
public class NotEnoughColumnsException : Exception
|
||||||
|
{
|
||||||
|
public NotEnoughColumnsException()
|
||||||
|
: base("There were not enough columns to complete conversion.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||||
@ -15,14 +12,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal abstract class PatternGenerator
|
internal abstract class PatternGenerator
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// An arbitrary maximum amount of iterations to perform in <see cref="RunWhile"/>.
|
|
||||||
/// The specific value is not super important - enough such that no false-positives occur.
|
|
||||||
///
|
|
||||||
/// /b/933228 requires at least 23 iterations.
|
|
||||||
/// </summary>
|
|
||||||
private const int max_rng_iterations = 30;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The last pattern.
|
/// The last pattern.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -53,44 +42,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
TotalColumns = Beatmap.TotalColumns;
|
TotalColumns = Beatmap.TotalColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void RunWhile([InstantHandle] Func<bool> condition, Action action)
|
|
||||||
{
|
|
||||||
int iterations = 0;
|
|
||||||
|
|
||||||
while (condition())
|
|
||||||
{
|
|
||||||
if (iterations++ >= max_rng_iterations)
|
|
||||||
{
|
|
||||||
// log an error but don't throw. we want to continue execution.
|
|
||||||
Logger.Error(new ExceededAllowedIterationsException(new StackTrace(0)),
|
|
||||||
"Conversion encountered errors. The beatmap may not be correctly converted.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates the patterns for <see cref="HitObject"/>, each filled with hit objects.
|
/// Generates the patterns for <see cref="HitObject"/>, each filled with hit objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
||||||
public abstract IEnumerable<Pattern> Generate();
|
public abstract IEnumerable<Pattern> Generate();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Denotes when a single conversion operation is in an infinitely looping state.
|
|
||||||
/// </summary>
|
|
||||||
public class ExceededAllowedIterationsException : Exception
|
|
||||||
{
|
|
||||||
private readonly string stackTrace;
|
|
||||||
|
|
||||||
public ExceededAllowedIterationsException(StackTrace stackTrace)
|
|
||||||
{
|
|
||||||
this.stackTrace = stackTrace.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string StackTrace => stackTrace;
|
|
||||||
public override string ToString() => $"{GetType().Name}: {Message}\r\n{StackTrace}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
throw new ArgumentException("Can't have zero or fewer stages.");
|
throw new ArgumentException("Can't have zero or fewer stages.");
|
||||||
|
|
||||||
GridContainer playfieldGrid;
|
GridContainer playfieldGrid;
|
||||||
InternalChild = playfieldGrid = new GridContainer
|
AddInternal(playfieldGrid = new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Content = new[] { new Drawable[stageDefinitions.Count] }
|
Content = new[] { new Drawable[stageDefinitions.Count] }
|
||||||
};
|
});
|
||||||
|
|
||||||
var normalColumnAction = ManiaAction.Key1;
|
var normalColumnAction = ManiaAction.Key1;
|
||||||
var specialColumnAction = ManiaAction.Special1;
|
var specialColumnAction = ManiaAction.Special1;
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
const float relax_leniency = 3;
|
const float relax_leniency = 3;
|
||||||
|
|
||||||
foreach (var drawable in playfield.HitObjects.AliveObjects)
|
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
||||||
{
|
{
|
||||||
if (!(drawable is DrawableOsuHitObject osuHit))
|
if (!(drawable is DrawableOsuHitObject osuHit))
|
||||||
continue;
|
continue;
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
public override void PostProcess()
|
public override void PostProcess()
|
||||||
{
|
{
|
||||||
connectionLayer.HitObjects = HitObjects.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
|
connectionLayer.HitObjects = HitObjectContainer.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
|
@ -319,17 +319,17 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
|
/// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task ImportFromStable()
|
public Task ImportFromStable()
|
||||||
{
|
{
|
||||||
var stable = GetStableStorage?.Invoke();
|
var stable = GetStableStorage?.Invoke();
|
||||||
|
|
||||||
if (stable == null)
|
if (stable == null)
|
||||||
{
|
{
|
||||||
Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error);
|
Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error);
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Factory.StartNew(() => Import(stable.GetDirectories("Songs").Select(f => stable.GetFullPath(f)).ToArray()), TaskCreationOptions.LongRunning);
|
return Task.Factory.StartNew(() => Import(stable.GetDirectories("Songs").Select(f => stable.GetFullPath(f)).ToArray()), TaskCreationOptions.LongRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -352,9 +352,8 @@ namespace osu.Game.Beatmaps
|
|||||||
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu"));
|
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu"));
|
||||||
if (string.IsNullOrEmpty(mapName))
|
if (string.IsNullOrEmpty(mapName))
|
||||||
{
|
{
|
||||||
// Todo: This is temporary for debugging purposes
|
Logger.Log($"No beatmap files found in the beatmap archive ({reader.Name}).", LoggingTarget.Database);
|
||||||
var files = reader.Filenames.ToList();
|
return null;
|
||||||
throw new InvalidOperationException($"No beatmap files found in this beatmap archive. Files ({files.Count}): {string.Join(", ", files)}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Beatmap beatmap;
|
Beatmap beatmap;
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public bool BeatmapLoaded => beatmap.IsResultAvailable;
|
public bool BeatmapLoaded => beatmap.IsResultAvailable;
|
||||||
public IBeatmap Beatmap => beatmap.Value.Result;
|
public IBeatmap Beatmap => beatmap.Value.Result;
|
||||||
public async Task<IBeatmap> GetBeatmapAsync() => await beatmap.Value;
|
public Task<IBeatmap> GetBeatmapAsync() => beatmap.Value;
|
||||||
private readonly AsyncLazy<IBeatmap> beatmap;
|
private readonly AsyncLazy<IBeatmap> beatmap;
|
||||||
|
|
||||||
private IBeatmap populateBeatmap()
|
private IBeatmap populateBeatmap()
|
||||||
@ -138,14 +138,14 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public bool BackgroundLoaded => background.IsResultAvailable;
|
public bool BackgroundLoaded => background.IsResultAvailable;
|
||||||
public Texture Background => background.Value.Result;
|
public Texture Background => background.Value.Result;
|
||||||
public async Task<Texture> GetBackgroundAsync() => await background.Value;
|
public Task<Texture> GetBackgroundAsync() => background.Value;
|
||||||
private AsyncLazy<Texture> background;
|
private AsyncLazy<Texture> background;
|
||||||
|
|
||||||
private Texture populateBackground() => GetBackground();
|
private Texture populateBackground() => GetBackground();
|
||||||
|
|
||||||
public bool TrackLoaded => track.IsResultAvailable;
|
public bool TrackLoaded => track.IsResultAvailable;
|
||||||
public Track Track => track.Value.Result;
|
public Track Track => track.Value.Result;
|
||||||
public async Task<Track> GetTrackAsync() => await track.Value;
|
public Task<Track> GetTrackAsync() => track.Value;
|
||||||
private AsyncLazy<Track> track;
|
private AsyncLazy<Track> track;
|
||||||
|
|
||||||
private Track populateTrack()
|
private Track populateTrack()
|
||||||
@ -158,21 +158,21 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public bool WaveformLoaded => waveform.IsResultAvailable;
|
public bool WaveformLoaded => waveform.IsResultAvailable;
|
||||||
public Waveform Waveform => waveform.Value.Result;
|
public Waveform Waveform => waveform.Value.Result;
|
||||||
public async Task<Waveform> GetWaveformAsync() => await waveform.Value;
|
public Task<Waveform> GetWaveformAsync() => waveform.Value;
|
||||||
private readonly AsyncLazy<Waveform> waveform;
|
private readonly AsyncLazy<Waveform> waveform;
|
||||||
|
|
||||||
private Waveform populateWaveform() => GetWaveform();
|
private Waveform populateWaveform() => GetWaveform();
|
||||||
|
|
||||||
public bool StoryboardLoaded => storyboard.IsResultAvailable;
|
public bool StoryboardLoaded => storyboard.IsResultAvailable;
|
||||||
public Storyboard Storyboard => storyboard.Value.Result;
|
public Storyboard Storyboard => storyboard.Value.Result;
|
||||||
public async Task<Storyboard> GetStoryboardAsync() => await storyboard.Value;
|
public Task<Storyboard> GetStoryboardAsync() => storyboard.Value;
|
||||||
private readonly AsyncLazy<Storyboard> storyboard;
|
private readonly AsyncLazy<Storyboard> storyboard;
|
||||||
|
|
||||||
private Storyboard populateStoryboard() => GetStoryboard();
|
private Storyboard populateStoryboard() => GetStoryboard();
|
||||||
|
|
||||||
public bool SkinLoaded => skin.IsResultAvailable;
|
public bool SkinLoaded => skin.IsResultAvailable;
|
||||||
public Skin Skin => skin.Value.Result;
|
public Skin Skin => skin.Value.Result;
|
||||||
public async Task<Skin> GetSkinAsync() => await skin.Value;
|
public Task<Skin> GetSkinAsync() => skin.Value;
|
||||||
private readonly AsyncLazy<Skin> skin;
|
private readonly AsyncLazy<Skin> skin;
|
||||||
|
|
||||||
private Skin populateSkin() => GetSkin();
|
private Skin populateSkin() => GetSkin();
|
||||||
|
@ -178,7 +178,8 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Import(CreateModel(archive), archive);
|
var model = CreateModel(archive);
|
||||||
|
return model == null ? null : Import(model, archive);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -389,7 +390,7 @@ namespace osu.Game.Database
|
|||||||
/// Actual expensive population should be done in <see cref="Populate"/>; this should just prepare for duplicate checking.
|
/// Actual expensive population should be done in <see cref="Populate"/>; this should just prepare for duplicate checking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="archive">The archive to create the model for.</param>
|
/// <param name="archive">The archive to create the model for.</param>
|
||||||
/// <returns>A model populated with minimal information.</returns>
|
/// <returns>A model populated with minimal information. Returning a null will abort importing silently.</returns>
|
||||||
protected abstract TModel CreateModel(ArchiveReader archive);
|
protected abstract TModel CreateModel(ArchiveReader archive);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
private volatile int screenShotTasks;
|
private volatile int screenShotTasks;
|
||||||
|
|
||||||
public async Task TakeScreenshotAsync() => await Task.Run(async () =>
|
public Task TakeScreenshotAsync() => Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Interlocked.Increment(ref screenShotTasks);
|
Interlocked.Increment(ref screenShotTasks);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
if (loadableIcon == loadedIcon) return;
|
if (loadableIcon == loadedIcon) return;
|
||||||
|
|
||||||
var texture = store?.Get(((char)loadableIcon).ToString());
|
var texture = store.Get(((char)loadableIcon).ToString());
|
||||||
|
|
||||||
spriteMain.Texture = texture;
|
spriteMain.Texture = texture;
|
||||||
spriteShadow.Texture = texture;
|
spriteShadow.Texture = texture;
|
||||||
@ -129,7 +129,7 @@ namespace osu.Game.Graphics
|
|||||||
if (icon == value) return;
|
if (icon == value) return;
|
||||||
|
|
||||||
icon = value;
|
icon = value;
|
||||||
if (IsLoaded)
|
if (LoadState == LoadState.Loaded)
|
||||||
updateTexture();
|
updateTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
|
||||||
namespace osu.Game.IO.Archives
|
namespace osu.Game.IO.Archives
|
||||||
@ -28,7 +29,9 @@ namespace osu.Game.IO.Archives
|
|||||||
|
|
||||||
public abstract IEnumerable<string> Filenames { get; }
|
public abstract IEnumerable<string> Filenames { get; }
|
||||||
|
|
||||||
public virtual byte[] Get(string name)
|
public virtual byte[] Get(string name) => GetAsync(name).Result;
|
||||||
|
|
||||||
|
public async Task<byte[]> GetAsync(string name)
|
||||||
{
|
{
|
||||||
using (Stream input = GetStream(name))
|
using (Stream input = GetStream(name))
|
||||||
{
|
{
|
||||||
@ -36,7 +39,7 @@ namespace osu.Game.IO.Archives
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
byte[] buffer = new byte[input.Length];
|
byte[] buffer = new byte[input.Length];
|
||||||
input.Read(buffer, 0, buffer.Length);
|
await input.ReadAsync(buffer, 0, buffer.Length);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,10 +75,10 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Screen s = screenStack;
|
Screen screen = screenStack;
|
||||||
while (s != null && !(s is Intro))
|
while (screen != null && !(screen is Intro))
|
||||||
s = s.ChildScreen;
|
screen = screen.ChildScreen;
|
||||||
return s as Intro;
|
return screen as Intro;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +126,8 @@ namespace osu.Game
|
|||||||
/// <param name="toolbar">Whether the toolbar should also be hidden.</param>
|
/// <param name="toolbar">Whether the toolbar should also be hidden.</param>
|
||||||
public void CloseAllOverlays(bool toolbar = true)
|
public void CloseAllOverlays(bool toolbar = true)
|
||||||
{
|
{
|
||||||
foreach (var o in overlays)
|
foreach (var overlay in overlays)
|
||||||
o.State = Visibility.Hidden;
|
overlay.State = Visibility.Hidden;
|
||||||
if (toolbar) Toolbar.State = Visibility.Hidden;
|
if (toolbar) Toolbar.State = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +238,7 @@ namespace osu.Game
|
|||||||
/// <param name="beatmapId">The beatmap to show.</param>
|
/// <param name="beatmapId">The beatmap to show.</param>
|
||||||
public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
|
public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
|
||||||
|
|
||||||
protected void LoadScore(Score s)
|
protected void LoadScore(Score score)
|
||||||
{
|
{
|
||||||
scoreLoad?.Cancel();
|
scoreLoad?.Cancel();
|
||||||
|
|
||||||
@ -246,18 +246,18 @@ namespace osu.Game
|
|||||||
|
|
||||||
if (menu == null)
|
if (menu == null)
|
||||||
{
|
{
|
||||||
scoreLoad = Schedule(() => LoadScore(s));
|
scoreLoad = Schedule(() => LoadScore(score));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!menu.IsCurrentScreen)
|
if (!menu.IsCurrentScreen)
|
||||||
{
|
{
|
||||||
menu.MakeCurrent();
|
menu.MakeCurrent();
|
||||||
this.Delay(500).Schedule(() => LoadScore(s), out scoreLoad);
|
this.Delay(500).Schedule(() => LoadScore(score), out scoreLoad);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.Beatmap == null)
|
if (score.Beatmap == null)
|
||||||
{
|
{
|
||||||
notifications.Post(new SimpleNotification
|
notifications.Post(new SimpleNotification
|
||||||
{
|
{
|
||||||
@ -267,12 +267,12 @@ namespace osu.Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleset.Value = s.Ruleset;
|
ruleset.Value = score.Ruleset;
|
||||||
|
|
||||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap);
|
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(score.Beatmap);
|
||||||
Beatmap.Value.Mods.Value = s.Mods;
|
Beatmap.Value.Mods.Value = score.Mods;
|
||||||
|
|
||||||
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
|
menu.Push(new PlayerLoader(new ReplayPlayer(score.Replay)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
@ -500,22 +500,24 @@ namespace osu.Game
|
|||||||
// we could avoid the need for scheduling altogether.
|
// we could avoid the need for scheduling altogether.
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
if (asyncLoadStream != null)
|
var previousLoadStream = asyncLoadStream;
|
||||||
|
|
||||||
|
//chain with existing load stream
|
||||||
|
asyncLoadStream = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
//chain with existing load stream
|
if (previousLoadStream != null)
|
||||||
asyncLoadStream = asyncLoadStream.ContinueWith(async t =>
|
await previousLoadStream;
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
Logger.Log($"Loading {d}...", LoggingTarget.Debug);
|
||||||
{
|
await LoadComponentAsync(d, add);
|
||||||
await LoadComponentAsync(d, add);
|
Logger.Log($"Loaded {d}!", LoggingTarget.Debug);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else
|
|
||||||
asyncLoadStream = LoadComponentAsync(d, add);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +240,15 @@ namespace osu.Game.Overlays
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
base.PopIn();
|
||||||
|
|
||||||
|
// Queries are allowed to be run only on the first pop-in
|
||||||
|
if (getSetsRequest == null)
|
||||||
|
Scheduler.AddOnce(updateSearch);
|
||||||
|
}
|
||||||
|
|
||||||
private SearchBeatmapSetsRequest getSetsRequest;
|
private SearchBeatmapSetsRequest getSetsRequest;
|
||||||
|
|
||||||
private readonly Bindable<string> currentQuery = new Bindable<string>();
|
private readonly Bindable<string> currentQuery = new Bindable<string>();
|
||||||
@ -251,16 +260,22 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
queryChangedDebounce?.Cancel();
|
queryChangedDebounce?.Cancel();
|
||||||
|
|
||||||
if (!IsLoaded) return;
|
if (!IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (State == Visibility.Hidden)
|
||||||
|
return;
|
||||||
|
|
||||||
BeatmapSets = null;
|
BeatmapSets = null;
|
||||||
ResultAmounts = null;
|
ResultAmounts = null;
|
||||||
|
|
||||||
getSetsRequest?.Cancel();
|
getSetsRequest?.Cancel();
|
||||||
|
|
||||||
if (api == null) return;
|
if (api == null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return;
|
if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty))
|
||||||
|
return;
|
||||||
|
|
||||||
previewTrackManager.StopAnyPlaying(this);
|
previewTrackManager.StopAnyPlaying(this);
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="DrawableHitObject"/> contained in this Playfield.
|
/// The <see cref="DrawableHitObject"/> contained in this Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HitObjectContainer HitObjects { get; private set; }
|
public HitObjectContainer HitObjectContainer { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All the <see cref="DrawableHitObject"/>s contained in this <see cref="Playfield"/> and all <see cref="NestedPlayfields"/>.
|
/// All the <see cref="DrawableHitObject"/>s contained in this <see cref="Playfield"/> and all <see cref="NestedPlayfields"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<DrawableHitObject> AllHitObjects => HitObjects?.Objects.Concat(NestedPlayfields.SelectMany(p => p.AllHitObjects)) ?? Enumerable.Empty<DrawableHitObject>();
|
public IEnumerable<DrawableHitObject> AllHitObjects => HitObjectContainer?.Objects.Concat(NestedPlayfields.SelectMany(p => p.AllHitObjects)) ?? Enumerable.Empty<DrawableHitObject>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All <see cref="Playfield"/>s nested inside this <see cref="Playfield"/>.
|
/// All <see cref="Playfield"/>s nested inside this <see cref="Playfield"/>.
|
||||||
@ -60,10 +60,10 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
this.beatmap = beatmap.Value;
|
this.beatmap = beatmap.Value;
|
||||||
|
|
||||||
HitObjects = CreateHitObjectContainer();
|
HitObjectContainer = CreateHitObjectContainer();
|
||||||
HitObjects.RelativeSizeAxes = Axes.Both;
|
HitObjectContainer.RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Add(HitObjects);
|
Add(HitObjectContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -75,13 +75,13 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// Adds a DrawableHitObject to this Playfield.
|
/// Adds a DrawableHitObject to this Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="h">The DrawableHitObject to add.</param>
|
/// <param name="h">The DrawableHitObject to add.</param>
|
||||||
public virtual void Add(DrawableHitObject h) => HitObjects.Add(h);
|
public virtual void Add(DrawableHitObject h) => HitObjectContainer.Add(h);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove a DrawableHitObject from this Playfield.
|
/// Remove a DrawableHitObject from this Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="h">The DrawableHitObject to remove.</param>
|
/// <param name="h">The DrawableHitObject to remove.</param>
|
||||||
public virtual void Remove(DrawableHitObject h) => HitObjects.Remove(h);
|
public virtual void Remove(DrawableHitObject h) => HitObjectContainer.Remove(h);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a <see cref="Playfield"/> as a nested <see cref="Playfield"/>.
|
/// Registers a <see cref="Playfield"/> as a nested <see cref="Playfield"/>.
|
||||||
|
@ -306,7 +306,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
Playfield.PostProcess();
|
Playfield.PostProcess();
|
||||||
|
|
||||||
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(Playfield.HitObjects.Objects);
|
mod.ApplyToDrawableHitObjects(Playfield.HitObjectContainer.Objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The container that contains the <see cref="DrawableHitObject"/>s.
|
/// The container that contains the <see cref="DrawableHitObject"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)base.HitObjects;
|
public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)HitObjectContainer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The direction in which <see cref="DrawableHitObject"/>s in this <see cref="ScrollingPlayfield"/> should scroll.
|
/// The direction in which <see cref="DrawableHitObject"/>s in this <see cref="ScrollingPlayfield"/> should scroll.
|
||||||
|
@ -64,32 +64,36 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
||||||
{
|
{
|
||||||
get { return beatmapSets.Select(g => g.BeatmapSet); }
|
get => beatmapSets.Select(g => g.BeatmapSet);
|
||||||
set
|
set => loadBeatmapSets(() => value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadBeatmapSetsFromManager(BeatmapManager manager) => loadBeatmapSets(manager.GetAllUsableBeatmapSetsEnumerable);
|
||||||
|
|
||||||
|
private void loadBeatmapSets(Func<IEnumerable<BeatmapSetInfo>> beatmapSets)
|
||||||
|
{
|
||||||
|
CarouselRoot newRoot = new CarouselRoot(this);
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
CarouselRoot newRoot = new CarouselRoot(this);
|
beatmapSets().Select(createCarouselSet).Where(g => g != null).ForEach(newRoot.AddChild);
|
||||||
|
newRoot.Filter(activeCriteria);
|
||||||
|
|
||||||
Task.Run(() =>
|
// preload drawables as the ctor overhead is quite high currently.
|
||||||
|
var _ = newRoot.Drawables;
|
||||||
|
}).ContinueWith(_ => Schedule(() =>
|
||||||
|
{
|
||||||
|
root = newRoot;
|
||||||
|
scrollableContent.Clear(false);
|
||||||
|
itemsCache.Invalidate();
|
||||||
|
scrollPositionCache.Invalidate();
|
||||||
|
|
||||||
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
value.Select(createCarouselSet).Where(g => g != null).ForEach(newRoot.AddChild);
|
BeatmapSetsChanged?.Invoke();
|
||||||
newRoot.Filter(activeCriteria);
|
initialLoadComplete = true;
|
||||||
|
});
|
||||||
// preload drawables as the ctor overhead is quite high currently.
|
}));
|
||||||
var _ = newRoot.Drawables;
|
|
||||||
}).ContinueWith(_ => Schedule(() =>
|
|
||||||
{
|
|
||||||
root = newRoot;
|
|
||||||
scrollableContent.Clear(false);
|
|
||||||
itemsCache.Invalidate();
|
|
||||||
scrollPositionCache.Invalidate();
|
|
||||||
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
BeatmapSetsChanged?.Invoke();
|
|
||||||
initialLoadComplete = true;
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<float> yPositions = new List<float>();
|
private readonly List<float> yPositions = new List<float>();
|
||||||
|
@ -41,7 +41,10 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
updateTexture();
|
updateTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTexture() => rankSprite.Texture = textures.Get($@"Grades/{Rank.GetDescription()}");
|
private void updateTexture()
|
||||||
|
{
|
||||||
|
rankSprite.Texture = textures.Get($@"Grades/{Rank.GetDescription()}");
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateRank(ScoreRank newRank)
|
public void UpdateRank(ScoreRank newRank)
|
||||||
{
|
{
|
||||||
|
@ -221,7 +221,7 @@ namespace osu.Game.Screens.Select
|
|||||||
sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty");
|
sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty");
|
||||||
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
|
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
|
||||||
|
|
||||||
Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable();
|
Carousel.LoadBeatmapSetsFromManager(this.beatmaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Edit(BeatmapInfo beatmap)
|
public void Edit(BeatmapInfo beatmap)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -108,10 +109,12 @@ namespace osu.Game.Skinning
|
|||||||
return path == null ? null : underlyingStore.GetStream(path);
|
return path == null ? null : underlyingStore.GetStream(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] IResourceStore<byte[]>.Get(string name)
|
byte[] IResourceStore<byte[]>.Get(string name) => GetAsync(name).Result;
|
||||||
|
|
||||||
|
public Task<byte[]> GetAsync(string name)
|
||||||
{
|
{
|
||||||
string path = getPathForFile(name);
|
string path = getPathForFile(name);
|
||||||
return path == null ? null : underlyingStore.Get(path);
|
return path == null ? Task.FromResult<byte[]>(null) : underlyingStore.GetAsync(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Humanizer" Version="2.4.2" />
|
<PackageReference Include="Humanizer" Version="2.4.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2018.824.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2018.901.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
|
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
||||||
<PackageReference Include="DeepEqual" Version="1.6.0" />
|
<PackageReference Include="DeepEqual" Version="1.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
Loading…
Reference in New Issue
Block a user