Remove AvailableColumns from ManiaRulesetContainer

Also restructures with the addition of a ManiaBeatmap which holds definitions for "groups" of columns. At the moment these are empty save for a "Column" property, but can be expanded in the future, maybe.
This commit is contained in:
smoogipoo
2018-01-03 18:44:25 +09:00
parent d72bbf037d
commit bd171926d6
13 changed files with 167 additions and 126 deletions

View File

@ -0,0 +1,18 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.UI;
namespace osu.Game.Rulesets.Mania.Beatmaps
{
/// <summary>
/// Defines properties for each grouping of <see cref="Column"/>s in a <see cref="ManiaPlayfield"/>.
/// </summary>
public struct GroupDefinition
{
/// <summary>
/// The number of <see cref="Column"/>s which this grouping contains.
/// </summary>
public int Columns;
}
}

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
namespace osu.Game.Rulesets.Mania.Beatmaps
{
public class ManiaBeatmap : Beatmap<ManiaHitObject>
{
/// <summary>
/// The definitions for each grouping in a <see cref="ManiaPlayfield"/>.
/// </summary>
public readonly List<GroupDefinition> Groups = new List<GroupDefinition>();
/// <summary>
/// Total number of columns represented by all groups in this <see cref="ManiaBeatmap"/>.
/// </summary>
public int TotalColumns => Groups.Sum(g => g.Columns);
/// <summary>
/// Creates a new <see cref="ManiaBeatmap"/>.
/// </summary>
/// <param name="initialGroup">The initial grouping of columns.</param>
public ManiaBeatmap(GroupDefinition initialGroup)
{
Groups.Add(initialGroup);
}
}
}

View File

