mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:28:00 +08:00
Merge branch 'master' into catch-combo-counter
This commit is contained in:
commit
1e09d8fd1a
@ -38,7 +38,13 @@ If you are looking to install or test osu! without setting up a development envi
|
|||||||
|
|
||||||
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
||||||
|
|
||||||
## Developing or debugging
|
## Developing a custom ruleset
|
||||||
|
|
||||||
|
osu! is designed to have extensible modular gameplay modes, called "rulesets". Building one of these allows a developer to harness the power of osu! for their own game style. To get started working on a ruleset, we have some templates available [here](https://github.com/ppy/osu-templates).
|
||||||
|
|
||||||
|
You can see some examples of custom rulesets by visiting the [custom ruleset directory](https://github.com/ppy/osu/issues/5852).
|
||||||
|
|
||||||
|
## Developing osu!
|
||||||
|
|
||||||
Please make sure you have the following prerequisites:
|
Please make sure you have the following prerequisites:
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
|
|
||||||
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition);
|
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition);
|
||||||
|
|
||||||
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, IBeatmap beatmap)
|
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var positionData = obj as IHasXPosition;
|
var positionData = obj as IHasXPosition;
|
||||||
var comboData = obj as IHasCombo;
|
var comboData = obj as IHasCombo;
|
||||||
|
@ -5,6 +5,7 @@ using osu.Game.Rulesets.Mania.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
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;
|
||||||
@ -68,14 +69,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition);
|
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition);
|
||||||
|
|
||||||
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original)
|
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
||||||
|
|
||||||
int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate);
|
int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate);
|
||||||
Random = new FastRandom(seed);
|
Random = new FastRandom(seed);
|
||||||
|
|
||||||
return base.ConvertBeatmap(original);
|
return base.ConvertBeatmap(original, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Beatmap<ManiaHitObject> CreateBeatmap()
|
protected override Beatmap<ManiaHitObject> CreateBeatmap()
|
||||||
@ -88,7 +89,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
return beatmap;
|
return beatmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
|
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (original is ManiaHitObject maniaOriginal)
|
if (original is ManiaHitObject maniaOriginal)
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Game.Rulesets.Osu.Objects;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
|
|
||||||
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasPosition);
|
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasPosition);
|
||||||
|
|
||||||
protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
|
protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var positionData = original as IHasPosition;
|
var positionData = original as IHasPosition;
|
||||||
var comboData = original as IHasCombo;
|
var comboData = original as IHasCombo;
|
||||||
|
@ -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.Threading;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -48,14 +49,16 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
MaximumBonusSpins = (int)((maximum_rotations_per_second - minimumRotationsPerSecond) * secondsDuration);
|
MaximumBonusSpins = (int)((maximum_rotations_per_second - minimumRotationsPerSecond) * secondsDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateNestedHitObjects()
|
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
base.CreateNestedHitObjects();
|
base.CreateNestedHitObjects(cancellationToken);
|
||||||
|
|
||||||
int totalSpins = MaximumBonusSpins + SpinsRequired;
|
int totalSpins = MaximumBonusSpins + SpinsRequired;
|
||||||
|
|
||||||
for (int i = 0; i < totalSpins; i++)
|
for (int i = 0; i < totalSpins; i++)
|
||||||
{
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
double startTime = StartTime + (float)(i + 1) / totalSpins * Duration;
|
double startTime = StartTime + (float)(i + 1) / totalSpins * Duration;
|
||||||
|
|
||||||
AddNested(i < SpinsRequired
|
AddNested(i < SpinsRequired
|
||||||
|
@ -8,6 +8,8 @@ using osu.Game.Rulesets.Taiko.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using System.Threading;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
@ -48,14 +50,14 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
public override bool CanConvert() => true;
|
public override bool CanConvert() => true;
|
||||||
|
|
||||||
protected override Beatmap<TaikoHitObject> ConvertBeatmap(IBeatmap original)
|
protected override Beatmap<TaikoHitObject> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// Rewrite the beatmap info to add the slider velocity multiplier
|
// Rewrite the beatmap info to add the slider velocity multiplier
|
||||||
original.BeatmapInfo = original.BeatmapInfo.Clone();
|
original.BeatmapInfo = original.BeatmapInfo.Clone();
|
||||||
original.BeatmapInfo.BaseDifficulty = original.BeatmapInfo.BaseDifficulty.Clone();
|
original.BeatmapInfo.BaseDifficulty = original.BeatmapInfo.BaseDifficulty.Clone();
|
||||||
original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= LEGACY_VELOCITY_MULTIPLIER;
|
original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= LEGACY_VELOCITY_MULTIPLIER;
|
||||||
|
|
||||||
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
|
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken);
|
||||||
|
|
||||||
if (original.BeatmapInfo.RulesetID == 3)
|
if (original.BeatmapInfo.RulesetID == 3)
|
||||||
{
|
{
|
||||||
@ -72,7 +74,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, IBeatmap beatmap)
|
protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// Old osu! used hit sounding to determine various hit type information
|
// Old osu! used hit sounding to determine various hit type information
|
||||||
IList<HitSampleInfo> samples = obj.Samples;
|
IList<HitSampleInfo> samples = obj.Samples;
|
||||||
@ -104,6 +106,9 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
};
|
};
|
||||||
|
|
||||||
i = (i + 1) % allSamples.Count;
|
i = (i + 1) % allSamples.Count;
|
||||||
|
|
||||||
|
if (Precision.AlmostEquals(0, tickSpacing))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Difficulty.Utils;
|
using osu.Game.Rulesets.Difficulty.Utils;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
@ -67,6 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
// as that index can be simply subtracted from the current index to get the number of elements in between
|
// as that index can be simply subtracted from the current index to get the number of elements in between
|
||||||
// without off-by-one errors
|
// without off-by-one errors
|
||||||
int indexBeforeLastRepeat = -1;
|
int indexBeforeLastRepeat = -1;
|
||||||
|
int lastMarkEnd = 0;
|
||||||
|
|
||||||
for (int i = 0; i < hitObjects.Count; i++)
|
for (int i = 0; i < hitObjects.Count; i++)
|
||||||
{
|
{
|
||||||
@ -87,7 +89,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
if (repeatedLength < roll_min_repetitions)
|
if (repeatedLength < roll_min_repetitions)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
markObjectsAsCheese(i, repeatedLength);
|
markObjectsAsCheese(Math.Max(lastMarkEnd, i - repeatedLength + 1), i);
|
||||||
|
lastMarkEnd = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +116,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
private void findTlTap(int parity, HitType type)
|
private void findTlTap(int parity, HitType type)
|
||||||
{
|
{
|
||||||
int tlLength = -2;
|
int tlLength = -2;
|
||||||
|
int lastMarkEnd = 0;
|
||||||
|
|
||||||
for (int i = parity; i < hitObjects.Count; i += 2)
|
for (int i = parity; i < hitObjects.Count; i += 2)
|
||||||
{
|
{
|
||||||
@ -124,17 +128,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
if (tlLength < tl_min_repetitions)
|
if (tlLength < tl_min_repetitions)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
markObjectsAsCheese(i, tlLength);
|
markObjectsAsCheese(Math.Max(lastMarkEnd, i - tlLength + 1), i);
|
||||||
|
lastMarkEnd = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks <paramref name="count"/> elements counting backwards from <paramref name="end"/> as <see cref="TaikoDifficultyHitObject.StaminaCheese"/>.
|
/// Marks all objects from <paramref name="start"/> to <paramref name="end"/> (inclusive) as <see cref="TaikoDifficultyHitObject.StaminaCheese"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void markObjectsAsCheese(int end, int count)
|
private void markObjectsAsCheese(int start, int end)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = start; i <= end; i++)
|
||||||
hitObjects[end - i].StaminaCheese = true;
|
hitObjects[i].StaminaCheese = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,17 +28,17 @@ using FileInfo = System.IO.FileInfo;
|
|||||||
namespace osu.Game.Tests.Beatmaps.IO
|
namespace osu.Game.Tests.Beatmaps.IO
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ImportBeatmapTest
|
public class ImportBeatmapTest : ImportTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadOszIntoOsu(loadOsu(host));
|
await LoadOszIntoOsu(LoadOsuIntoHost(host));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -51,11 +51,11 @@ 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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
|
|
||||||
@ -72,11 +72,11 @@ 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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
var importedSecondTime = await LoadOszIntoOsu(osu);
|
var importedSecondTime = await LoadOszIntoOsu(osu);
|
||||||
@ -98,11 +98,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithReZip()
|
public async Task TestImportThenImportWithReZip()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -156,11 +156,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithChangedFile()
|
public async Task TestImportThenImportWithChangedFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -207,11 +207,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportThenImportWithDifferentFilename()
|
public async Task TestImportThenImportWithDifferentFilename()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -259,11 +259,11 @@ 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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
|
|
||||||
@ -301,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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -314,7 +314,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
Interlocked.Increment(ref loggedExceptionCount);
|
Interlocked.Increment(ref loggedExceptionCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
// ReSharper disable once AccessToModifiedClosure
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
@ -378,11 +378,11 @@ 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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
|
|
||||||
@ -406,11 +406,11 @@ 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(set.ToString()))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"{nameof(ImportBeatmapTest)}-{set}"))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var imported = await LoadOszIntoOsu(osu);
|
var imported = await LoadOszIntoOsu(osu);
|
||||||
|
|
||||||
@ -440,11 +440,11 @@ 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())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var metadata = new BeatmapMetadata
|
var metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
@ -496,15 +496,15 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Ignore("Binding IPC on Appveyor isn't working (port in use). Need to figure out why")]
|
[Ignore("Binding IPC on Appveyor isn't working (port in use). Need to figure out why")]
|
||||||
public void TestImportOverIPC()
|
public void TestImportOverIPC()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("host", true))
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"{nameof(ImportBeatmapTest)}-host", true))
|
||||||
using (HeadlessGameHost client = new CleanRunHeadlessGameHost("client", true))
|
using (HeadlessGameHost client = new CleanRunHeadlessGameHost($"{nameof(ImportBeatmapTest)}-client", true))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Assert.IsTrue(host.IsPrimaryInstance);
|
Assert.IsTrue(host.IsPrimaryInstance);
|
||||||
Assert.IsFalse(client.IsPrimaryInstance);
|
Assert.IsFalse(client.IsPrimaryInstance);
|
||||||
|
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -526,11 +526,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWhenFileOpen()
|
public async Task TestImportWhenFileOpen()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
using (File.OpenRead(temp))
|
using (File.OpenRead(temp))
|
||||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||||
@ -548,11 +548,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithDuplicateHashes()
|
public async Task TestImportWithDuplicateHashes()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -590,11 +590,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportNestedStructure()
|
public async Task TestImportNestedStructure()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -635,11 +635,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportWithIgnoredDirectoryInArchive()
|
public async Task TestImportWithIgnoredDirectoryInArchive()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
@ -689,11 +689,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapInfo()
|
public async Task TestUpdateBeatmapInfo()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
@ -719,11 +719,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task TestUpdateBeatmapFile()
|
public async Task TestUpdateBeatmapFile()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
var temp = TestResources.GetTestBeatmapForImport();
|
var temp = TestResources.GetTestBeatmapForImport();
|
||||||
@ -761,11 +761,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCreateNewEmptyBeatmap()
|
public void TestCreateNewEmptyBeatmap()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
@ -788,11 +788,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCreateNewBeatmapWithObject()
|
public void TestCreateNewBeatmapWithObject()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
@ -863,14 +863,6 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
Assert.AreEqual(expected, osu.Dependencies.Get<FileStore>().QueryFiles(f => f.ReferenceCount == 1).Count());
|
Assert.AreEqual(expected, osu.Dependencies.Get<FileStore>().QueryFiles(f => f.ReferenceCount == 1).Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
private OsuGameBase loadOsu(GameHost host)
|
|
||||||
{
|
|
||||||
var osu = new OsuGameBase();
|
|
||||||
Task.Run(() => host.Run(osu));
|
|
||||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
|
||||||
return osu;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
||||||
{
|
{
|
||||||
IEnumerable<BeatmapSetInfo> resultSets = null;
|
IEnumerable<BeatmapSetInfo> resultSets = null;
|
||||||
|
@ -4,18 +4,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Collections;
|
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Collections.IO
|
namespace osu.Game.Tests.Collections.IO
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ImportCollectionsTest
|
public class ImportCollectionsTest : ImportTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public async Task TestImportEmptyDatabase()
|
public async Task TestImportEmptyDatabase()
|
||||||
@ -24,7 +21,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(new MemoryStream());
|
await osu.CollectionManager.Import(new MemoryStream());
|
||||||
|
|
||||||
@ -44,7 +41,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
||||||
|
|
||||||
@ -70,7 +67,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host, true);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
||||||
|
|
||||||
@ -101,7 +98,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
AppDomain.CurrentDomain.UnhandledException += setException;
|
AppDomain.CurrentDomain.UnhandledException += setException;
|
||||||
|
|
||||||
var osu = loadOsu(host, true);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
@ -135,7 +132,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host, true);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
||||||
|
|
||||||
@ -156,7 +153,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host, true);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
|
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
|
||||||
|
|
||||||
@ -172,50 +169,5 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestOsuGameBase loadOsu(GameHost host, bool withBeatmap = false)
|
|
||||||
{
|
|
||||||
var osu = new TestOsuGameBase(withBeatmap);
|
|
||||||
|
|
||||||
#pragma warning disable 4014
|
|
||||||
Task.Run(() => host.Run(osu));
|
|
||||||
#pragma warning restore 4014
|
|
||||||
|
|
||||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
|
||||||
|
|
||||||
return osu;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
|
|
||||||
{
|
|
||||||
Task task = Task.Run(() =>
|
|
||||||
{
|
|
||||||
while (!result()) Thread.Sleep(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestOsuGameBase : OsuGameBase
|
|
||||||
{
|
|
||||||
public CollectionManager CollectionManager { get; private set; }
|
|
||||||
|
|
||||||
private readonly bool withBeatmap;
|
|
||||||
|
|
||||||
public TestOsuGameBase(bool withBeatmap)
|
|
||||||
{
|
|
||||||
this.withBeatmap = withBeatmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
// Beatmap must be imported before the collection manager is loaded.
|
|
||||||
if (withBeatmap)
|
|
||||||
BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
|
||||||
|
|
||||||
AddInternal(CollectionManager = new CollectionManager(Storage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
osu.Game.Tests/ImportTest.cs
Normal file
66
osu.Game.Tests/ImportTest.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// 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;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.Collections;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests
|
||||||
|
{
|
||||||
|
public abstract class ImportTest
|
||||||
|
{
|
||||||
|
protected virtual TestOsuGameBase LoadOsuIntoHost(GameHost host, bool withBeatmap = false)
|
||||||
|
{
|
||||||
|
var osu = new TestOsuGameBase(withBeatmap);
|
||||||
|
Task.Run(() => host.Run(osu));
|
||||||
|
|
||||||
|
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
||||||
|
|
||||||
|
bool ready = false;
|
||||||
|
// wait for two update frames to be executed. this ensures that all components have had a change to run LoadComplete and hopefully avoid
|
||||||
|
// database access (GlobalActionContainer is one to do this).
|
||||||
|
host.UpdateThread.Scheduler.Add(() => host.UpdateThread.Scheduler.Add(() => ready = true));
|
||||||
|
|
||||||
|
waitForOrAssert(() => ready, @"osu! failed to start in a reasonable amount of time");
|
||||||
|
|
||||||
|
return osu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
|
||||||
|
{
|
||||||
|
Task task = Task.Run(() =>
|
||||||
|
{
|
||||||
|
while (!result()) Thread.Sleep(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestOsuGameBase : OsuGameBase
|
||||||
|
{
|
||||||
|
public CollectionManager CollectionManager { get; private set; }
|
||||||
|
|
||||||
|
private readonly bool withBeatmap;
|
||||||
|
|
||||||
|
public TestOsuGameBase(bool withBeatmap)
|
||||||
|
{
|
||||||
|
this.withBeatmap = withBeatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
// Beatmap must be imported before the collection manager is loaded.
|
||||||
|
if (withBeatmap)
|
||||||
|
BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
||||||
|
|
||||||
|
AddInternal(CollectionManager = new CollectionManager(Storage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,8 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -17,18 +16,18 @@ using osu.Game.IO;
|
|||||||
namespace osu.Game.Tests.NonVisual
|
namespace osu.Game.Tests.NonVisual
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CustomDataDirectoryTest
|
public class CustomDataDirectoryTest : ImportTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDefaultDirectory()
|
public void TestDefaultDirectory()
|
||||||
{
|
{
|
||||||
using (HeadlessGameHost host = new CustomTestHeadlessGameHost(nameof(TestDefaultDirectory)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string defaultStorageLocation = getDefaultLocationFor(nameof(TestDefaultDirectory));
|
string defaultStorageLocation = getDefaultLocationFor(nameof(TestDefaultDirectory));
|
||||||
|
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var storage = osu.Dependencies.Get<Storage>();
|
var storage = osu.Dependencies.Get<Storage>();
|
||||||
|
|
||||||
Assert.That(storage.GetFullPath("."), Is.EqualTo(defaultStorageLocation));
|
Assert.That(storage.GetFullPath("."), Is.EqualTo(defaultStorageLocation));
|
||||||
@ -45,14 +44,14 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
|
|
||||||
using (var host = new CustomTestHeadlessGameHost(nameof(TestCustomDirectory)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
|
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
|
||||||
storageConfig.Set(StorageConfig.FullPath, customPath);
|
storageConfig.Set(StorageConfig.FullPath, customPath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
// switch to DI'd storage
|
// switch to DI'd storage
|
||||||
var storage = osu.Dependencies.Get<Storage>();
|
var storage = osu.Dependencies.Get<Storage>();
|
||||||
@ -71,14 +70,14 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
|
|
||||||
using (var host = new CustomTestHeadlessGameHost(nameof(TestSubDirectoryLookup)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
|
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
|
||||||
storageConfig.Set(StorageConfig.FullPath, customPath);
|
storageConfig.Set(StorageConfig.FullPath, customPath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
// switch to DI'd storage
|
// switch to DI'd storage
|
||||||
var storage = osu.Dependencies.Get<Storage>();
|
var storage = osu.Dependencies.Get<Storage>();
|
||||||
@ -104,13 +103,13 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
|
|
||||||
using (HeadlessGameHost host = new CustomTestHeadlessGameHost(nameof(TestMigration)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string defaultStorageLocation = getDefaultLocationFor(nameof(TestMigration));
|
string defaultStorageLocation = getDefaultLocationFor(nameof(TestMigration));
|
||||||
|
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
var storage = osu.Dependencies.Get<Storage>();
|
var storage = osu.Dependencies.Get<Storage>();
|
||||||
|
|
||||||
// Store the current storage's path. We'll need to refer to this for assertions in the original directory after the migration completes.
|
// Store the current storage's path. We'll need to refer to this for assertions in the original directory after the migration completes.
|
||||||
@ -165,11 +164,11 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
string customPath2 = prepareCustomPath("-2");
|
string customPath2 = prepareCustomPath("-2");
|
||||||
|
|
||||||
using (HeadlessGameHost host = new CustomTestHeadlessGameHost(nameof(TestMigrationBetweenTwoTargets)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
const string database_filename = "client.db";
|
const string database_filename = "client.db";
|
||||||
|
|
||||||
@ -194,11 +193,11 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
|
|
||||||
using (HeadlessGameHost host = new CustomTestHeadlessGameHost(nameof(TestMigrationToSameTargetFails)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
Assert.DoesNotThrow(() => osu.Migrate(customPath));
|
Assert.DoesNotThrow(() => osu.Migrate(customPath));
|
||||||
Assert.Throws<ArgumentException>(() => osu.Migrate(customPath));
|
Assert.Throws<ArgumentException>(() => osu.Migrate(customPath));
|
||||||
@ -215,11 +214,11 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
|
|
||||||
using (HeadlessGameHost host = new CustomTestHeadlessGameHost(nameof(TestMigrationToNestedTargetFails)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
Assert.DoesNotThrow(() => osu.Migrate(customPath));
|
Assert.DoesNotThrow(() => osu.Migrate(customPath));
|
||||||
|
|
||||||
@ -244,11 +243,11 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
string customPath = prepareCustomPath();
|
string customPath = prepareCustomPath();
|
||||||
|
|
||||||
using (HeadlessGameHost host = new CustomTestHeadlessGameHost(nameof(TestMigrationToSeeminglyNestedTarget)))
|
using (var host = new CustomTestHeadlessGameHost())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
Assert.DoesNotThrow(() => osu.Migrate(customPath));
|
Assert.DoesNotThrow(() => osu.Migrate(customPath));
|
||||||
|
|
||||||
@ -268,25 +267,6 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OsuGameBase loadOsu(GameHost host)
|
|
||||||
{
|
|
||||||
var osu = new OsuGameBase();
|
|
||||||
Task.Run(() => host.Run(osu));
|
|
||||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
|
||||||
|
|
||||||
return osu;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
|
|
||||||
{
|
|
||||||
Task task = Task.Run(() =>
|
|
||||||
{
|
|
||||||
while (!result()) Thread.Sleep(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string getDefaultLocationFor(string testTypeName)
|
private static string getDefaultLocationFor(string testTypeName)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(RuntimeInfo.StartupDirectory, "headless", testTypeName);
|
string path = Path.Combine(RuntimeInfo.StartupDirectory, "headless", testTypeName);
|
||||||
@ -307,14 +287,14 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CustomTestHeadlessGameHost : HeadlessGameHost
|
public class CustomTestHeadlessGameHost : CleanRunHeadlessGameHost
|
||||||
{
|
{
|
||||||
public Storage InitialStorage { get; }
|
public Storage InitialStorage { get; }
|
||||||
|
|
||||||
public CustomTestHeadlessGameHost(string name)
|
public CustomTestHeadlessGameHost([CallerMemberName] string callingMethodName = @"")
|
||||||
: base(name)
|
: base(callingMethodName: callingMethodName)
|
||||||
{
|
{
|
||||||
string defaultStorageLocation = getDefaultLocationFor(name);
|
string defaultStorageLocation = getDefaultLocationFor(callingMethodName);
|
||||||
|
|
||||||
InitialStorage = new DesktopStorage(defaultStorageLocation, this);
|
InitialStorage = new DesktopStorage(defaultStorageLocation, this);
|
||||||
InitialStorage.DeleteDirectory(string.Empty);
|
InitialStorage.DeleteDirectory(string.Empty);
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -17,12 +16,11 @@ using osu.Game.Rulesets.Osu;
|
|||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Tests.Resources;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Scores.IO
|
namespace osu.Game.Tests.Scores.IO
|
||||||
{
|
{
|
||||||
public class ImportScoreTest
|
public class ImportScoreTest : ImportTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public async Task TestBasicImport()
|
public async Task TestBasicImport()
|
||||||
@ -31,7 +29,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = await loadOsu(host);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
var toImport = new ScoreInfo
|
var toImport = new ScoreInfo
|
||||||
{
|
{
|
||||||
@ -45,7 +43,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
OnlineScoreID = 12345,
|
OnlineScoreID = 12345,
|
||||||
};
|
};
|
||||||
|
|
||||||
var imported = await loadIntoOsu(osu, toImport);
|
var imported = await loadScoreIntoOsu(osu, toImport);
|
||||||
|
|
||||||
Assert.AreEqual(toImport.Rank, imported.Rank);
|
Assert.AreEqual(toImport.Rank, imported.Rank);
|
||||||
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
|
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
|
||||||
@ -70,14 +68,14 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = await loadOsu(host);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
var toImport = new ScoreInfo
|
var toImport = new ScoreInfo
|
||||||
{
|
{
|
||||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||||
};
|
};
|
||||||
|
|
||||||
var imported = await loadIntoOsu(osu, toImport);
|
var imported = await loadScoreIntoOsu(osu, toImport);
|
||||||
|
|
||||||
Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock));
|
Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock));
|
||||||
Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime));
|
Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime));
|
||||||
@ -96,7 +94,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = await loadOsu(host);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
var toImport = new ScoreInfo
|
var toImport = new ScoreInfo
|
||||||
{
|
{
|
||||||
@ -107,7 +105,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var imported = await loadIntoOsu(osu, toImport);
|
var imported = await loadScoreIntoOsu(osu, toImport);
|
||||||
|
|
||||||
Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]);
|
Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]);
|
||||||
Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]);
|
Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]);
|
||||||
@ -126,7 +124,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = await loadOsu(host);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
var toImport = new ScoreInfo
|
var toImport = new ScoreInfo
|
||||||
{
|
{
|
||||||
@ -138,7 +136,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var imported = await loadIntoOsu(osu, toImport);
|
var imported = await loadScoreIntoOsu(osu, toImport);
|
||||||
|
|
||||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||||
@ -146,7 +144,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
beatmapManager.Delete(beatmapManager.QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == imported.Beatmap.ID)));
|
beatmapManager.Delete(beatmapManager.QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == imported.Beatmap.ID)));
|
||||||
Assert.That(scoreManager.Query(s => s.ID == imported.ID).DeletePending, Is.EqualTo(true));
|
Assert.That(scoreManager.Query(s => s.ID == imported.ID).DeletePending, Is.EqualTo(true));
|
||||||
|
|
||||||
var secondImport = await loadIntoOsu(osu, imported);
|
var secondImport = await loadScoreIntoOsu(osu, imported);
|
||||||
Assert.That(secondImport, Is.Null);
|
Assert.That(secondImport, Is.Null);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -163,9 +161,9 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = await loadOsu(host);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
await loadIntoOsu(osu, new ScoreInfo { OnlineScoreID = 2 }, new TestArchiveReader());
|
await loadScoreIntoOsu(osu, new ScoreInfo { OnlineScoreID = 2 }, new TestArchiveReader());
|
||||||
|
|
||||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||||
|
|
||||||
@ -179,7 +177,7 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ScoreInfo> loadIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
|
private async Task<ScoreInfo> loadScoreIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
|
||||||
{
|
{
|
||||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
@ -192,33 +190,6 @@ namespace osu.Game.Tests.Scores.IO
|
|||||||
return scoreManager.GetAllUsableScores().FirstOrDefault();
|
return scoreManager.GetAllUsableScores().FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<OsuGameBase> loadOsu(GameHost host)
|
|
||||||
{
|
|
||||||
var osu = new OsuGameBase();
|
|
||||||
|
|
||||||
#pragma warning disable 4014
|
|
||||||
Task.Run(() => host.Run(osu));
|
|
||||||
#pragma warning restore 4014
|
|
||||||
|
|
||||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
|
||||||
|
|
||||||
var beatmapFile = TestResources.GetTestBeatmapForImport();
|
|
||||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
|
||||||
await beatmapManager.Import(beatmapFile);
|
|
||||||
|
|
||||||
return osu;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
|
|
||||||
{
|
|
||||||
Task task = Task.Run(() =>
|
|
||||||
{
|
|
||||||
while (!result()) Thread.Sleep(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestArchiveReader : ArchiveReader
|
private class TestArchiveReader : ArchiveReader
|
||||||
{
|
{
|
||||||
public TestArchiveReader()
|
public TestArchiveReader()
|
||||||
|
147
osu.Game.Tests/Skins/IO/ImportSkinTest.cs
Normal file
147
osu.Game.Tests/Skins/IO/ImportSkinTest.cs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// 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;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.IO.Archives;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Skins.IO
|
||||||
|
{
|
||||||
|
public class ImportSkinTest : ImportTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task TestBasicImport()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
|
var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin.osk"));
|
||||||
|
|
||||||
|
Assert.That(imported.Name, Is.EqualTo("test skin"));
|
||||||
|
Assert.That(imported.Creator, Is.EqualTo("skinner"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestImportTwiceWithSameMetadata()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
|
var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin.osk"));
|
||||||
|
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin2.osk"));
|
||||||
|
|
||||||
|
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// the first should be overwritten by the second import.
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestImportTwiceWithNoMetadata()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
|
// if a user downloads two skins that do have skin.ini files but don't have any creator metadata in the skin.ini, they should both import separately just for safety.
|
||||||
|
var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk"));
|
||||||
|
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk"));
|
||||||
|
|
||||||
|
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(2));
|
||||||
|
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestImportTwiceWithDifferentMetadata()
|
||||||
|
{
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
|
var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2", "skinner"), "skin.osk"));
|
||||||
|
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2.1", "skinner"), "skin2.osk"));
|
||||||
|
|
||||||
|
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(2));
|
||||||
|
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||||
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryStream createOsk(string name, string author)
|
||||||
|
{
|
||||||
|
var zipStream = new MemoryStream();
|
||||||
|
using var zip = ZipArchive.Create();
|
||||||
|
zip.AddEntry("skin.ini", generateSkinIni(name, author));
|
||||||
|
zip.SaveTo(zipStream);
|
||||||
|
return zipStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryStream generateSkinIni(string name, string author)
|
||||||
|
{
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
var writer = new StreamWriter(stream);
|
||||||
|
|
||||||
|
writer.WriteLine("[General]");
|
||||||
|
writer.WriteLine($"Name: {name}");
|
||||||
|
writer.WriteLine($"Author: {author}");
|
||||||
|
writer.WriteLine();
|
||||||
|
writer.WriteLine($"# unique {Guid.NewGuid()}");
|
||||||
|
|
||||||
|
writer.Flush();
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SkinInfo> loadSkinIntoOsu(OsuGameBase osu, ArchiveReader archive = null)
|
||||||
|
{
|
||||||
|
var skinManager = osu.Dependencies.Get<SkinManager>();
|
||||||
|
return await skinManager.Import(archive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,27 +22,16 @@ namespace osu.Game.Tests.Visual.Collections
|
|||||||
{
|
{
|
||||||
public class TestSceneManageCollectionsDialog : OsuManualInputManagerTestScene
|
public class TestSceneManageCollectionsDialog : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
private readonly Container content;
|
private DialogOverlay dialogOverlay;
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private CollectionManager manager;
|
||||||
private readonly CollectionManager manager;
|
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
private BeatmapManager beatmapManager;
|
private BeatmapManager beatmapManager;
|
||||||
|
|
||||||
private ManageCollectionsDialog dialog;
|
private ManageCollectionsDialog dialog;
|
||||||
|
|
||||||
public TestSceneManageCollectionsDialog()
|
|
||||||
{
|
|
||||||
base.Content.AddRange(new Drawable[]
|
|
||||||
{
|
|
||||||
manager = new CollectionManager(LocalStorage),
|
|
||||||
content = new Container { RelativeSizeAxes = Axes.Both },
|
|
||||||
dialogOverlay = new DialogOverlay()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host)
|
private void load(GameHost host)
|
||||||
{
|
{
|
||||||
@ -50,14 +39,16 @@ namespace osu.Game.Tests.Visual.Collections
|
|||||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default));
|
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default));
|
||||||
|
|
||||||
beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
base.Content.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
manager = new CollectionManager(LocalStorage),
|
||||||
dependencies.Cache(manager);
|
Content,
|
||||||
dependencies.Cache(dialogOverlay);
|
dialogOverlay = new DialogOverlay()
|
||||||
return dependencies;
|
});
|
||||||
|
|
||||||
|
Dependencies.Cache(manager);
|
||||||
|
Dependencies.Cache(dialogOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -276,7 +277,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public override bool CanConvert() => true;
|
public override bool CanConvert() => true;
|
||||||
|
|
||||||
protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
|
protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
yield return new TestHitObject
|
yield return new TestHitObject
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineBeatmapID = beatmapId,
|
||||||
Path = "normal.osu",
|
|
||||||
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||||
Length = length,
|
Length = length,
|
||||||
BPM = bpm,
|
BPM = bpm,
|
||||||
|
@ -34,6 +34,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
protected TestOsuGame Game;
|
protected TestOsuGame Game;
|
||||||
|
|
||||||
|
protected override bool UseFreshStoragePerRun => true;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host)
|
private void load(GameHost host)
|
||||||
{
|
{
|
||||||
|
@ -74,6 +74,13 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
private void returnToMenu()
|
private void returnToMenu()
|
||||||
{
|
{
|
||||||
|
// if we don't pause, there's a chance the track may change at the main menu out of our control (due to reaching the end of the track).
|
||||||
|
AddStep("pause audio", () =>
|
||||||
|
{
|
||||||
|
if (Game.MusicController.IsPlaying)
|
||||||
|
Game.MusicController.TogglePause();
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
||||||
AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,13 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
private void returnToMenu()
|
private void returnToMenu()
|
||||||
{
|
{
|
||||||
|
// if we don't pause, there's a chance the track may change at the main menu out of our control (due to reaching the end of the track).
|
||||||
|
AddStep("pause audio", () =>
|
||||||
|
{
|
||||||
|
if (Game.MusicController.IsPlaying)
|
||||||
|
Game.MusicController.TogglePause();
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
||||||
AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||||
}
|
}
|
||||||
|
@ -839,7 +839,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = id * 10,
|
OnlineBeatmapID = id * 10,
|
||||||
Path = "normal.osu",
|
|
||||||
Version = "Normal",
|
Version = "Normal",
|
||||||
StarDifficulty = 2,
|
StarDifficulty = 2,
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
BaseDifficulty = new BeatmapDifficulty
|
||||||
@ -850,7 +849,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = id * 10 + 1,
|
OnlineBeatmapID = id * 10 + 1,
|
||||||
Path = "hard.osu",
|
|
||||||
Version = "Hard",
|
Version = "Hard",
|
||||||
StarDifficulty = 5,
|
StarDifficulty = 5,
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
BaseDifficulty = new BeatmapDifficulty
|
||||||
@ -861,7 +859,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
new BeatmapInfo
|
new BeatmapInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = id * 10 + 2,
|
OnlineBeatmapID = id * 10 + 2,
|
||||||
Path = "insane.osu",
|
|
||||||
Version = "Insane",
|
Version = "Insane",
|
||||||
StarDifficulty = 6,
|
StarDifficulty = 6,
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
BaseDifficulty = new BeatmapDifficulty
|
||||||
|
@ -23,25 +23,15 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
public class TestSceneFilterControl : OsuManualInputManagerTestScene
|
public class TestSceneFilterControl : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
private readonly Container content;
|
|
||||||
|
|
||||||
private readonly CollectionManager collectionManager;
|
private CollectionManager collectionManager;
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
private BeatmapManager beatmapManager;
|
private BeatmapManager beatmapManager;
|
||||||
|
|
||||||
private FilterControl control;
|
private FilterControl control;
|
||||||
|
|
||||||
public TestSceneFilterControl()
|
|
||||||
{
|
|
||||||
base.Content.AddRange(new Drawable[]
|
|
||||||
{
|
|
||||||
collectionManager = new CollectionManager(LocalStorage),
|
|
||||||
content = new Container { RelativeSizeAxes = Axes.Both }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host)
|
private void load(GameHost host)
|
||||||
{
|
{
|
||||||
@ -49,13 +39,14 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default));
|
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default));
|
||||||
|
|
||||||
beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
base.Content.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
collectionManager = new CollectionManager(LocalStorage),
|
||||||
dependencies.Cache(collectionManager);
|
Content
|
||||||
return dependencies;
|
});
|
||||||
|
|
||||||
|
Dependencies.Cache(collectionManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -879,7 +879,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
Ruleset = getRuleset(),
|
Ruleset = getRuleset(),
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineBeatmapID = beatmapId,
|
||||||
Path = "normal.osu",
|
|
||||||
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||||
Length = length,
|
Length = length,
|
||||||
BPM = bpm,
|
BPM = bpm,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -26,6 +27,8 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public IBeatmap Beatmap { get; }
|
public IBeatmap Beatmap { get; }
|
||||||
|
|
||||||
|
private CancellationToken cancellationToken;
|
||||||
|
|
||||||
protected BeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
|
protected BeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
@ -36,14 +39,25 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract bool CanConvert();
|
public abstract bool CanConvert();
|
||||||
|
|
||||||
/// <summary>
|
public IBeatmap Convert(CancellationToken cancellationToken = default)
|
||||||
/// Converts <see cref="Beatmap"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The converted Beatmap.</returns>
|
|
||||||
public IBeatmap Convert()
|
|
||||||
{
|
{
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
// We always operate on a clone of the original beatmap, to not modify it game-wide
|
// We always operate on a clone of the original beatmap, to not modify it game-wide
|
||||||
return ConvertBeatmap(Beatmap.Clone());
|
return ConvertBeatmap(Beatmap.Clone(), cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the conversion of a Beatmap using this Beatmap Converter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="original">The un-converted Beatmap.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>The converted Beatmap.</returns>
|
||||||
|
protected virtual Beatmap<T> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
#pragma warning disable 618
|
||||||
|
return ConvertBeatmap(original);
|
||||||
|
#pragma warning restore 618
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -51,19 +65,20 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="original">The un-converted Beatmap.</param>
|
/// <param name="original">The un-converted Beatmap.</param>
|
||||||
/// <returns>The converted Beatmap.</returns>
|
/// <returns>The converted Beatmap.</returns>
|
||||||
|
[Obsolete("Use the cancellation-supporting override")] // Can be removed 20210318
|
||||||
protected virtual Beatmap<T> ConvertBeatmap(IBeatmap original)
|
protected virtual Beatmap<T> ConvertBeatmap(IBeatmap original)
|
||||||
{
|
{
|
||||||
var beatmap = CreateBeatmap();
|
var beatmap = CreateBeatmap();
|
||||||
|
|
||||||
beatmap.BeatmapInfo = original.BeatmapInfo;
|
beatmap.BeatmapInfo = original.BeatmapInfo;
|
||||||
beatmap.ControlPointInfo = original.ControlPointInfo;
|
beatmap.ControlPointInfo = original.ControlPointInfo;
|
||||||
beatmap.HitObjects = convertHitObjects(original.HitObjects, original).OrderBy(s => s.StartTime).ToList();
|
beatmap.HitObjects = convertHitObjects(original.HitObjects, original, cancellationToken).OrderBy(s => s.StartTime).ToList();
|
||||||
beatmap.Breaks = original.Breaks;
|
beatmap.Breaks = original.Breaks;
|
||||||
|
|
||||||
return beatmap;
|
return beatmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<T> convertHitObjects(IReadOnlyList<HitObject> hitObjects, IBeatmap beatmap)
|
private List<T> convertHitObjects(IReadOnlyList<HitObject> hitObjects, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = new List<T>(hitObjects.Count);
|
var result = new List<T>(hitObjects.Count);
|
||||||
|
|
||||||
@ -75,7 +90,7 @@ namespace osu.Game.Beatmaps
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var converted = ConvertHitObject(obj, beatmap);
|
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
|
||||||
|
|
||||||
if (ObjectConverted != null)
|
if (ObjectConverted != null)
|
||||||
{
|
{
|
||||||
@ -104,7 +119,23 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="original">The hit object to convert.</param>
|
/// <param name="original">The hit object to convert.</param>
|
||||||
/// <param name="beatmap">The un-converted Beatmap.</param>
|
/// <param name="beatmap">The un-converted Beatmap.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>The converted hit object.</returns>
|
/// <returns>The converted hit object.</returns>
|
||||||
protected abstract IEnumerable<T> ConvertHitObject(HitObject original, IBeatmap beatmap);
|
protected virtual IEnumerable<T> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
#pragma warning disable 618
|
||||||
|
return ConvertHitObject(original, beatmap);
|
||||||
|
#pragma warning restore 618
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the conversion of a hit object.
|
||||||
|
/// This method is generally executed sequentially for all objects in a beatmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="original">The hit object to convert.</param>
|
||||||
|
/// <param name="beatmap">The un-converted Beatmap.</param>
|
||||||
|
/// <returns>The converted hit object.</returns>
|
||||||
|
[Obsolete("Use the cancellation-supporting override")] // Can be removed 20210318
|
||||||
|
protected virtual IEnumerable<T> ConvertHitObject(HitObject original, IBeatmap beatmap) => Enumerable.Empty<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
@ -76,7 +77,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public bool CanConvert() => true;
|
public bool CanConvert() => true;
|
||||||
|
|
||||||
public IBeatmap Convert()
|
public IBeatmap Convert(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
foreach (var obj in Beatmap.HitObjects)
|
foreach (var obj in Beatmap.HitObjects)
|
||||||
ObjectConverted?.Invoke(obj, obj.Yield());
|
ObjectConverted?.Invoke(obj, obj.Yield());
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -30,6 +31,8 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts <see cref="Beatmap"/>.
|
/// Converts <see cref="Beatmap"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IBeatmap Convert();
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>The converted Beatmap.</returns>
|
||||||
|
IBeatmap Convert(CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert
|
// Convert
|
||||||
IBeatmap converted = converter.Convert();
|
IBeatmap converted = converter.Convert(cancellationSource.Token);
|
||||||
|
|
||||||
// Apply conversion mods to the result
|
// Apply conversion mods to the result
|
||||||
foreach (var mod in mods.OfType<IApplicableAfterBeatmapConversion>())
|
foreach (var mod in mods.OfType<IApplicableAfterBeatmapConversion>())
|
||||||
|
@ -230,7 +230,7 @@ namespace osu.Game.Collections
|
|||||||
public void DeleteAll()
|
public void DeleteAll()
|
||||||
{
|
{
|
||||||
Collections.Clear();
|
Collections.Clear();
|
||||||
PostNotification?.Invoke(new SimpleNotification { Text = "Deleted all collections!" });
|
PostNotification?.Invoke(new ProgressCompletionNotification { Text = "Deleted all collections!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly object saveLock = new object();
|
private readonly object saveLock = new object();
|
||||||
|
@ -24,6 +24,7 @@ namespace osu.Game.Configuration
|
|||||||
Set(OsuSetting.Skin, 0, -1, int.MaxValue);
|
Set(OsuSetting.Skin, 0, -1, int.MaxValue);
|
||||||
|
|
||||||
Set(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
|
Set(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
|
||||||
|
Set(OsuSetting.BeatmapDetailModsFilter, false);
|
||||||
|
|
||||||
Set(OsuSetting.ShowConvertedBeatmaps, true);
|
Set(OsuSetting.ShowConvertedBeatmaps, true);
|
||||||
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
||||||
@ -200,6 +201,7 @@ namespace osu.Game.Configuration
|
|||||||
CursorRotation,
|
CursorRotation,
|
||||||
MenuParallax,
|
MenuParallax,
|
||||||
BeatmapDetailTab,
|
BeatmapDetailTab,
|
||||||
|
BeatmapDetailModsFilter,
|
||||||
Username,
|
Username,
|
||||||
ReleaseStream,
|
ReleaseStream,
|
||||||
SavePassword,
|
SavePassword,
|
||||||
|
@ -253,6 +253,9 @@ namespace osu.Game.Database
|
|||||||
/// Generally should include all file types which determine the file's uniqueness.
|
/// Generally should include all file types which determine the file's uniqueness.
|
||||||
/// Large files should be avoided if possible.
|
/// Large files should be avoided if possible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is only used by the default hash implementation. If <see cref="ComputeHash"/> is overridden, it will not be used.
|
||||||
|
/// </remarks>
|
||||||
protected abstract string[] HashableFileTypes { get; }
|
protected abstract string[] HashableFileTypes { get; }
|
||||||
|
|
||||||
internal static void LogForModel(TModel model, string message, Exception e = null)
|
internal static void LogForModel(TModel model, string message, Exception e = null)
|
||||||
@ -271,7 +274,7 @@ namespace osu.Game.Database
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// In the case of no matching files, a hash will be generated from the passed archive's <see cref="ArchiveReader.Name"/>.
|
/// In the case of no matching files, a hash will be generated from the passed archive's <see cref="ArchiveReader.Name"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private string computeHash(TModel item, ArchiveReader reader = null)
|
protected virtual string ComputeHash(TModel item, ArchiveReader reader = null)
|
||||||
{
|
{
|
||||||
// for now, concatenate all .osu files in the set to create a unique hash.
|
// for now, concatenate all .osu files in the set to create a unique hash.
|
||||||
MemoryStream hashable = new MemoryStream();
|
MemoryStream hashable = new MemoryStream();
|
||||||
@ -318,7 +321,7 @@ namespace osu.Game.Database
|
|||||||
LogForModel(item, "Beginning import...");
|
LogForModel(item, "Beginning import...");
|
||||||
|
|
||||||
item.Files = archive != null ? createFileInfos(archive, Files) : new List<TFileModel>();
|
item.Files = archive != null ? createFileInfos(archive, Files) : new List<TFileModel>();
|
||||||
item.Hash = computeHash(item, archive);
|
item.Hash = ComputeHash(item, archive);
|
||||||
|
|
||||||
await Populate(item, archive, cancellationToken);
|
await Populate(item, archive, cancellationToken);
|
||||||
|
|
||||||
@ -437,7 +440,7 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
using (ContextFactory.GetForWrite())
|
using (ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
item.Hash = computeHash(item);
|
item.Hash = ComputeHash(item);
|
||||||
ModelStore.Update(item);
|
ModelStore.Update(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,8 +123,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected void FadeUnhovered()
|
protected void FadeUnhovered()
|
||||||
{
|
{
|
||||||
Bar.FadeOut(transition_length, Easing.OutQuint);
|
Bar.FadeTo(IsHovered ? 1 : 0, transition_length, Easing.OutQuint);
|
||||||
Text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
|
Text.FadeColour(IsHovered ? Color4.White : AccentColour, transition_length, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
@ -211,7 +211,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
|||||||
|
|
||||||
TweenEdgeEffectTo(deactivateEdgeEffect, TRANSITION_LENGTH);
|
TweenEdgeEffectTo(deactivateEdgeEffect, TRANSITION_LENGTH);
|
||||||
|
|
||||||
box.FadeColour(BackgroundInactive, TRANSITION_LENGTH, Easing.OutQuint);
|
box.FadeColour(IsHovered ? backgroundHover : BackgroundInactive, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
highlightBox.FadeOut(TRANSITION_LENGTH, Easing.OutQuint);
|
highlightBox.FadeOut(TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
|
||||||
Text.Font = Text.Font.With(weight: FontWeight.Medium);
|
Text.Font = Text.Font.With(weight: FontWeight.Medium);
|
||||||
|
@ -23,6 +23,7 @@ using osu.Game.Overlays.Chat.Selection;
|
|||||||
using osu.Game.Overlays.Chat.Tabs;
|
using osu.Game.Overlays.Chat.Tabs;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
@ -78,7 +79,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config, OsuColour colours)
|
private void load(OsuConfigManager config, OsuColour colours, TextureStore textures)
|
||||||
{
|
{
|
||||||
const float padding = 5;
|
const float padding = 5;
|
||||||
|
|
||||||
@ -163,13 +164,13 @@ namespace osu.Game.Overlays
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
new SpriteIcon
|
new Sprite
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.Comments,
|
Texture = textures.Get(IconTexture),
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Size = new Vector2(20),
|
Size = new Vector2(OverlayTitle.ICON_SIZE),
|
||||||
Margin = new MarginPadding(10),
|
Margin = new MarginPadding { Left = 10 },
|
||||||
},
|
},
|
||||||
ChannelTabControl = CreateChannelTabControl().With(d =>
|
ChannelTabControl = CreateChannelTabControl().With(d =>
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public abstract class OverlayTitle : CompositeDrawable, INamedOverlayComponent
|
public abstract class OverlayTitle : CompositeDrawable, INamedOverlayComponent
|
||||||
{
|
{
|
||||||
|
public const float ICON_SIZE = 30;
|
||||||
|
|
||||||
private readonly OsuSpriteText titleText;
|
private readonly OsuSpriteText titleText;
|
||||||
private readonly Container icon;
|
private readonly Container icon;
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ namespace osu.Game.Overlays
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Margin = new MarginPadding { Horizontal = 5 }, // compensates for osu-web sprites having around 5px of whitespace on each side
|
Margin = new MarginPadding { Horizontal = 5 }, // compensates for osu-web sprites having around 5px of whitespace on each side
|
||||||
Size = new Vector2(30)
|
Size = new Vector2(ICON_SIZE)
|
||||||
},
|
},
|
||||||
titleText = new OsuSpriteText
|
titleText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Overlays.Profile;
|
using osu.Game.Overlays.Profile;
|
||||||
@ -176,6 +177,10 @@ namespace osu.Game.Overlays
|
|||||||
AccentColour = colourProvider.Highlight1;
|
AccentColour = colourProvider.Highlight1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnClick(ClickEvent e) => true;
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e) => true;
|
||||||
|
|
||||||
private class ProfileSectionTabItem : OverlayTabItem
|
private class ProfileSectionTabItem : OverlayTabItem
|
||||||
{
|
{
|
||||||
public ProfileSectionTabItem(ProfileSection value)
|
public ProfileSectionTabItem(ProfileSection value)
|
||||||
|
@ -145,6 +145,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
#pragma warning restore 618
|
#pragma warning restore 618
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use the cancellation-supporting override")] // Can be removed 20210318
|
||||||
protected virtual void CreateNestedHitObjects()
|
protected virtual void CreateNestedHitObjects()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -207,14 +207,15 @@ namespace osu.Game.Screens.Edit
|
|||||||
beatmapProcessor?.PreProcess();
|
beatmapProcessor?.PreProcess();
|
||||||
|
|
||||||
foreach (var hitObject in pendingUpdates)
|
foreach (var hitObject in pendingUpdates)
|
||||||
{
|
|
||||||
processHitObject(hitObject);
|
processHitObject(hitObject);
|
||||||
HitObjectUpdated?.Invoke(hitObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingUpdates.Clear();
|
|
||||||
|
|
||||||
beatmapProcessor?.PostProcess();
|
beatmapProcessor?.PostProcess();
|
||||||
|
|
||||||
|
// explicitly needs to be fired after PostProcess
|
||||||
|
foreach (var hitObject in pendingUpdates)
|
||||||
|
HitObjectUpdated?.Invoke(hitObject);
|
||||||
|
|
||||||
|
pendingUpdates.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected Bindable<BeatmapDetailAreaTabItem> CurrentTab => tabControl.Current;
|
protected Bindable<BeatmapDetailAreaTabItem> CurrentTab => tabControl.Current;
|
||||||
|
|
||||||
|
protected Bindable<bool> CurrentModsFilter => tabControl.CurrentModsFilter;
|
||||||
|
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
@ -26,6 +26,12 @@ namespace osu.Game.Screens.Select
|
|||||||
set => tabs.Current = value;
|
set => tabs.Current = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bindable<bool> CurrentModsFilter
|
||||||
|
{
|
||||||
|
get => modsCheckbox.Current;
|
||||||
|
set => modsCheckbox.Current = value;
|
||||||
|
}
|
||||||
|
|
||||||
public Action<BeatmapDetailAreaTabItem, bool> OnFilter; // passed the selected tab and if mods is checked
|
public Action<BeatmapDetailAreaTabItem, bool> OnFilter; // passed the selected tab and if mods is checked
|
||||||
|
|
||||||
public IReadOnlyList<BeatmapDetailAreaTabItem> TabItems
|
public IReadOnlyList<BeatmapDetailAreaTabItem> TabItems
|
||||||
|
@ -66,24 +66,9 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuConfigManager config)
|
private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuConfigManager config)
|
||||||
{
|
{
|
||||||
config.BindWith(OsuSetting.ShowConvertedBeatmaps, showConverted);
|
|
||||||
showConverted.ValueChanged += _ => updateCriteria();
|
|
||||||
|
|
||||||
config.BindWith(OsuSetting.DisplayStarsMinimum, minimumStars);
|
|
||||||
minimumStars.ValueChanged += _ => updateCriteria();
|
|
||||||
|
|
||||||
config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars);
|
|
||||||
maximumStars.ValueChanged += _ => updateCriteria();
|
|
||||||
|
|
||||||
ruleset.BindTo(parentRuleset);
|
|
||||||
ruleset.BindValueChanged(_ => updateCriteria());
|
|
||||||
|
|
||||||
sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode);
|
sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode);
|
||||||
groupMode = config.GetBindable<GroupMode>(OsuSetting.SongSelectGroupingMode);
|
groupMode = config.GetBindable<GroupMode>(OsuSetting.SongSelectGroupingMode);
|
||||||
|
|
||||||
groupMode.BindValueChanged(_ => updateCriteria());
|
|
||||||
sortMode.BindValueChanged(_ => updateCriteria());
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -182,6 +167,21 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
config.BindWith(OsuSetting.ShowConvertedBeatmaps, showConverted);
|
||||||
|
showConverted.ValueChanged += _ => updateCriteria();
|
||||||
|
|
||||||
|
config.BindWith(OsuSetting.DisplayStarsMinimum, minimumStars);
|
||||||
|
minimumStars.ValueChanged += _ => updateCriteria();
|
||||||
|
|
||||||
|
config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars);
|
||||||
|
maximumStars.ValueChanged += _ => updateCriteria();
|
||||||
|
|
||||||
|
ruleset.BindTo(parentRuleset);
|
||||||
|
ruleset.BindValueChanged(_ => updateCriteria());
|
||||||
|
|
||||||
|
groupMode.BindValueChanged(_ => updateCriteria());
|
||||||
|
sortMode.BindValueChanged(_ => updateCriteria());
|
||||||
|
|
||||||
collectionDropdown.Current.ValueChanged += val =>
|
collectionDropdown.Current.ValueChanged += val =>
|
||||||
{
|
{
|
||||||
if (val.NewValue == null)
|
if (val.NewValue == null)
|
||||||
|
@ -29,6 +29,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private Bindable<TabType> selectedTab;
|
private Bindable<TabType> selectedTab;
|
||||||
|
|
||||||
|
private Bindable<bool> selectedModsFilter;
|
||||||
|
|
||||||
public PlayBeatmapDetailArea()
|
public PlayBeatmapDetailArea()
|
||||||
{
|
{
|
||||||
Add(Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both });
|
Add(Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both });
|
||||||
@ -38,8 +40,13 @@ namespace osu.Game.Screens.Select
|
|||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
selectedTab = config.GetBindable<TabType>(OsuSetting.BeatmapDetailTab);
|
selectedTab = config.GetBindable<TabType>(OsuSetting.BeatmapDetailTab);
|
||||||
|
selectedModsFilter = config.GetBindable<bool>(OsuSetting.BeatmapDetailModsFilter);
|
||||||
|
|
||||||
selectedTab.BindValueChanged(tab => CurrentTab.Value = getTabItemFromTabType(tab.NewValue), true);
|
selectedTab.BindValueChanged(tab => CurrentTab.Value = getTabItemFromTabType(tab.NewValue), true);
|
||||||
CurrentTab.BindValueChanged(tab => selectedTab.Value = getTabTypeFromTabItem(tab.NewValue));
|
CurrentTab.BindValueChanged(tab => selectedTab.Value = getTabTypeFromTabItem(tab.NewValue));
|
||||||
|
|
||||||
|
selectedModsFilter.BindValueChanged(checkbox => CurrentModsFilter.Value = checkbox.NewValue, true);
|
||||||
|
CurrentModsFilter.BindValueChanged(checkbox => selectedModsFilter.Value = checkbox.NewValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
|
@ -12,6 +12,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
@ -86,21 +87,46 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
|
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
|
||||||
|
|
||||||
|
private const string unknown_creator_string = "Unknown";
|
||||||
|
|
||||||
|
protected override string ComputeHash(SkinInfo item, ArchiveReader reader = null)
|
||||||
|
{
|
||||||
|
// we need to populate early to create a hash based off skin.ini contents
|
||||||
|
if (item.Name?.Contains(".osk") == true)
|
||||||
|
populateMetadata(item);
|
||||||
|
|
||||||
|
if (item.Creator != null && item.Creator != unknown_creator_string)
|
||||||
|
{
|
||||||
|
// this is the optimal way to hash legacy skins, but will need to be reconsidered when we move forward with skin implementation.
|
||||||
|
// likely, the skin should expose a real version (ie. the version of the skin, not the skin.ini version it's targeting).
|
||||||
|
return item.ToString().ComputeSHA2Hash();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was no creator, the ToString above would give the filename, which alone isn't really enough to base any decisions on.
|
||||||
|
return base.ComputeHash(item, reader);
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task Populate(SkinInfo model, ArchiveReader archive, CancellationToken cancellationToken = default)
|
protected override async Task Populate(SkinInfo model, ArchiveReader archive, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
await base.Populate(model, archive, cancellationToken);
|
await base.Populate(model, archive, cancellationToken);
|
||||||
|
|
||||||
Skin reference = GetSkin(model);
|
if (model.Name?.Contains(".osk") == true)
|
||||||
|
populateMetadata(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateMetadata(SkinInfo item)
|
||||||
|
{
|
||||||
|
Skin reference = GetSkin(item);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(reference.Configuration.SkinInfo.Name))
|
if (!string.IsNullOrEmpty(reference.Configuration.SkinInfo.Name))
|
||||||
{
|
{
|
||||||
model.Name = reference.Configuration.SkinInfo.Name;
|
item.Name = reference.Configuration.SkinInfo.Name;
|
||||||
model.Creator = reference.Configuration.SkinInfo.Creator;
|
item.Creator = reference.Configuration.SkinInfo.Creator;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
model.Name = model.Name.Replace(".osk", "");
|
item.Name = item.Name.Replace(".osk", "");
|
||||||
model.Creator ??= "Unknown";
|
item.Creator ??= unknown_creator_string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
private Lazy<Storage> localStorage;
|
private Lazy<Storage> localStorage;
|
||||||
protected Storage LocalStorage => localStorage.Value;
|
protected Storage LocalStorage => localStorage.Value;
|
||||||
|
|
||||||
private readonly Lazy<DatabaseContextFactory> contextFactory;
|
private Lazy<DatabaseContextFactory> contextFactory;
|
||||||
|
|
||||||
protected IAPIProvider API
|
protected IAPIProvider API
|
||||||
{
|
{
|
||||||
@ -69,8 +69,33 @@ namespace osu.Game.Tests.Visual
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool UseOnlineAPI => false;
|
protected virtual bool UseOnlineAPI => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When running headless, there is an opportunity to use the host storage rather than creating a second isolated one.
|
||||||
|
/// This is because the host is recycled per TestScene execution in headless at an nunit level.
|
||||||
|
/// </summary>
|
||||||
|
private Storage isolatedHostStorage;
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
{
|
{
|
||||||
|
if (!UseFreshStoragePerRun)
|
||||||
|
isolatedHostStorage = (parent.Get<GameHost>() as HeadlessGameHost)?.Storage;
|
||||||
|
|
||||||
|
contextFactory = new Lazy<DatabaseContextFactory>(() =>
|
||||||
|
{
|
||||||
|
var factory = new DatabaseContextFactory(LocalStorage);
|
||||||
|
|
||||||
|
// only reset the database if not using the host storage.
|
||||||
|
// if we reset the host storage, it will delete global key bindings.
|
||||||
|
if (isolatedHostStorage == null)
|
||||||
|
factory.ResetDatabase();
|
||||||
|
|
||||||
|
using (var usage = factory.Get())
|
||||||
|
usage.Migrate();
|
||||||
|
return factory;
|
||||||
|
});
|
||||||
|
|
||||||
|
RecycleLocalStorage();
|
||||||
|
|
||||||
var baseDependencies = base.CreateChildDependencies(parent);
|
var baseDependencies = base.CreateChildDependencies(parent);
|
||||||
|
|
||||||
var providedRuleset = CreateRuleset();
|
var providedRuleset = CreateRuleset();
|
||||||
@ -104,19 +129,11 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
protected OsuTestScene()
|
protected OsuTestScene()
|
||||||
{
|
{
|
||||||
RecycleLocalStorage();
|
|
||||||
contextFactory = new Lazy<DatabaseContextFactory>(() =>
|
|
||||||
{
|
|
||||||
var factory = new DatabaseContextFactory(LocalStorage);
|
|
||||||
factory.ResetDatabase();
|
|
||||||
using (var usage = factory.Get())
|
|
||||||
usage.Migrate();
|
|
||||||
return factory;
|
|
||||||
});
|
|
||||||
|
|
||||||
base.Content.Add(content = new DrawSizePreservingFillContainer());
|
base.Content.Add(content = new DrawSizePreservingFillContainer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual bool UseFreshStoragePerRun => false;
|
||||||
|
|
||||||
public virtual void RecycleLocalStorage()
|
public virtual void RecycleLocalStorage()
|
||||||
{
|
{
|
||||||
if (localStorage?.IsValueCreated == true)
|
if (localStorage?.IsValueCreated == true)
|
||||||
@ -131,7 +148,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage = new Lazy<Storage>(() => new NativeStorage(Path.Combine(RuntimeInfo.StartupDirectory, $"{GetType().Name}-{Guid.NewGuid()}")));
|
localStorage =
|
||||||
|
new Lazy<Storage>(() => isolatedHostStorage ?? new NativeStorage(Path.Combine(RuntimeInfo.StartupDirectory, $"{GetType().Name}-{Guid.NewGuid()}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -172,7 +190,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
if (MusicController?.TrackLoaded == true)
|
if (MusicController?.TrackLoaded == true)
|
||||||
MusicController.CurrentTrack.Stop();
|
MusicController.CurrentTrack.Stop();
|
||||||
|
|
||||||
if (contextFactory.IsValueCreated)
|
if (contextFactory?.IsValueCreated == true)
|
||||||
contextFactory.Value.ResetDatabase();
|
contextFactory.Value.ResetDatabase();
|
||||||
|
|
||||||
RecycleLocalStorage();
|
RecycleLocalStorage();
|
||||||
|
Loading…
Reference in New Issue
Block a user