mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 18:32:55 +08:00
Merge branch 'master' into fix-music-controller-regressed
This commit is contained in:
commit
072aab90ab
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.907.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||||
|
@ -21,13 +21,11 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class CatchRuleset : Ruleset, ILegacyRuleset
|
public class CatchRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
||||||
|
@ -14,11 +14,13 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
[TestCase("basic")]
|
[TestCase("basic")]
|
||||||
|
[TestCase("zero-length-slider")]
|
||||||
public void Test(string name) => base.Test(name);
|
public void Test(string name) => base.Test(name);
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
|
@ -5,7 +5,6 @@ using osu.Game.Rulesets.Mania.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -167,8 +166,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
var positionData = original as IHasPosition;
|
var positionData = original as IHasPosition;
|
||||||
|
|
||||||
for (double time = original.StartTime; !Precision.DefinitelyBigger(time, generator.EndTime); time += generator.SegmentDuration)
|
for (int i = 0; i <= generator.SpanCount; i++)
|
||||||
{
|
{
|
||||||
|
double time = original.StartTime + generator.SegmentDuration * i;
|
||||||
|
|
||||||
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
||||||
computeDensity(time);
|
computeDensity(time);
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
public readonly double EndTime;
|
public readonly double EndTime;
|
||||||
public readonly double SegmentDuration;
|
public readonly double SegmentDuration;
|
||||||
|
public readonly int SpanCount;
|
||||||
private readonly int spanCount;
|
|
||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
|
|
||||||
@ -42,20 +41,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
var distanceData = hitObject as IHasDistance;
|
var distanceData = hitObject as IHasDistance;
|
||||||
var repeatsData = hitObject as IHasRepeats;
|
var repeatsData = hitObject as IHasRepeats;
|
||||||
|
|
||||||
spanCount = repeatsData?.SpanCount() ?? 1;
|
SpanCount = repeatsData?.SpanCount() ?? 1;
|
||||||
|
|
||||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
||||||
|
|
||||||
// The true distance, accounting for any repeats
|
// The true distance, accounting for any repeats
|
||||||
double distance = (distanceData?.Distance ?? 0) * spanCount;
|
double distance = (distanceData?.Distance ?? 0) * SpanCount;
|
||||||
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
||||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
EndTime = hitObject.StartTime + osuDuration;
|
EndTime = hitObject.StartTime + osuDuration;
|
||||||
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
|
SegmentDuration = (EndTime - HitObject.StartTime) / SpanCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Pattern> Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
@ -96,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spanCount > 1)
|
if (SpanCount > 1)
|
||||||
{
|
{
|
||||||
if (SegmentDuration <= 90)
|
if (SegmentDuration <= 90)
|
||||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||||
@ -104,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (SegmentDuration <= 120)
|
if (SegmentDuration <= 120)
|
||||||
{
|
{
|
||||||
convertType |= PatternType.ForceNotStack;
|
convertType |= PatternType.ForceNotStack;
|
||||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
return generateRandomNotes(HitObject.StartTime, SpanCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SegmentDuration <= 160)
|
if (SegmentDuration <= 160)
|
||||||
@ -117,7 +116,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 && spanCount < TotalColumns - 1 - RandomStart)
|
if (SegmentDuration > 400 && SpanCount < TotalColumns - 1 - RandomStart)
|
||||||
return generateTiledHoldNotes(HitObject.StartTime);
|
return generateTiledHoldNotes(HitObject.StartTime);
|
||||||
|
|
||||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||||
@ -251,7 +250,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
bool increasing = Random.NextDouble() > 0.5;
|
bool increasing = Random.NextDouble() > 0.5;
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, column, startTime, startTime);
|
addToPattern(pattern, column, startTime, startTime);
|
||||||
startTime += SegmentDuration;
|
startTime += SegmentDuration;
|
||||||
@ -302,7 +301,7 @@ 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 <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
|
||||||
@ -393,7 +392,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
int columnRepeat = Math.Min(SpanCount, TotalColumns);
|
||||||
|
|
||||||
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)
|
||||||
@ -447,7 +446,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var rowPattern = new Pattern();
|
var rowPattern = new Pattern();
|
||||||
|
|
||||||
for (int i = 0; i <= spanCount; i++)
|
for (int i = 0; i <= SpanCount; i++)
|
||||||
{
|
{
|
||||||
if (!(ignoreHead && startTime == HitObject.StartTime))
|
if (!(ignoreHead && startTime == HitObject.StartTime))
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
@ -35,7 +34,6 @@ using osu.Game.Screens.Ranking.Statistics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class ManiaRuleset : Ruleset, ILegacyRuleset
|
public class ManiaRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"RandomW": 3083084786,
|
||||||
|
"RandomX": 273326509,
|
||||||
|
"RandomY": 273553282,
|
||||||
|
"RandomZ": 2659838971,
|
||||||
|
"StartTime": 4836,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 4836,
|
||||||
|
"EndTime": 4836,
|
||||||
|
"Column": 0
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StackLeniency: 0.7
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
HPDrainRate:1
|
||||||
|
CircleSize:4
|
||||||
|
OverallDifficulty:1
|
||||||
|
ApproachRate:9
|
||||||
|
SliderMultiplier:2.5
|
||||||
|
SliderTickRate:0.5
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
34,431.654676258993,4,1,0,50,1,0
|
||||||
|
4782,-66.6666666666667,4,1,0,20,0,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
15,199,4836,22,0,L,1,46.8750017881394
|
@ -12,6 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
@ -30,14 +30,12 @@ using osu.Game.Scoring;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Statistics;
|
using osu.Game.Rulesets.Osu.Statistics;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class OsuRuleset : Ruleset, ILegacyRuleset
|
public class OsuRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
||||||
|
@ -18,6 +18,10 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
||||||
|
|
||||||
|
protected new float CalculatedBorderPortion
|
||||||
|
// Roughly matches osu!stable's slider border portions.
|
||||||
|
=> base.CalculatedBorderPortion * 0.77f;
|
||||||
|
|
||||||
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
||||||
|
|
||||||
protected override Color4 ColourAt(float position)
|
protected override Color4 ColourAt(float position)
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
namespace osu.Game.Rulesets.Taiko.Tests
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[Timeout(10000)]
|
||||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||||
|
@ -22,7 +22,6 @@ using osu.Game.Rulesets.Taiko.Scoring;
|
|||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Taiko.Edit;
|
using osu.Game.Rulesets.Taiko.Edit;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
@ -32,7 +31,6 @@ using osu.Game.Skinning;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
|
||||||
public class TaikoRuleset : Ruleset, ILegacyRuleset
|
public class TaikoRuleset : Ruleset, ILegacyRuleset
|
||||||
{
|
{
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
||||||
|
@ -10,6 +10,7 @@ using System.Text;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
@ -19,6 +20,7 @@ using osu.Game.Rulesets.Catch;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Taiko;
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.Formats
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
@ -26,18 +28,33 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LegacyBeatmapEncoderTest
|
public class LegacyBeatmapEncoderTest
|
||||||
{
|
{
|
||||||
private static IEnumerable<string> allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
private static readonly DllResourceStore beatmaps_resource_store = TestResources.GetStore();
|
||||||
|
|
||||||
|
private static IEnumerable<string> allBeatmaps = beatmaps_resource_store.GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
||||||
|
|
||||||
[TestCaseSource(nameof(allBeatmaps))]
|
[TestCaseSource(nameof(allBeatmaps))]
|
||||||
public void TestEncodeDecodeStability(string name)
|
public void TestEncodeDecodeStability(string name)
|
||||||
{
|
{
|
||||||
var decoded = decodeFromLegacy(TestResources.GetStore().GetStream(name));
|
var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name);
|
||||||
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded));
|
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name);
|
||||||
|
|
||||||
sort(decoded);
|
sort(decoded.beatmap);
|
||||||
sort(decodedAfterEncode);
|
sort(decodedAfterEncode.beatmap);
|
||||||
|
|
||||||
Assert.That(decodedAfterEncode.Serialize(), Is.EqualTo(decoded.Serialize()));
|
Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(decoded.beatmap.Serialize()));
|
||||||
|
Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b)
|
||||||
|
{
|
||||||
|
// equal to null, no need to SequenceEqual
|
||||||
|
if (a.ComboColours == null && b.ComboColours == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (a.ComboColours == null || b.ComboColours == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return a.ComboColours.SequenceEqual(b.ComboColours);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sort(IBeatmap beatmap)
|
private void sort(IBeatmap beatmap)
|
||||||
@ -50,18 +67,31 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap decodeFromLegacy(Stream stream)
|
private (IBeatmap beatmap, TestLegacySkin beatmapSkin) decodeFromLegacy(Stream stream, string name)
|
||||||
{
|
{
|
||||||
using (var reader = new LineBufferedReader(stream))
|
using (var reader = new LineBufferedReader(stream))
|
||||||
return convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader));
|
{
|
||||||
|
var beatmap = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader);
|
||||||
|
var beatmapSkin = new TestLegacySkin(beatmaps_resource_store, name);
|
||||||
|
return (convert(beatmap), beatmapSkin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream encodeToLegacy(IBeatmap beatmap)
|
private class TestLegacySkin : LegacySkin
|
||||||
{
|
{
|
||||||
|
public TestLegacySkin(IResourceStore<byte[]> storage, string fileName)
|
||||||
|
: base(new SkinInfo { Name = "Test Skin", Creator = "Craftplacer" }, storage, null, fileName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap)
|
||||||
|
{
|
||||||
|
var (beatmap, beatmapSkin) = fullBeatmap;
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
|
|
||||||
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
new LegacyBeatmapEncoder(beatmap).Encode(writer);
|
new LegacyBeatmapEncoder(beatmap, beatmapSkin).Encode(writer);
|
||||||
|
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
|
@ -15,8 +15,10 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
using osu.Game.Users;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using SharpCompress.Archives.Zip;
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
@ -32,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportWhenClosed()
|
public async Task TestImportWhenClosed()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenClosed)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -49,7 +51,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDelete()
|
public async Task TestImportThenDelete()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDelete)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -70,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenImport()
|
public async Task TestImportThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -96,7 +98,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithReZip()
|
public async Task TestImportThenImportWithReZip()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithReZip)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -154,7 +156,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithChangedFile()
|
public async Task TestImportThenImportWithChangedFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithChangedFile)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -205,7 +207,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithDifferentFilename()
|
public async Task TestImportThenImportWithDifferentFilename()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportWithDifferentFilename)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -257,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportCorruptThenImport()
|
public async Task TestImportCorruptThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportCorruptThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -299,7 +301,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestRollbackOnFailure()
|
public async Task TestRollbackOnFailure()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestRollbackOnFailure)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -376,7 +378,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDeleteThenImport()
|
public async Task TestImportThenDeleteThenImport()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDeleteThenImport)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -404,7 +406,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"{nameof(TestImportThenDeleteThenImportWithOnlineIDMismatch)}-{set}"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(set.ToString()))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -438,7 +440,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
public async Task TestImportWithDuplicateBeatmapIDs()
|
public async Task TestImportWithDuplicateBeatmapIDs()
|
||||||
{
|
{
|
||||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateBeatmapIDs)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -524,7 +526,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWhenFileOpen()
|
public async Task TestImportWhenFileOpen()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenFileOpen)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -546,7 +548,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDuplicateHashes()
|
public async Task TestImportWithDuplicateHashes()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateHashes)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -588,7 +590,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportNestedStructure()
|
public async Task TestImportNestedStructure()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -633,7 +635,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithIgnoredDirectoryInArchive()
|
public async Task TestImportWithIgnoredDirectoryInArchive()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithIgnoredDirectoryInArchive)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -687,7 +689,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapInfo()
|
public async Task TestUpdateBeatmapInfo()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapInfo)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -717,7 +719,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapFile()
|
public async Task TestUpdateBeatmapFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapFile)))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -756,6 +758,63 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCreateNewEmptyBeatmap()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
manager.Save(working.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
|
||||||
|
|
||||||
|
// Check that the new file is referenced correctly by attempting a retrieval
|
||||||
|
Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
|
||||||
|
Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCreateNewBeatmapWithObject()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
((Beatmap)working.Beatmap).HitObjects.Add(new HitCircle { StartTime = 5000 });
|
||||||
|
|
||||||
|
manager.Save(working.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
|
||||||
|
|
||||||
|
// Check that the new file is referenced correctly by attempting a retrieval
|
||||||
|
Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
|
||||||
|
Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(updatedBeatmap.HitObjects[0].StartTime, Is.EqualTo(5000));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
||||||
{
|
{
|
||||||
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||||
|
@ -351,7 +351,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
using (var encoded = new MemoryStream())
|
using (var encoded = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var sw = new StreamWriter(encoded))
|
using (var sw = new StreamWriter(encoded))
|
||||||
new LegacyBeatmapEncoder(beatmap).Encode(sw);
|
new LegacyBeatmapEncoder(beatmap, null).Encode(sw);
|
||||||
|
|
||||||
return encoded.ToArray();
|
return encoded.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestBasicImport()
|
public async Task TestBasicImport()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestBasicImport"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -66,7 +66,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportMods()
|
public async Task TestImportMods()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportMods"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportStatistics()
|
public async Task TestImportStatistics()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportStatistics"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDeletedBeatmapSet()
|
public async Task TestImportWithDeletedBeatmapSet()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWithDeletedBeatmapSet"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -159,7 +159,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestOnlineScoreIsAvailableLocally()
|
public async Task TestOnlineScoreIsAvailableLocally()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestOnlineScoreIsAvailableLocally"))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
54
osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs
Normal file
54
osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public class TestSceneOverlayActivation : OsuPlayerTestScene
|
||||||
|
{
|
||||||
|
protected new OverlayTestPlayer Player => base.Player as OverlayTestPlayer;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivation()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationPaused()
|
||||||
|
{
|
||||||
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("pause gameplay", () => Player.Pause());
|
||||||
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationReplayLoaded()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
||||||
|
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGameplayOverlayActivationBreaks()
|
||||||
|
{
|
||||||
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
||||||
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
||||||
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
||||||
|
|
||||||
|
protected class OverlayTestPlayer : TestPlayer
|
||||||
|
{
|
||||||
|
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
|
@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -14,6 +15,7 @@ using osu.Game.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,8 @@ using osu.Game.Online.API;
|
|||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
|
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -94,6 +96,34 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz";
|
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz";
|
||||||
|
|
||||||
|
public WorkingBeatmap CreateNew(RulesetInfo ruleset, User user)
|
||||||
|
{
|
||||||
|
var metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = "artist",
|
||||||
|
Title = "title",
|
||||||
|
Author = user,
|
||||||
|
};
|
||||||
|
|
||||||
|
var set = new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
Metadata = metadata,
|
||||||
|
Beatmaps = new List<BeatmapInfo>
|
||||||
|
{
|
||||||
|
new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty(),
|
||||||
|
Ruleset = ruleset,
|
||||||
|
Metadata = metadata,
|
||||||
|
Version = "difficulty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var working = Import(set).Result;
|
||||||
|
return GetWorkingBeatmap(working.Beatmaps.First());
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default)
|
protected override async Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (archive != null)
|
if (archive != null)
|
||||||
@ -198,24 +228,35 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
||||||
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
||||||
public void Save(BeatmapInfo info, IBeatmap beatmapContent)
|
/// <param name="beatmapSkin">The beatmap <see cref="ISkin"/> content to write, null if to be omitted.</param>
|
||||||
|
public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null)
|
||||||
{
|
{
|
||||||
var setInfo = QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == info.ID));
|
var setInfo = QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == info.ID));
|
||||||
|
|
||||||
using (var stream = new MemoryStream())
|
using (var stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
new LegacyBeatmapEncoder(beatmapContent).Encode(sw);
|
new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw);
|
||||||
|
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
using (ContextFactory.GetForWrite())
|
using (ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
var beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == info.ID);
|
var beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == info.ID);
|
||||||
|
var metadata = beatmapInfo.Metadata ?? setInfo.Metadata;
|
||||||
|
|
||||||
|
// grab the original file (or create a new one if not found).
|
||||||
|
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
|
||||||
|
|
||||||
|
// metadata may have changed; update the path with the standard format.
|
||||||
|
beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu";
|
||||||
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
||||||
|
|
||||||
|
// update existing or populate new file's filename.
|
||||||
|
fileInfo.Filename = beatmapInfo.Path;
|
||||||
|
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
UpdateFile(setInfo, setInfo.Files.Single(f => string.Equals(f.Filename, info.Path, StringComparison.OrdinalIgnoreCase)), stream);
|
UpdateFile(setInfo, fileInfo, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override IBeatmap GetBeatmap()
|
protected override IBeatmap GetBeatmap()
|
||||||
{
|
{
|
||||||
|
if (BeatmapInfo.Path == null)
|
||||||
|
return new Beatmap { BeatmapInfo = BeatmapInfo };
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
||||||
@ -67,6 +70,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Track GetBeatmapTrack()
|
protected override Track GetBeatmapTrack()
|
||||||
{
|
{
|
||||||
|
if (Metadata?.AudioFile == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return trackStore.Get(getPathForFile(Metadata.AudioFile));
|
return trackStore.Get(getPathForFile(Metadata.AudioFile));
|
||||||
@ -80,6 +86,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Waveform GetWaveform()
|
protected override Waveform GetWaveform()
|
||||||
{
|
{
|
||||||
|
if (Metadata?.AudioFile == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
||||||
|
@ -6,11 +6,13 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class BeatmapMetadata : IEquatable<BeatmapMetadata>, IHasPrimaryKey
|
public class BeatmapMetadata : IEquatable<BeatmapMetadata>, IHasPrimaryKey
|
||||||
{
|
{
|
||||||
|
@ -5,10 +5,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete, IEquatable<BeatmapSetInfo>
|
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete, IEquatable<BeatmapSetInfo>
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
@ -8,6 +8,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
public interface IHasCustomColours
|
public interface IHasCustomColours
|
||||||
{
|
{
|
||||||
Dictionary<string, Color4> CustomColours { get; set; }
|
Dictionary<string, Color4> CustomColours { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,16 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
{
|
{
|
||||||
@ -23,9 +26,18 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private readonly IBeatmap beatmap;
|
private readonly IBeatmap beatmap;
|
||||||
|
|
||||||
public LegacyBeatmapEncoder(IBeatmap beatmap)
|
[CanBeNull]
|
||||||
|
private readonly ISkin skin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="LegacyBeatmapEncoder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to encode.</param>
|
||||||
|
/// <param name="skin">The beatmap's skin, used for encoding combo colours.</param>
|
||||||
|
public LegacyBeatmapEncoder(IBeatmap beatmap, [CanBeNull] ISkin skin)
|
||||||
{
|
{
|
||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
|
this.skin = skin;
|
||||||
|
|
||||||
if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3)
|
if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3)
|
||||||
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
|
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
|
||||||
@ -53,6 +65,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
handleControlPoints(writer);
|
handleControlPoints(writer);
|
||||||
|
|
||||||
|
writer.WriteLine();
|
||||||
|
handleColours(writer);
|
||||||
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
handleHitObjects(writer);
|
handleHitObjects(writer);
|
||||||
}
|
}
|
||||||
@ -196,6 +211,28 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleColours(TextWriter writer)
|
||||||
|
{
|
||||||
|
var colours = skin?.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
|
||||||
|
|
||||||
|
if (colours == null || colours.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
writer.WriteLine("[Colours]");
|
||||||
|
|
||||||
|
for (var i = 0; i < colours.Count; i++)
|
||||||
|
{
|
||||||
|
var comboColour = colours[i];
|
||||||
|
|
||||||
|
writer.Write(FormattableString.Invariant($"Combo{i}: "));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.R * byte.MaxValue)},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.G * byte.MaxValue)},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.B * byte.MaxValue)},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.A * byte.MaxValue)}"));
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleHitObjects(TextWriter writer)
|
private void handleHitObjects(TextWriter writer)
|
||||||
{
|
{
|
||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -22,6 +23,7 @@ using osu.Game.Storyboards;
|
|||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public abstract class WorkingBeatmap : IWorkingBeatmap
|
public abstract class WorkingBeatmap : IWorkingBeatmap
|
||||||
{
|
{
|
||||||
public readonly BeatmapInfo BeatmapInfo;
|
public readonly BeatmapInfo BeatmapInfo;
|
||||||
@ -53,7 +55,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
const double excess_length = 1000;
|
const double excess_length = 1000;
|
||||||
|
|
||||||
var lastObject = Beatmap.HitObjects.LastOrDefault();
|
var lastObject = Beatmap?.HitObjects.LastOrDefault();
|
||||||
|
|
||||||
double length;
|
double length;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Configuration;
|
|||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -13,6 +14,7 @@ using osu.Game.Screens.Select.Filter;
|
|||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public class OsuConfigManager : IniConfigManager<OsuSetting>
|
public class OsuConfigManager : IniConfigManager<OsuSetting>
|
||||||
{
|
{
|
||||||
protected override void InitialiseDefaults()
|
protected override void InitialiseDefaults()
|
||||||
@ -231,6 +233,6 @@ namespace osu.Game.Configuration
|
|||||||
UIHoldActivationDelay,
|
UIHoldActivationDelay,
|
||||||
HitLighting,
|
HitLighting,
|
||||||
MenuBackgroundSource,
|
MenuBackgroundSource,
|
||||||
GameplayDisableWinKey
|
GameplayDisableWinKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,15 +397,24 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update an existing file, or create a new entry if not already part of the <paramref name="model"/>'s files.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The item to operate on.</param>
|
||||||
|
/// <param name="file">The file model to be updated or added.</param>
|
||||||
|
/// <param name="contents">The new file contents.</param>
|
||||||
public void UpdateFile(TModel model, TFileModel file, Stream contents)
|
public void UpdateFile(TModel model, TFileModel file, Stream contents)
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
// Dereference the existing file info, since the file model will be removed.
|
// Dereference the existing file info, since the file model will be removed.
|
||||||
Files.Dereference(file.FileInfo);
|
if (file.FileInfo != null)
|
||||||
|
{
|
||||||
|
Files.Dereference(file.FileInfo);
|
||||||
|
|
||||||
// Remove the file model.
|
// Remove the file model.
|
||||||
usage.Context.Set<TFileModel>().Remove(file);
|
usage.Context.Set<TFileModel>().Remove(file);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the new file info and containing file model.
|
// Add the new file info and containing file model.
|
||||||
model.Files.Remove(file);
|
model.Files.Remove(file);
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.StateChanges;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
@ -47,7 +48,10 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (!CanShowCursor)
|
var lastMouseSource = inputManager.CurrentState.Mouse.LastSource;
|
||||||
|
bool hasValidInput = lastMouseSource != null && !(lastMouseSource is ISourcedFromTouch);
|
||||||
|
|
||||||
|
if (!hasValidInput || !CanShowCursor)
|
||||||
{
|
{
|
||||||
currentTarget?.Cursor?.Hide();
|
currentTarget?.Cursor?.Hide();
|
||||||
currentTarget = null;
|
currentTarget = null;
|
||||||
|
@ -25,7 +25,13 @@ namespace osu.Game.IO
|
|||||||
this.subPath = subPath;
|
this.subPath = subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string MutatePath(string path) => !string.IsNullOrEmpty(subPath) ? Path.Combine(subPath, path) : path;
|
protected virtual string MutatePath(string path)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return !string.IsNullOrEmpty(subPath) ? Path.Combine(subPath, path) : path;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void ChangeTargetStorage(Storage newStorage)
|
protected virtual void ChangeTargetStorage(Storage newStorage)
|
||||||
{
|
{
|
||||||
|
25
osu.Game/Input/GameIdleTracker.cs
Normal file
25
osu.Game/Input/GameIdleTracker.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Input
|
||||||
|
{
|
||||||
|
public class GameIdleTracker : IdleTracker
|
||||||
|
{
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
|
public GameIdleTracker(int time)
|
||||||
|
: base(time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
inputManager = GetContainingInputManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool AllowIdle => inputManager.FocusedDrawable == null;
|
||||||
|
}
|
||||||
|
}
|
@ -720,24 +720,6 @@ namespace osu.Game
|
|||||||
overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime);
|
overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameIdleTracker : IdleTracker
|
|
||||||
{
|
|
||||||
private InputManager inputManager;
|
|
||||||
|
|
||||||
public GameIdleTracker(int time)
|
|
||||||
: base(time)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
inputManager = GetContainingInputManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool AllowIdle => inputManager.FocusedDrawable == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void forwardLoggedErrorsToNotifications()
|
private void forwardLoggedErrorsToNotifications()
|
||||||
{
|
{
|
||||||
int recentLogCount = 0;
|
int recentLogCount = 0;
|
||||||
@ -993,10 +975,4 @@ namespace osu.Game
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScorePresentType
|
|
||||||
{
|
|
||||||
Results,
|
|
||||||
Gameplay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
public BeatmapListingTitle()
|
public BeatmapListingTitle()
|
||||||
{
|
{
|
||||||
Title = "beatmap listing";
|
Title = "beatmap listing";
|
||||||
Description = "Browse for new beatmaps";
|
Description = "browse for new beatmaps";
|
||||||
IconTexture = "Icons/Hexacons/beatmap";
|
IconTexture = "Icons/Hexacons/beatmap";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
public ChangelogHeaderTitle()
|
public ChangelogHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "changelog";
|
Title = "changelog";
|
||||||
Description = "Track recent dev updates in the osu! ecosystem";
|
Description = "track recent dev updates in the osu! ecosystem";
|
||||||
IconTexture = "Icons/Hexacons/devtools";
|
IconTexture = "Icons/Hexacons/devtools";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public string IconTexture => "Icons/Hexacons/messaging";
|
public string IconTexture => "Icons/Hexacons/messaging";
|
||||||
public string Title => "chat";
|
public string Title => "chat";
|
||||||
public string Description => "Join the real-time discussion";
|
public string Description => "join the real-time discussion";
|
||||||
|
|
||||||
private const float textbox_height = 60;
|
private const float textbox_height = 60;
|
||||||
private const float channel_selection_min_height = 0.3f;
|
private const float channel_selection_min_height = 0.3f;
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
public DashboardTitle()
|
public DashboardTitle()
|
||||||
{
|
{
|
||||||
Title = "dashboard";
|
Title = "dashboard";
|
||||||
Description = "View your friends and other information";
|
Description = "view your friends and other information";
|
||||||
IconTexture = "Icons/Hexacons/social";
|
IconTexture = "Icons/Hexacons/social";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Overlays.News
|
|||||||
public NewsHeaderTitle()
|
public NewsHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "news";
|
Title = "news";
|
||||||
Description = "Get up-to-date on community happenings";
|
Description = "get up-to-date on community happenings";
|
||||||
IconTexture = "Icons/Hexacons/news";
|
IconTexture = "Icons/Hexacons/news";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ namespace osu.Game.Overlays
|
|||||||
public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
|
public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
|
||||||
{
|
{
|
||||||
public string IconTexture => "Icons/Hexacons/notification";
|
public string IconTexture => "Icons/Hexacons/notification";
|
||||||
public string Title => "Notifications";
|
public string Title => "notifications";
|
||||||
public string Description => "Waiting for 'ya";
|
public string Description => "waiting for 'ya";
|
||||||
|
|
||||||
private const float width = 320;
|
private const float width = 320;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public string IconTexture => "Icons/Hexacons/music";
|
public string IconTexture => "Icons/Hexacons/music";
|
||||||
public string Title => "now playing";
|
public string Title => "now playing";
|
||||||
public string Description => "Manage the currently playing track";
|
public string Description => "manage the currently playing track";
|
||||||
|
|
||||||
private const float player_height = 130;
|
private const float player_height = 130;
|
||||||
private const float transition_length = 800;
|
private const float transition_length = 800;
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Rankings
|
|||||||
public RankingsTitle()
|
public RankingsTitle()
|
||||||
{
|
{
|
||||||
Title = "ranking";
|
Title = "ranking";
|
||||||
Description = "Find out who's the best right now";
|
Description = "find out who's the best right now";
|
||||||
IconTexture = "Icons/Hexacons/rankings";
|
IconTexture = "Icons/Hexacons/rankings";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public string IconTexture => "Icons/Hexacons/settings";
|
public string IconTexture => "Icons/Hexacons/settings";
|
||||||
public string Title => "settings";
|
public string Title => "settings";
|
||||||
public string Description => "Change the way osu! behaves";
|
public string Description => "change the way osu! behaves";
|
||||||
|
|
||||||
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
|
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
|
||||||
{
|
{
|
||||||
|
@ -17,8 +17,8 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
TooltipMain = "Home";
|
TooltipMain = "home";
|
||||||
TooltipSub = "Return to the main menu";
|
TooltipSub = "return to the main menu";
|
||||||
SetIcon("Icons/Hexacons/home");
|
SetIcon("Icons/Hexacons/home");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
var rInstance = value.CreateInstance();
|
var rInstance = value.CreateInstance();
|
||||||
|
|
||||||
ruleset.TooltipMain = rInstance.Description;
|
ruleset.TooltipMain = rInstance.Description;
|
||||||
ruleset.TooltipSub = $"Play some {rInstance.Description}";
|
ruleset.TooltipSub = $"play some {rInstance.Description}";
|
||||||
ruleset.SetIcon(rInstance.CreateIcon());
|
ruleset.SetIcon(rInstance.CreateIcon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using System.Reflection;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -18,6 +19,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base class for gameplay modifiers.
|
/// The base class for gameplay modifiers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public abstract class Mod : IMod, IJsonSerializable
|
public abstract class Mod : IMod, IJsonSerializable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -23,10 +23,12 @@ using osu.Game.Scoring;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets
|
namespace osu.Game.Rulesets
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public abstract class Ruleset
|
public abstract class Ruleset
|
||||||
{
|
{
|
||||||
public RulesetInfo RulesetInfo { get; internal set; }
|
public RulesetInfo RulesetInfo { get; internal set; }
|
||||||
|
@ -5,9 +5,11 @@ using System;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets
|
namespace osu.Game.Rulesets
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public class RulesetInfo : IEquatable<RulesetInfo>
|
public class RulesetInfo : IEquatable<RulesetInfo>
|
||||||
{
|
{
|
||||||
public int? ID { get; set; }
|
public int? ID { get; set; }
|
||||||
|
@ -32,8 +32,6 @@ namespace osu.Game.Screens.Edit.Components.Menus
|
|||||||
Height = 1,
|
Height = 1,
|
||||||
Colour = Color4.White.Opacity(0.2f),
|
Colour = Color4.White.Opacity(0.2f),
|
||||||
});
|
});
|
||||||
|
|
||||||
Current.Value = EditorScreenMode.Compose;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -28,6 +28,7 @@ using osu.Framework.Logging;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osu.Game.Screens.Edit.Setup;
|
using osu.Game.Screens.Edit.Setup;
|
||||||
@ -72,6 +73,9 @@ namespace osu.Game.Screens.Edit
|
|||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, GameHost host)
|
private void load(OsuColour colours, GameHost host)
|
||||||
{
|
{
|
||||||
@ -89,6 +93,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
// todo: remove caching of this and consume via editorBeatmap?
|
// todo: remove caching of this and consume via editorBeatmap?
|
||||||
dependencies.Cache(beatDivisor);
|
dependencies.Cache(beatDivisor);
|
||||||
|
|
||||||
|
bool isNewBeatmap = false;
|
||||||
|
|
||||||
|
if (Beatmap.Value is DummyWorkingBeatmap)
|
||||||
|
{
|
||||||
|
isNewBeatmap = true;
|
||||||
|
Beatmap.Value = beatmapManager.CreateNew(Ruleset.Value, api.LocalUser.Value);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
||||||
@ -101,9 +113,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap));
|
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, Beatmap.Value.Skin));
|
||||||
dependencies.CacheAs(editorBeatmap);
|
dependencies.CacheAs(editorBeatmap);
|
||||||
|
|
||||||
changeHandler = new EditorChangeHandler(editorBeatmap);
|
changeHandler = new EditorChangeHandler(editorBeatmap);
|
||||||
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
|
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
|
||||||
|
|
||||||
@ -148,6 +159,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Mode = { Value = isNewBeatmap ? EditorScreenMode.SongSetup : EditorScreenMode.Compose },
|
||||||
Items = new[]
|
Items = new[]
|
||||||
{
|
{
|
||||||
new MenuItem("File")
|
new MenuItem("File")
|
||||||
@ -399,7 +411,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
clock.SeekForward(!clock.IsRunning, amount);
|
clock.SeekForward(!clock.IsRunning, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveBeatmap() => beatmapManager.Save(playableBeatmap.BeatmapInfo, editorBeatmap);
|
private void saveBeatmap()
|
||||||
|
{
|
||||||
|
// apply any set-level metadata changes.
|
||||||
|
beatmapManager.Update(playableBeatmap.BeatmapInfo.BeatmapSet);
|
||||||
|
|
||||||
|
// save the loaded beatmap's data stream.
|
||||||
|
beatmapManager.Save(playableBeatmap.BeatmapInfo, editorBeatmap, editorBeatmap.BeatmapSkin);
|
||||||
|
}
|
||||||
|
|
||||||
private void exportBeatmap()
|
private void exportBeatmap()
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
|||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit
|
namespace osu.Game.Screens.Edit
|
||||||
{
|
{
|
||||||
@ -47,6 +48,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
public readonly IBeatmap PlayableBeatmap;
|
public readonly IBeatmap PlayableBeatmap;
|
||||||
|
|
||||||
|
public readonly ISkin BeatmapSkin;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BindableBeatDivisor beatDivisor { get; set; }
|
private BindableBeatDivisor beatDivisor { get; set; }
|
||||||
|
|
||||||
@ -54,9 +57,10 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private readonly Dictionary<HitObject, Bindable<double>> startTimeBindables = new Dictionary<HitObject, Bindable<double>>();
|
private readonly Dictionary<HitObject, Bindable<double>> startTimeBindables = new Dictionary<HitObject, Bindable<double>>();
|
||||||
|
|
||||||
public EditorBeatmap(IBeatmap playableBeatmap)
|
public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null)
|
||||||
{
|
{
|
||||||
PlayableBeatmap = playableBeatmap;
|
PlayableBeatmap = playableBeatmap;
|
||||||
|
BeatmapSkin = beatmapSkin;
|
||||||
|
|
||||||
beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset?.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap);
|
beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset?.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap);
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
using (var stream = new MemoryStream())
|
using (var stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
new LegacyBeatmapEncoder(editorBeatmap).Encode(sw);
|
new LegacyBeatmapEncoder(editorBeatmap, editorBeatmap.BeatmapSkin).Encode(sw);
|
||||||
|
|
||||||
savedStates.Add(stream.ToArray());
|
savedStates.Add(stream.ToArray());
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Timing
|
namespace osu.Game.Screens.Edit.Timing
|
||||||
{
|
{
|
||||||
internal class TimingSection : Section<TimingControlPoint>
|
internal class TimingSection : Section<TimingControlPoint>
|
||||||
{
|
{
|
||||||
private SettingsSlider<double> bpm;
|
private SettingsSlider<double> bpmSlider;
|
||||||
private SettingsEnumDropdown<TimeSignatures> timeSignature;
|
private SettingsEnumDropdown<TimeSignatures> timeSignature;
|
||||||
|
private BPMTextBox bpmTextEntry;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Flow.AddRange(new Drawable[]
|
Flow.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
bpm = new BPMSlider
|
bpmTextEntry = new BPMTextBox(),
|
||||||
{
|
bpmSlider = new BPMSlider(),
|
||||||
Bindable = new TimingControlPoint().BeatLengthBindable,
|
|
||||||
LabelText = "BPM",
|
|
||||||
},
|
|
||||||
timeSignature = new SettingsEnumDropdown<TimeSignatures>
|
timeSignature = new SettingsEnumDropdown<TimeSignatures>
|
||||||
{
|
{
|
||||||
LabelText = "Time Signature"
|
LabelText = "Time Signature"
|
||||||
@ -36,7 +36,8 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
{
|
{
|
||||||
if (point.NewValue != null)
|
if (point.NewValue != null)
|
||||||
{
|
{
|
||||||
bpm.Bindable = point.NewValue.BeatLengthBindable;
|
bpmSlider.Bindable = point.NewValue.BeatLengthBindable;
|
||||||
|
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
||||||
timeSignature.Bindable = point.NewValue.TimeSignatureBindable;
|
timeSignature.Bindable = point.NewValue.TimeSignatureBindable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,34 +53,88 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BPMTextBox : LabelledTextBox
|
||||||
|
{
|
||||||
|
private readonly BindableNumber<double> beatLengthBindable = new TimingControlPoint().BeatLengthBindable;
|
||||||
|
|
||||||
|
public BPMTextBox()
|
||||||
|
{
|
||||||
|
Label = "BPM";
|
||||||
|
|
||||||
|
OnCommit += (val, isNew) =>
|
||||||
|
{
|
||||||
|
if (!isNew) return;
|
||||||
|
|
||||||
|
if (double.TryParse(Current.Value, out double doubleVal))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
beatLengthBindable.Value = beatLengthToBpm(doubleVal);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// will restore the previous text value on failure.
|
||||||
|
beatLengthBindable.TriggerChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beatLengthBindable.BindValueChanged(val =>
|
||||||
|
{
|
||||||
|
Current.Value = beatLengthToBpm(val.NewValue).ToString("N2");
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bindable<double> Bindable
|
||||||
|
{
|
||||||
|
get => beatLengthBindable;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// incoming will be beat length, not bpm
|
||||||
|
beatLengthBindable.UnbindBindings();
|
||||||
|
beatLengthBindable.BindTo(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class BPMSlider : SettingsSlider<double>
|
private class BPMSlider : SettingsSlider<double>
|
||||||
{
|
{
|
||||||
private readonly BindableDouble beatLengthBindable = new BindableDouble();
|
private const double sane_minimum = 60;
|
||||||
|
private const double sane_maximum = 240;
|
||||||
|
|
||||||
private BindableDouble bpmBindable;
|
private readonly BindableNumber<double> beatLengthBindable = new TimingControlPoint().BeatLengthBindable;
|
||||||
|
private readonly BindableDouble bpmBindable = new BindableDouble();
|
||||||
|
|
||||||
|
public BPMSlider()
|
||||||
|
{
|
||||||
|
beatLengthBindable.BindValueChanged(beatLength => updateCurrent(beatLengthToBpm(beatLength.NewValue)), true);
|
||||||
|
bpmBindable.BindValueChanged(bpm => bpmBindable.Default = beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
|
||||||
|
|
||||||
|
base.Bindable = bpmBindable;
|
||||||
|
}
|
||||||
|
|
||||||
public override Bindable<double> Bindable
|
public override Bindable<double> Bindable
|
||||||
{
|
{
|
||||||
get => base.Bindable;
|
get => base.Bindable;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
// incoming will be beatlength
|
// incoming will be beat length, not bpm
|
||||||
|
|
||||||
beatLengthBindable.UnbindBindings();
|
beatLengthBindable.UnbindBindings();
|
||||||
beatLengthBindable.BindTo(value);
|
beatLengthBindable.BindTo(value);
|
||||||
|
|
||||||
base.Bindable = bpmBindable = new BindableDouble(beatLengthToBpm(beatLengthBindable.Value))
|
|
||||||
{
|
|
||||||
MinValue = beatLengthToBpm(beatLengthBindable.MaxValue),
|
|
||||||
MaxValue = beatLengthToBpm(beatLengthBindable.MinValue),
|
|
||||||
Default = beatLengthToBpm(beatLengthBindable.Default),
|
|
||||||
};
|
|
||||||
|
|
||||||
bpmBindable.BindValueChanged(bpm => beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private double beatLengthToBpm(double beatLength) => 60000 / beatLength;
|
private void updateCurrent(double newValue)
|
||||||
|
{
|
||||||
|
// we use a more sane range for the slider display unless overridden by the user.
|
||||||
|
// if a value comes in outside our range, we should expand temporarily.
|
||||||
|
bpmBindable.MinValue = Math.Min(newValue, sane_minimum);
|
||||||
|
bpmBindable.MaxValue = Math.Max(newValue, sane_maximum);
|
||||||
|
|
||||||
|
bpmBindable.Value = newValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static double beatLengthToBpm(double beatLength) => 60000 / beatLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
"You can press Ctrl-T anywhere in the game to toggle the toolbar!",
|
"You can press Ctrl-T anywhere in the game to toggle the toolbar!",
|
||||||
"You can press Ctrl-O anywhere in the game to access options!",
|
"You can press Ctrl-O anywhere in the game to access options!",
|
||||||
"All settings are dynamic and take effect in real-time. Try changing the skin while playing!",
|
"All settings are dynamic and take effect in real-time. Try pausing and changing the skin while playing!",
|
||||||
"New features are coming online every update. Make sure to stay up-to-date!",
|
"New features are coming online every update. Make sure to stay up-to-date!",
|
||||||
"If you find the UI too large or small, try adjusting UI scale in settings!",
|
"If you find the UI too large or small, try adjusting UI scale in settings!",
|
||||||
"Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
|
"Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
|
||||||
|
@ -98,7 +98,11 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
buttons = new ButtonSystem
|
buttons = new ButtonSystem
|
||||||
{
|
{
|
||||||
OnEdit = delegate { this.Push(new Editor()); },
|
OnEdit = delegate
|
||||||
|
{
|
||||||
|
Beatmap.SetDefault();
|
||||||
|
this.Push(new Editor());
|
||||||
|
},
|
||||||
OnSolo = onSolo,
|
OnSolo = onSolo,
|
||||||
OnMulti = delegate { this.Push(new Multiplayer()); },
|
OnMulti = delegate { this.Push(new Multiplayer()); },
|
||||||
OnExit = confirmAndExit,
|
OnExit = confirmAndExit,
|
||||||
|
@ -203,6 +203,10 @@ namespace osu.Game.Screens.Play
|
|||||||
skipOverlay.Hide();
|
skipOverlay.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawableRuleset.IsPaused.BindValueChanged(_ => updateOverlayActivationMode());
|
||||||
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateOverlayActivationMode());
|
||||||
|
breakTracker.IsBreakTime.BindValueChanged(_ => updateOverlayActivationMode());
|
||||||
|
|
||||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
||||||
|
|
||||||
// bind clock into components that require it
|
// bind clock into components that require it
|
||||||
@ -347,6 +351,16 @@ namespace osu.Game.Screens.Play
|
|||||||
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
|
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateOverlayActivationMode()
|
||||||
|
{
|
||||||
|
bool canTriggerOverlays = DrawableRuleset.IsPaused.Value || breakTracker.IsBreakTime.Value;
|
||||||
|
|
||||||
|
if (DrawableRuleset.HasReplayLoaded.Value || canTriggerOverlays)
|
||||||
|
OverlayActivationMode.Value = OverlayActivation.UserTriggered;
|
||||||
|
else
|
||||||
|
OverlayActivationMode.Value = OverlayActivation.Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
private void updatePauseOnFocusLostState() =>
|
private void updatePauseOnFocusLostState() =>
|
||||||
HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost
|
HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost
|
||||||
&& !DrawableRuleset.HasReplayLoaded.Value
|
&& !DrawableRuleset.HasReplayLoaded.Value
|
||||||
@ -640,6 +654,8 @@ namespace osu.Game.Screens.Play
|
|||||||
musicController.ResetTrackAdjustments();
|
musicController.ResetTrackAdjustments();
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
||||||
mod.ApplyToTrack(musicController.CurrentTrack);
|
mod.ApplyToTrack(musicController.CurrentTrack);
|
||||||
|
|
||||||
|
updateOverlayActivationMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSuspending(IScreen next)
|
public override void OnSuspending(IScreen next)
|
||||||
|
11
osu.Game/Screens/ScorePresentType.cs
Normal file
11
osu.Game/Screens/ScorePresentType.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
namespace osu.Game.Screens
|
||||||
|
{
|
||||||
|
public enum ScorePresentType
|
||||||
|
{
|
||||||
|
Results,
|
||||||
|
Gameplay
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public readonly int Keys;
|
public readonly int Keys;
|
||||||
|
|
||||||
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
public Dictionary<string, Color4> CustomColours { get; } = new Dictionary<string, Color4>();
|
||||||
|
|
||||||
public Dictionary<string, string> ImageLookups = new Dictionary<string, string>();
|
public Dictionary<string, string> ImageLookups = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours);
|
public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours);
|
||||||
|
|
||||||
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
public Dictionary<string, Color4> CustomColours { get; } = new Dictionary<string, Color4>();
|
||||||
|
|
||||||
public readonly Dictionary<string, string> ConfigDictionary = new Dictionary<string, string>();
|
public readonly Dictionary<string, string> ConfigDictionary = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
|
||||||
namespace osu.Game.Tests
|
namespace osu.Game.Tests
|
||||||
@ -10,8 +11,15 @@ namespace osu.Game.Tests
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CleanRunHeadlessGameHost : HeadlessGameHost
|
public class CleanRunHeadlessGameHost : HeadlessGameHost
|
||||||
{
|
{
|
||||||
public CleanRunHeadlessGameHost(string gameName = @"", bool bindIPC = false, bool realtime = true)
|
/// <summary>
|
||||||
: base(gameName, bindIPC, realtime)
|
/// Create a new instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameSuffix">An optional suffix which will isolate this host from others called from the same method source.</param>
|
||||||
|
/// <param name="bindIPC">Whether to bind IPC channels.</param>
|
||||||
|
/// <param name="realtime">Whether the host should be forced to run in realtime, rather than accelerated test time.</param>
|
||||||
|
/// <param name="callingMethodName">The name of the calling method, used for test file isolation and clean-up.</param>
|
||||||
|
public CleanRunHeadlessGameHost(string gameSuffix = @"", bool bindIPC = false, bool realtime = true, [CallerMemberName] string callingMethodName = @"")
|
||||||
|
: base(callingMethodName + gameSuffix, bindIPC, realtime)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[ExcludeFromDynamicCompile]
|
||||||
public abstract class OsuTestScene : TestScene
|
public abstract class OsuTestScene : TestScene
|
||||||
{
|
{
|
||||||
protected Bindable<WorkingBeatmap> Beatmap { get; private set; }
|
protected Bindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.907.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
||||||
<PackageReference Include="Sentry" Version="2.1.6" />
|
<PackageReference Include="Sentry" Version="2.1.6" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.907.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.907.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user