@ -3,6 +3,7 @@
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
@ -24,24 +25,36 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
public int TargetColumns;
public readonly bool IsForCurrentRuleset;
private Pattern lastPattern = new Pattern(); private Pattern lastPattern = new Pattern();
private FastRandom random; private FastRandom random;
private Beatmap beatmap;
private readonly int availableColumns; private ManiaBeatmap beatmap;
private readonly bool isForCurrentRuleset;
public ManiaBeatmapConverter(bool isForCurrentRuleset, int availableColumns) public ManiaBeatmapConverter(bool isForCurrentRuleset, Beatmap original)
{ {
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns)); IsForCurrentRuleset = isForCurrentRuleset;
this.isForCurrentRuleset = isForCurrentRuleset; if (isForCurrentRuleset)
this.availableColumns = availableColumns; TargetColumns = (int)Math.Max(1, Math.Round(original.BeatmapInfo.BaseDifficulty.CircleSize));
else
{
float percentSliderOrSpinner = (float)original.HitObjects.Count(h => h is IHasEndTime) / original.HitObjects.Count;
if (percentSliderOrSpinner < 0.2)
TargetColumns = 7;
else if (percentSliderOrSpinner < 0.3 || Math.Round(original.BeatmapInfo.BaseDifficulty.CircleSize) >= 5)
TargetColumns = Math.Round(original.BeatmapInfo.BaseDifficulty.OverallDifficulty) > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6)
TargetColumns = Math.Round(original.BeatmapInfo.BaseDifficulty.OverallDifficulty) > 4 ? 5 : 4;
else
TargetColumns = Math.Max(4, Math.Min((int)Math.Round(original.BeatmapInfo.BaseDifficulty.OverallDifficulty) + 1, 7));
}
} }
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original) protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original)
{ {
beatmap = original;
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty; BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
@ -51,6 +64,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
return base.ConvertBeatmap(original); return base.ConvertBeatmap(original);
} }
protected override Beatmap<ManiaHitObject> CreateBeatmap() => beatmap = new ManiaBeatmap(new GroupDefinition { Columns = TargetColumns });
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap) protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
{ {
var maniaOriginal = original as ManiaHitObject; var maniaOriginal = original as ManiaHitObject;
@ -60,7 +75,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
yield break; yield break;
} }
var objects = isForCurrentRuleset ? generateSpecific(original) : generateConverted(original); var objects = IsForCurrentRuleset ? generateSpecific(original) : generateConverted(original);
if (objects == null) if (objects == null)
yield break; yield break;
@ -96,7 +111,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <returns>The hit objects generated.</returns> /// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original) private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
{ {
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, availableColumns, lastPattern); var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern);
Pattern newPattern = generator.Generate(); Pattern newPattern = generator.Generate();
lastPattern = newPattern; lastPattern = newPattern;
@ -120,14 +135,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
Patterns.PatternGenerator conversion = null; Patterns.PatternGenerator conversion = null;
if (distanceData != null) if (distanceData != null)
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern); conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern);
else if (endTimeData != null) else if (endTimeData != null)
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, availableColumns); conversion = new EndTimeObjectPatternGenerator(random, original, beatmap);
else if (positionData != null) else if (positionData != null)
{ {
computeDensity(original.StartTime); computeDensity(original.StartTime);
conversion = new HitObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern, lastTime, lastPosition, density, lastStair); conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair);
recordNote(original.StartTime, positionData.Position); recordNote(original.StartTime, positionData.Position);
} }
@ -149,8 +164,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary> /// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{ {
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern) public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, availableColumns, previousPattern) : base(random, hitObject, beatmap, previousPattern)
{ {
} }

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Audio; using osu.Game.Audio;
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;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
@ -30,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private PatternType convertType; private PatternType convertType;
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern) public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, availableColumns, previousPattern) : base(random, hitObject, beatmap, previousPattern)
{ {
convertType = PatternType.None; convertType = PatternType.None;
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode) if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
@ -79,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (duration >= 4000) if (duration >= 4000)
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0); return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
if (segmentDuration > 400 && repeatCount < AvailableColumns - 1 - RandomStart) if (segmentDuration > 400 && repeatCount < TotalColumns - 1 - RandomStart)
return generateTiledHoldNotes(HitObject.StartTime); return generateTiledHoldNotes(HitObject.StartTime);
return generateHoldAndNormalNotes(HitObject.StartTime); return generateHoldAndNormalNotes(HitObject.StartTime);
@ -87,7 +86,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (segmentDuration <= 110) if (segmentDuration <= 110)
{ {
if (PreviousPattern.ColumnWithObjects < AvailableColumns) if (PreviousPattern.ColumnWithObjects < TotalColumns)
convertType |= PatternType.ForceNotStack; convertType |= PatternType.ForceNotStack;
else else
convertType &= ~PatternType.ForceNotStack; convertType &= ~PatternType.ForceNotStack;
@ -135,12 +134,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
var pattern = new Pattern(); var pattern = new Pattern();
int usableColumns = AvailableColumns - RandomStart - PreviousPattern.ColumnWithObjects; int usableColumns = TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects;
int nextColumn = Random.Next(RandomStart, AvailableColumns); int nextColumn = Random.Next(RandomStart, TotalColumns);
for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) for (int i = 0; i < Math.Min(usableColumns, noteCount); i++)
{ {
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(pattern, nextColumn, startTime, endTime); addToPattern(pattern, nextColumn, startTime, endTime);
} }
@ -148,7 +147,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
for (int i = 0; i < noteCount - usableColumns; i++) for (int i = 0; i < noteCount - usableColumns; i++)
{ {
while (pattern.ColumnHasObject(nextColumn)) while (pattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(pattern, nextColumn, startTime, endTime); addToPattern(pattern, nextColumn, startTime, endTime);
} }
@ -172,10 +171,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
var pattern = new Pattern(); var pattern = new Pattern();
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
{ {
while (PreviousPattern.ColumnHasObject(nextColumn)) while (PreviousPattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
} }
int lastColumn = nextColumn; int lastColumn = nextColumn;
@ -183,7 +182,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
addToPattern(pattern, nextColumn, startTime, startTime); addToPattern(pattern, nextColumn, startTime, startTime);
while (nextColumn == lastColumn) while (nextColumn == lastColumn)
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
lastColumn = nextColumn; lastColumn = nextColumn;
startTime += segmentDuration; startTime += segmentDuration;
@ -221,7 +220,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// Check if we're at the borders of the stage, and invert the pattern if so // Check if we're at the borders of the stage, and invert the pattern if so
if (increasing) if (increasing)
{ {
if (column >= AvailableColumns - 1) if (column >= TotalColumns - 1)
{ {
increasing = false; increasing = false;
column--; column--;
@ -259,8 +258,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
var pattern = new Pattern(); var pattern = new Pattern();
bool legacy = AvailableColumns >= 4 && AvailableColumns <= 8; bool legacy = TotalColumns >= 4 && TotalColumns <= 8;
int interval = Random.Next(1, AvailableColumns - (legacy ? 1 : 0)); int interval = Random.Next(1, TotalColumns - (legacy ? 1 : 0));
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
for (int i = 0; i <= repeatCount; i++) for (int i = 0; i <= repeatCount; i++)
@ -268,15 +267,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
addToPattern(pattern, nextColumn, startTime, startTime); addToPattern(pattern, nextColumn, startTime, startTime);
nextColumn += interval; nextColumn += interval;
if (nextColumn >= AvailableColumns - RandomStart) if (nextColumn >= TotalColumns - RandomStart)
nextColumn = nextColumn - AvailableColumns - RandomStart + (legacy ? 1 : 0); nextColumn = nextColumn - TotalColumns - RandomStart + (legacy ? 1 : 0);
nextColumn += RandomStart; nextColumn += RandomStart;
// If we're in 2K, let's not add many consecutive doubles // If we're in 2K, let's not add many consecutive doubles
if (AvailableColumns > 2) if (TotalColumns > 2)
addToPattern(pattern, nextColumn, startTime, startTime); addToPattern(pattern, nextColumn, startTime, startTime);
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
startTime += segmentDuration; startTime += segmentDuration;
} }
@ -298,7 +297,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// □ - □ □ // □ - □ □
// ■ - ■ ■ // ■ - ■ ■
switch (AvailableColumns) switch (TotalColumns)
{ {
case 2: case 2:
p2 = 0; p2 = 0;
@ -351,19 +350,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
var pattern = new Pattern(); var pattern = new Pattern();
int columnRepeat = Math.Min(repeatCount, AvailableColumns); int columnRepeat = Math.Min(repeatCount, TotalColumns);
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
{ {
while (PreviousPattern.ColumnHasObject(nextColumn)) while (PreviousPattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
} }
for (int i = 0; i < columnRepeat; i++) for (int i = 0; i < columnRepeat; i++)
{ {
while (pattern.ColumnHasObject(nextColumn)) while (pattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(pattern, nextColumn, startTime, endTime); addToPattern(pattern, nextColumn, startTime, endTime);
startTime += segmentDuration; startTime += segmentDuration;
@ -388,10 +387,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
var pattern = new Pattern(); var pattern = new Pattern();
int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
{ {
while (PreviousPattern.ColumnHasObject(holdColumn)) while (PreviousPattern.ColumnHasObject(holdColumn))
holdColumn = Random.Next(RandomStart, AvailableColumns); holdColumn = Random.Next(RandomStart, TotalColumns);
} }
// Create the hold note // Create the hold note
@ -401,13 +400,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (ConversionDifficulty > 6.5) if (ConversionDifficulty > 6.5)
noteCount = GetRandomNoteCount(0.63, 0); noteCount = GetRandomNoteCount(0.63, 0);
else if (ConversionDifficulty > 4) else if (ConversionDifficulty > 4)
noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0.12 : 0.45, 0); noteCount = GetRandomNoteCount(TotalColumns < 6 ? 0.12 : 0.45, 0);
else if (ConversionDifficulty > 2.5) else if (ConversionDifficulty > 2.5)
noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0 : 0.24, 0); noteCount = GetRandomNoteCount(TotalColumns < 6 ? 0 : 0.24, 0);
noteCount = Math.Min(AvailableColumns - 1, noteCount); noteCount = Math.Min(TotalColumns - 1, noteCount);
bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP);
int nextColumn = Random.Next(RandomStart, AvailableColumns); int nextColumn = Random.Next(RandomStart, TotalColumns);
var rowPattern = new Pattern(); var rowPattern = new Pattern();
for (int i = 0; i <= repeatCount; i++) for (int i = 0; i <= repeatCount; i++)
@ -417,7 +416,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
for (int j = 0; j < noteCount; j++) for (int j = 0; j < noteCount; j++)
{ {
while (rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn) while (rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn)
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
addToPattern(rowPattern, nextColumn, startTime, startTime); addToPattern(rowPattern, nextColumn, startTime, startTime);
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
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;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
@ -16,8 +15,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
private readonly double endTime; private readonly double endTime;
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns) public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap)
: base(random, hitObject, beatmap, availableColumns, new Pattern()) : base(random, hitObject, beatmap, new Pattern())
{ {
var endtimeData = HitObject as IHasEndTime; var endtimeData = HitObject as IHasEndTime;
@ -30,14 +29,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
bool generateHold = endTime - HitObject.StartTime >= 100; bool generateHold = endTime - HitObject.StartTime >= 100;
if (AvailableColumns == 8) if (TotalColumns == 8)
{ {
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000) if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000)
addToPattern(pattern, 0, generateHold); addToPattern(pattern, 0, generateHold);
else else
addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold); addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold);
} }
else if (AvailableColumns > 0) else if (TotalColumns > 0)
addToPattern(pattern, getNextRandomColumn(0), generateHold); addToPattern(pattern, getNextRandomColumn(0), generateHold);
return pattern; return pattern;
@ -50,10 +49,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <returns>A random column after <paramref name="start"/>.</returns> /// <returns>A random column after <paramref name="start"/>.</returns>
private int getNextRandomColumn(int start) private int getNextRandomColumn(int start)
{ {
int nextColumn = Random.Next(start, AvailableColumns); int nextColumn = Random.Next(start, TotalColumns);
while (PreviousPattern.ColumnHasObject(nextColumn)) while (PreviousPattern.ColumnHasObject(nextColumn))
nextColumn = Random.Next(start, AvailableColumns); nextColumn = Random.Next(start, TotalColumns);
return nextColumn; return nextColumn;
} }

View File

@ -5,7 +5,6 @@ using System;
using System.Linq; using System.Linq;
using OpenTK; using OpenTK;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
@ -20,8 +19,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly PatternType convertType; private readonly PatternType convertType;
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair) public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
: base(random, hitObject, beatmap, availableColumns, previousPattern) : base(random, hitObject, beatmap, previousPattern)
{ {
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime)); if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
if (density < 0) throw new ArgumentOutOfRangeException(nameof(density)); if (density < 0) throw new ArgumentOutOfRangeException(nameof(density));
@ -88,23 +87,23 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// Generate a new pattern by copying the last hit objects in reverse-column order // Generate a new pattern by copying the last hit objects in reverse-column order
var pattern = new Pattern(); var pattern = new Pattern();
for (int i = RandomStart; i < AvailableColumns; i++) for (int i = RandomStart; i < TotalColumns; i++)
if (PreviousPattern.ColumnHasObject(i)) if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, RandomStart + AvailableColumns - i - 1); addToPattern(pattern, RandomStart + TotalColumns - i - 1);
return pattern; return pattern;
} }
if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1 if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1
// If we convert to 7K + 1, let's not overload the special key // If we convert to 7K + 1, let's not overload the special key
&& (AvailableColumns != 8 || lastColumn != 0) && (TotalColumns != 8 || lastColumn != 0)
// Make sure the last column was not the centre column // Make sure the last column was not the centre column
&& (AvailableColumns % 2 == 0 || lastColumn != AvailableColumns / 2)) && (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
{ {
// Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object) // Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object)
var pattern = new Pattern(); var pattern = new Pattern();
int column = RandomStart + AvailableColumns - lastColumn - 1; int column = RandomStart + TotalColumns - lastColumn - 1;
addToPattern(pattern, column); addToPattern(pattern, column);
return pattern; return pattern;
@ -115,7 +114,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// Generate a new pattern by placing on the already filled columns // Generate a new pattern by placing on the already filled columns
var pattern = new Pattern(); var pattern = new Pattern();
for (int i = RandomStart; i < AvailableColumns; i++) for (int i = RandomStart; i < TotalColumns; i++)
if (PreviousPattern.ColumnHasObject(i)) if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, i); addToPattern(pattern, i);
@ -128,7 +127,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
var pattern = new Pattern(); var pattern = new Pattern();
int targetColumn = lastColumn + 1; int targetColumn = lastColumn + 1;
if (targetColumn == AvailableColumns) if (targetColumn == TotalColumns)
{ {
targetColumn = RandomStart; targetColumn = RandomStart;
StairType = PatternType.ReverseStair; StairType = PatternType.ReverseStair;
@ -146,7 +145,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
int targetColumn = lastColumn - 1; int targetColumn = lastColumn - 1;
if (targetColumn == RandomStart - 1) if (targetColumn == RandomStart - 1)
{ {
targetColumn = AvailableColumns - 1; targetColumn = TotalColumns - 1;
StairType = PatternType.Stair; StairType = PatternType.Stair;
} }
@ -206,7 +205,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
bool allowStacking = (convertType & PatternType.ForceNotStack) == 0; bool allowStacking = (convertType & PatternType.ForceNotStack) == 0;
if (!allowStacking) if (!allowStacking)
noteCount = Math.Min(noteCount, AvailableColumns - RandomStart - PreviousPattern.ColumnWithObjects); noteCount = Math.Min(noteCount, TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects);
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++)
@ -216,11 +215,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if ((convertType & PatternType.Gathered) > 0) if ((convertType & PatternType.Gathered) > 0)
{ {
nextColumn++; nextColumn++;
if (nextColumn == AvailableColumns) if (nextColumn == TotalColumns)
nextColumn = RandomStart; nextColumn = RandomStart;
} }
else else
nextColumn = Random.Next(RandomStart, AvailableColumns); nextColumn = Random.Next(RandomStart, TotalColumns);
} }
addToPattern(pattern, nextColumn); addToPattern(pattern, nextColumn);
@ -268,7 +267,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
bool addToCentre; bool addToCentre;
int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre); int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre);
int columnLimit = (AvailableColumns % 2 == 0 ? AvailableColumns : AvailableColumns - 1) / 2; int columnLimit = (TotalColumns % 2 == 0 ? TotalColumns : TotalColumns - 1) / 2;
int nextColumn = Random.Next(RandomStart, columnLimit); int nextColumn = Random.Next(RandomStart, columnLimit);
for (int i = 0; i < noteCount; i++) for (int i = 0; i < noteCount; i++)
{ {
@ -278,11 +277,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// Add normal note // Add normal note
addToPattern(pattern, nextColumn); addToPattern(pattern, nextColumn);
// Add mirrored note // Add mirrored note
addToPattern(pattern, RandomStart + AvailableColumns - nextColumn - 1); addToPattern(pattern, RandomStart + TotalColumns - nextColumn - 1);
} }
if (addToCentre) if (addToCentre)
addToPattern(pattern, AvailableColumns / 2); addToPattern(pattern, TotalColumns / 2);
if (RandomStart > 0 && hasSpecialColumn) if (RandomStart > 0 && hasSpecialColumn)
addToPattern(pattern, 0); addToPattern(pattern, 0);
@ -300,7 +299,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <returns>The amount of notes to be generated.</returns> /// <returns>The amount of notes to be generated.</returns>
private int getRandomNoteCount(double p2, double p3, double p4, double p5) private int getRandomNoteCount(double p2, double p3, double p4, double p5)
{ {
switch (AvailableColumns) switch (TotalColumns)
{ {
case 2: case 2:
p2 = 0; p2 = 0;
@ -348,7 +347,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if ((convertType & PatternType.ForceNotStack) > 0) if ((convertType & PatternType.ForceNotStack) > 0)
return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3);
switch (AvailableColumns) switch (TotalColumns)
{ {
case 2: case 2:
centreProbability = 0; centreProbability = 0;
@ -379,7 +378,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
double centreVal = Random.NextDouble(); double centreVal = Random.NextDouble();
int noteCount = GetRandomNoteCount(p2, p3); int noteCount = GetRandomNoteCount(p2, p3);
addToCentre = AvailableColumns % 2 != 0 && noteCount != 3 && centreVal > 1 - centreProbability; addToCentre = TotalColumns % 2 != 0 && noteCount != 3 && centreVal > 1 - centreProbability;
return noteCount; return noteCount;
} }

View File

@ -25,16 +25,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// </summary> /// </summary>
protected readonly FastRandom Random; protected readonly FastRandom Random;
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern) protected PatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
: base(hitObject, beatmap, availableColumns, previousPattern) : base(hitObject, beatmap, previousPattern)
{ {
if (random == null) throw new ArgumentNullException(nameof(random)); if (random == null) throw new ArgumentNullException(nameof(random));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern)); if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
Random = random; Random = random;
RandomStart = AvailableColumns == 8 ? 1 : 0; RandomStart = TotalColumns == 8 ? 1 : 0;
} }
/// <summary> /// <summary>
@ -45,14 +44,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <returns>The column.</returns> /// <returns>The column.</returns>
protected int GetColumn(float position, bool allowSpecial = false) protected int GetColumn(float position, bool allowSpecial = false)
{ {
if (allowSpecial && AvailableColumns == 8) if (allowSpecial && TotalColumns == 8)
{ {
const float local_x_divisor = 512f / 7; const float local_x_divisor = 512f / 7;
return MathHelper.Clamp((int)Math.Floor(position / local_x_divisor), 0, 6) + 1; return MathHelper.Clamp((int)Math.Floor(position / local_x_divisor), 0, 6) + 1;
} }
float localXDivisor = 512f / AvailableColumns; float localXDivisor = 512f / TotalColumns;
return MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, AvailableColumns - 1); return MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, TotalColumns - 1);
} }
/// <summary> /// <summary>

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
@ -12,11 +11,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
/// </summary> /// </summary>
internal abstract class PatternGenerator internal abstract class PatternGenerator
{ {
/// <summary>
/// The number of columns available to create the pattern.
/// </summary>
protected readonly int AvailableColumns;
/// <summary> /// <summary>
/// The last pattern. /// The last pattern.
/// </summary> /// </summary>
@ -30,19 +24,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
/// <summary> /// <summary>
/// The beatmap which <see cref="HitObject"/> is a part of. /// The beatmap which <see cref="HitObject"/> is a part of.
/// </summary> /// </summary>
protected readonly Beatmap Beatmap; protected readonly ManiaBeatmap Beatmap;
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern) protected readonly int TotalColumns;
protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
{ {
if (hitObject == null) throw new ArgumentNullException(nameof(hitObject)); if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern)); if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
HitObject = hitObject; HitObject = hitObject;
Beatmap = beatmap; Beatmap = beatmap;
AvailableColumns = availableColumns;
PreviousPattern = previousPattern; PreviousPattern = previousPattern;
TotalColumns = Beatmap.TotalColumns;
} }
/// <summary> /// <summary>

View File

@ -5,7 +5,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using System.Collections.Generic; using System.Collections.Generic;
using System;
namespace osu.Game.Rulesets.Mania namespace osu.Game.Rulesets.Mania
{ {
@ -18,6 +17,6 @@ namespace osu.Game.Rulesets.Mania
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0; public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, beatmap);
} }
} }

View File

@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer) public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{ {
int availableColumns = ((ManiaRulesetContainer)rulesetContainer).AvailableColumns; int availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList(); var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList();
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = shuffledColumns[h.Column]); rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = shuffledColumns[h.Column]);

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenTK; using OpenTK;
@ -29,11 +28,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject> public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject>
{ {
/// <summary> public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
/// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which
/// the beatmap converter will attempt to convert beatmaps to use.
/// </summary>
public int AvailableColumns { get; private set; }
public IEnumerable<DrawableBarLine> BarLines; public IEnumerable<DrawableBarLine> BarLines;
@ -74,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.UI
BarLines.ForEach(Playfield.Add); BarLines.ForEach(Playfield.Add);
} }
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(AvailableColumns) protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.TotalColumns)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -82,27 +77,9 @@ namespace osu.Game.Rulesets.Mania.UI
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, AvailableColumns); public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Beatmap.TotalColumns);
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);
{
if (IsForCurrentRuleset)
AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.CircleSize));
else
{
float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count;
if (percentSliderOrSpinner < 0.2)
AvailableColumns = 7;
else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.CircleSize) >= 5)
AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6)
AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) > 4 ? 5 : 4;
else
AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) + 1, 7));
}
return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns);
}
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h) protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
{ {

View File

@ -48,6 +48,8 @@
<Reference Include="System.Core" /> <Reference Include="System.Core" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Beatmaps\GroupDefinition.cs" />
<Compile Include="Beatmaps\ManiaBeatmap.cs" />
<Compile Include="Beatmaps\Patterns\Legacy\EndTimeObjectPatternGenerator.cs" /> <Compile Include="Beatmaps\Patterns\Legacy\EndTimeObjectPatternGenerator.cs" />
<Compile Include="Beatmaps\Patterns\Legacy\DistanceObjectPatternGenerator.cs" /> <Compile Include="Beatmaps\Patterns\Legacy\DistanceObjectPatternGenerator.cs" />
<Compile Include="Beatmaps\Patterns\Legacy\PatternGenerator.cs" /> <Compile Include="Beatmaps\Patterns\Legacy\PatternGenerator.cs" />

View File

@ -39,12 +39,12 @@ namespace osu.Game.Beatmaps
/// <returns>The converted Beatmap.</returns> /// <returns>The converted Beatmap.</returns>
protected virtual Beatmap<T> ConvertBeatmap(Beatmap original) protected virtual Beatmap<T> ConvertBeatmap(Beatmap original)
{ {
return new Beatmap<T> var beatmap = CreateBeatmap();
{ beatmap.BeatmapInfo = original.BeatmapInfo;
BeatmapInfo = original.BeatmapInfo, beatmap.ControlPointInfo = original.ControlPointInfo;
ControlPointInfo = original.ControlPointInfo, beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList();
HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList()
}; return beatmap;
} }
/// <summary> /// <summary>
@ -78,6 +78,11 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
protected abstract IEnumerable<Type> ValidConversionTypes { get; } protected abstract IEnumerable<Type> ValidConversionTypes { get; }
/// <summary>
/// Creates the <see cref="Beatmap{T}"/> that will be returned by this <see cref="BeatmapProcessor{T}"/>.
/// </summary>
protected virtual Beatmap<T> CreateBeatmap() => new Beatmap<T>();
/// <summary> /// <summary>
/// Performs the conversion of a hit object. /// Performs the conversion of a hit object.
/// This method is generally executed sequentially for all objects in a beatmap. /// This method is generally executed sequentially for all objects in a beatmap.