From 67ea3beeb49d5ad74f7dadb9cd9a0396ee9aa299 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 21 Jan 2019 17:53:00 +0900 Subject: [PATCH 01/11] Fix catch slider conversion for last droplets --- .../Objects/JuiceStream.cs | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index d8bd3e0edc..7e8f64d6f7 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -62,15 +62,22 @@ namespace osu.Game.Rulesets.Catch.Objects X = X }); - double lastDropletTime = StartTime; + double lastTickTime = StartTime; for (int span = 0; span < this.SpanCount(); span++) { var spanStartTime = StartTime + span * spanDuration; var reversed = span % 2 == 1; - for (double d = 0; d <= length; d += tickDistance) + for (double d = tickDistance;; d += tickDistance) { + bool isLastTick = false; + if (d + minDistanceFromEnd >= length) + { + d = length; + isLastTick = true; + } + var timeProgress = d / length; var distanceProgress = reversed ? 1 - timeProgress : timeProgress; @@ -79,15 +86,15 @@ namespace osu.Game.Rulesets.Catch.Objects if (LegacyLastTickOffset != null) { // If we're the last tick, apply the legacy offset - if (span == this.SpanCount() - 1 && d + tickDistance > length) + if (span == this.SpanCount() - 1 && isLastTick) time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value); } - double tinyTickInterval = time - lastDropletTime; + double tinyTickInterval = time - lastTickTime; while (tinyTickInterval > 100) tinyTickInterval /= 2; - for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval) + for (double t = lastTickTime + tinyTickInterval; t < time; t += tinyTickInterval) { double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; @@ -104,22 +111,22 @@ namespace osu.Game.Rulesets.Catch.Objects }); } - if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd) - { - AddNested(new Droplet - { - StartTime = time, - X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } + lastTickTime = time; - lastDropletTime = time; + if (isLastTick) + break; + + AddNested(new Droplet + { + StartTime = time, + X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + Samples = new List(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); } AddNested(new Fruit From 3375096f1da60f847ee3ee1161b9d3a490a046fa Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 Jan 2019 18:11:27 +0900 Subject: [PATCH 02/11] Fix juice stream generates tiny droplet at tick time --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 7e8f64d6f7..61beaf7154 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -94,7 +94,8 @@ namespace osu.Game.Rulesets.Catch.Objects while (tinyTickInterval > 100) tinyTickInterval /= 2; - for (double t = lastTickTime + tinyTickInterval; t < time; t += tinyTickInterval) + // we don't want to generate at (t == time - epsilon) due to floating point accuracy. time - 1 seems working. + for (double t = lastTickTime + tinyTickInterval; t < time - 1; t += tinyTickInterval) { double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; From aaba377e113671d078b14b9fedf0e9f3ff9876fa Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 Jan 2019 18:13:14 +0900 Subject: [PATCH 03/11] Add a test for catch slider conversion --- .../CatchBeatmapConversionTest.cs | 1 + .../Beatmaps/slider-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/slider.osu | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index 162624da57..2b7d414555 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -21,6 +21,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase("basic")] [TestCase("spinner")] [TestCase("spinner-and-circles")] + [TestCase("slider")] public new void Test(string name) { base.Test(name); diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json new file mode 100644 index 0000000000..58c52b6867 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":19184.0,"Objects":[{"StartTime":19184.0,"Position":320.0},{"StartTime":19263.0,"Position":311.730255},{"StartTime":19343.0,"Position":324.6205},{"StartTime":19423.0,"Position":343.0907},{"StartTime":19503.0,"Position":372.2917},{"StartTime":19582.0,"Position":385.194733},{"StartTime":19662.0,"Position":379.0426},{"StartTime":19742.0,"Position":385.1066},{"StartTime":19822.0,"Position":391.624664},{"StartTime":19919.0,"Position":386.27832},{"StartTime":20016.0,"Position":380.117035},{"StartTime":20113.0,"Position":381.664154},{"StartTime":20247.0,"Position":370.872864}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu new file mode 100644 index 0000000000..d48b2d7769 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu @@ -0,0 +1,18 @@ +osu file format v14 + +[General] +Mode: 2 + +[Difficulty] +HPDrainRate:3 +CircleSize:2 +OverallDifficulty:4 +ApproachRate:4 +SliderMultiplier:0.9 +SliderTickRate:1 + +[TimingPoints] +35.4473684210527,638.298947368422,4,2,1,60,1,0 + +[HitObjects] +320,176,19184,2,8,P|384:168|368:232,1,150 From 1a5a23875201f033f922cd7b8f770032c93ed0cd Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sat, 26 Jan 2019 16:14:37 +0900 Subject: [PATCH 04/11] Use integer count for tiny droplet generation --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 61beaf7154..8cbd824805 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -90,13 +90,17 @@ namespace osu.Game.Rulesets.Catch.Objects time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value); } + int tinyTickCount = 1; double tinyTickInterval = time - lastTickTime; - while (tinyTickInterval > 100) - tinyTickInterval /= 2; - - // we don't want to generate at (t == time - epsilon) due to floating point accuracy. time - 1 seems working. - for (double t = lastTickTime + tinyTickInterval; t < time - 1; t += tinyTickInterval) + while (tinyTickInterval > 100 && tinyTickCount < 10000) { + tinyTickInterval /= 2; + tinyTickCount *= 2; + } + + for (int tinyTickIndex = 0; tinyTickIndex < tinyTickCount - 1; tinyTickIndex++) + { + var t = lastTickTime + (tinyTickIndex + 1) * tinyTickInterval; double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; AddNested(new TinyDroplet From ea48d6a88a7e1caaecbdfa684b9e8c8f2b093f86 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sat, 26 Jan 2019 16:16:49 +0900 Subject: [PATCH 05/11] reduce code duplication / allocations --- .../Objects/JuiceStream.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 8cbd824805..88b96aa0c4 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -55,6 +55,13 @@ namespace osu.Game.Rulesets.Catch.Objects var minDistanceFromEnd = Velocity * 0.01; + var tickSamples = Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + }).ToList(); + AddNested(new Fruit { Samples = Samples, @@ -107,12 +114,7 @@ namespace osu.Game.Rulesets.Catch.Objects { StartTime = t, X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) + Samples = tickSamples }); } @@ -125,12 +127,7 @@ namespace osu.Game.Rulesets.Catch.Objects { StartTime = time, X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) + Samples = tickSamples }); } From 628b3e1119cef797dcef2bd59a62bde1479f3578 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 Jan 2019 18:19:57 +0900 Subject: [PATCH 06/11] Move osu-resources to nuget --- .gitmodules | 3 -- osu-resources | 1 - osu.Desktop/osu.Desktop.csproj | 1 - .../Formats/LegacyBeatmapDecoderTest.cs | 32 +++++++++---------- .../Formats/LegacyStoryboardDecoderTest.cs | 4 +-- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 2 +- .../Beatmaps/IO/ImportBeatmapTest.cs | 19 +++-------- .../Beatmaps/IO/OszArchiveReaderTest.cs | 6 ++-- osu.Game.Tests/Resources/Resource.cs | 24 +++++++++----- osu.Game.Tests/Scores/IO/ImportScoreTest.cs | 14 ++------ osu.Game.Tests/WaveformTestBeatmap.cs | 6 ++-- osu.Game/osu.Game.csproj | 4 +-- osu.TestProject.props | 1 - osu.sln | 6 ---- 14 files changed, 49 insertions(+), 74 deletions(-) delete mode 160000 osu-resources diff --git a/.gitmodules b/.gitmodules index f1c4f5d172..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "osu-resources"] - path = osu-resources - url = https://github.com/ppy/osu-resources \ No newline at end of file diff --git a/osu-resources b/osu-resources deleted file mode 160000 index 9880089b4e..0000000000 --- a/osu-resources +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9880089b4e8fcd78d68f30c8a40d43bf8dccca86 diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 4f0ae3d65d..874f73da6d 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -22,7 +22,6 @@ - diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 1221212f94..171ba91ada 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeBeatmapVersion() { - using (var resStream = Resource.OpenResource("beatmap-version.osu")) + using (var resStream = TestResources.OpenResource("beatmap-version.osu")) using (var stream = new StreamReader(resStream)) { var decoder = Decoder.GetDecoder(stream); @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapGeneral() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapEditor() { var decoder = new LegacyBeatmapDecoder(); - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var beatmapInfo = decoder.Decode(stream).BeatmapInfo; @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapMetadata() { var decoder = new LegacyBeatmapDecoder(); - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -119,7 +119,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapDifficulty() { var decoder = new LegacyBeatmapDecoder(); - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty; @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapEvents() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapTimingPoints() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -190,7 +190,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapColours() { var decoder = new LegacySkinDecoder(); - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var comboColors = decoder.Decode(stream).ComboColours; @@ -215,7 +215,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapComboOffsetsOsu() { var decoder = new LegacyBeatmapDecoder(); - using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu")) + using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu")) using (var stream = new StreamReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -237,7 +237,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapComboOffsetsCatch() { var decoder = new LegacyBeatmapDecoder(); - using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu")) + using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu")) using (var stream = new StreamReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -259,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapHitObjects() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -286,7 +286,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeControlPointCustomSampleBank() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("controlpoint-custom-samplebank.osu")) + using (var resStream = TestResources.OpenResource("controlpoint-custom-samplebank.osu")) using (var stream = new StreamReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -307,7 +307,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeHitObjectCustomSampleBank() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("hitobject-custom-samplebank.osu")) + using (var resStream = TestResources.OpenResource("hitobject-custom-samplebank.osu")) using (var stream = new StreamReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -324,7 +324,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeHitObjectFileSamples() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("hitobject-file-samples.osu")) + using (var resStream = TestResources.OpenResource("hitobject-file-samples.osu")) using (var stream = new StreamReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -342,7 +342,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeSliderSamples() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("slider-samples.osu")) + using (var resStream = TestResources.OpenResource("slider-samples.osu")) using (var stream = new StreamReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -385,7 +385,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeHitObjectNullAdditionBank() { var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; - using (var resStream = Resource.OpenResource("hitobject-no-addition-bank.osu")) + using (var resStream = TestResources.OpenResource("hitobject-no-addition-bank.osu")) using (var stream = new StreamReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 5049349999..136d1de930 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeStoryboardEvents() { var decoder = new LegacyStoryboardDecoder(); - using (var resStream = Resource.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu")) + using (var resStream = TestResources.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu")) using (var stream = new StreamReader(resStream)) { var storyboard = decoder.Decode(stream); @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeVariableWithSuffix() { var decoder = new LegacyStoryboardDecoder(); - using (var resStream = Resource.OpenResource("variable-with-suffix.osb")) + using (var resStream = TestResources.OpenResource("variable-with-suffix.osb")) using (var stream = new StreamReader(resStream)) { var storyboard = decoder.Decode(stream); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 44291a6805..d5ab0e43d1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -146,7 +146,7 @@ namespace osu.Game.Tests.Beatmaps.Formats /// The after being decoded by an . private Beatmap decode(string filename, out Beatmap jsonDecoded) { - using (var stream = Resource.OpenResource(filename)) + using (var stream = TestResources.OpenResource(filename)) using (var sr = new StreamReader(stream)) { var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr); diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index a159659d35..b6a8b3b06c 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -12,6 +12,7 @@ using osu.Framework.Platform; using osu.Game.IPC; using osu.Framework.Allocation; using osu.Game.Beatmaps; +using osu.Game.Tests.Resources; using SharpCompress.Archives.Zip; namespace osu.Game.Tests.Beatmaps.IO @@ -19,8 +20,6 @@ namespace osu.Game.Tests.Beatmaps.IO [TestFixture] public class ImportBeatmapTest { - public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; - [Test] public void TestImportWhenClosed() { @@ -114,7 +113,7 @@ namespace osu.Game.Tests.Beatmaps.IO Assert.AreEqual(0, fireCount -= 2); - var breakTemp = createTemporaryBeatmap(); + var breakTemp = TestResources.GetTestBeatmapForImport(); MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 }); MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp)); @@ -223,7 +222,7 @@ namespace osu.Game.Tests.Beatmaps.IO var osu = loadOsu(host); - var temp = createTemporaryBeatmap(); + var temp = TestResources.GetTestBeatmapForImport(); var importer = new ArchiveImportIPCChannel(client); if (!importer.ImportAsync(temp).Wait(10000)) @@ -248,7 +247,7 @@ namespace osu.Game.Tests.Beatmaps.IO try { var osu = loadOsu(host); - var temp = createTemporaryBeatmap(); + var temp = TestResources.GetTestBeatmapForImport(); using (File.OpenRead(temp)) osu.Dependencies.Get().Import(temp); ensureLoaded(osu); @@ -262,17 +261,9 @@ namespace osu.Game.Tests.Beatmaps.IO } } - private static string createTemporaryBeatmap() - { - var temp = Path.GetTempFileName() + ".osz"; - File.Copy(TEST_OSZ_PATH, temp, true); - Assert.IsTrue(File.Exists(temp)); - return temp; - } - public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null) { - var temp = path ?? createTemporaryBeatmap(); + var temp = path ?? TestResources.GetTestBeatmapForImport(); var manager = osu.Dependencies.Get(); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index aa95e7390f..17197aff27 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Beatmaps.IO [Test] public void TestReadBeatmaps() { - using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz")) + using (var osz = TestResources.GetTestBeatmapStream()) { var reader = new ZipArchiveReader(osz); string[] expected = @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.IO [Test] public void TestReadMetadata() { - using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz")) + using (var osz = TestResources.GetTestBeatmapStream()) { var reader = new ZipArchiveReader(osz); @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO [Test] public void TestReadFile() { - using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz")) + using (var osz = TestResources.GetTestBeatmapStream()) { var reader = new ZipArchiveReader(osz); using (var stream = new StreamReader( diff --git a/osu.Game.Tests/Resources/Resource.cs b/osu.Game.Tests/Resources/Resource.cs index 5405436422..9cb85a63bf 100644 --- a/osu.Game.Tests/Resources/Resource.cs +++ b/osu.Game.Tests/Resources/Resource.cs @@ -1,20 +1,28 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.IO; -using System.Reflection; +using NUnit.Framework; +using osu.Framework.IO.Stores; namespace osu.Game.Tests.Resources { - public static class Resource + public static class TestResources { - public static Stream OpenResource(string name) - { - var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)); + public static Stream OpenResource(string name) => new DllResourceStore("osu.Game.Tests.dll").GetStream($"Resources/{name}"); - return Assembly.GetExecutingAssembly().GetManifestResourceStream($@"osu.Game.Tests.Resources.{name}") ?? - Assembly.LoadFrom(Path.Combine(localPath, @"osu.Game.Resources.dll")).GetManifestResourceStream($@"osu.Game.Resources.{name}"); + public static Stream GetTestBeatmapStream() => new DllResourceStore("osu.Game.Resources.dll").GetStream("Beatmaps/241526 Soleily - Renatus.osz"); + + public static string GetTestBeatmapForImport() + { + var temp = Path.GetTempFileName() + ".osz"; + + using (var stream = GetTestBeatmapStream()) + using (var newFile = File.Create(temp)) + stream.CopyTo(newFile); + + Assert.IsTrue(File.Exists(temp)); + return temp; } } } diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs index f5ebe313dd..e39f18c3cd 100644 --- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs +++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,14 +15,13 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; +using osu.Game.Tests.Resources; using osu.Game.Users; namespace osu.Game.Tests.Scores.IO { public class ImportScoreTest { - public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; - [Test] public void TestBasicImport() { @@ -132,21 +130,13 @@ namespace osu.Game.Tests.Scores.IO return scoreManager.GetAllUsableScores().First(); } - private string createTemporaryBeatmap() - { - var temp = Path.GetTempFileName() + ".osz"; - File.Copy(TEST_OSZ_PATH, temp, true); - Assert.IsTrue(File.Exists(temp)); - return temp; - } - 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"); - var beatmapFile = createTemporaryBeatmap(); + var beatmapFile = TestResources.GetTestBeatmapForImport(); var beatmapManager = osu.Dependencies.Get(); beatmapManager.Import(beatmapFile); diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs index 72db4b0c17..2028671b0e 100644 --- a/osu.Game.Tests/WaveformTestBeatmap.cs +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.IO.Archives; -using osu.Game.Tests.Beatmaps.IO; +using osu.Game.Tests.Resources; namespace osu.Game.Tests { @@ -18,12 +18,12 @@ namespace osu.Game.Tests public class WaveformTestBeatmap : WorkingBeatmap { private readonly ZipArchiveReader reader; - private readonly FileStream stream; + private readonly Stream stream; public WaveformTestBeatmap() : base(new BeatmapInfo()) { - stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH); + stream = TestResources.GetTestBeatmapStream(); reader = new ZipArchiveReader(stream); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 669c7a6d8d..be54ea53f8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -10,15 +10,13 @@ - - - + diff --git a/osu.TestProject.props b/osu.TestProject.props index 456ecfd468..a5c70f4edc 100644 --- a/osu.TestProject.props +++ b/osu.TestProject.props @@ -8,7 +8,6 @@ - diff --git a/osu.sln b/osu.sln index bf1b6d60e1..73d8ec0116 100644 --- a/osu.sln +++ b/osu.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}" @@ -37,10 +35,6 @@ Global {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.Build.0 = Release|Any CPU {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.Build.0 = Debug|Any CPU {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.ActiveCfg = Release|Any CPU From bf57f80d6edadb5ad321c9764c0777165656db4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 Jan 2019 18:33:56 +0900 Subject: [PATCH 07/11] Update readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a54b28b74a..62109d767e 100644 --- a/README.md +++ b/README.md @@ -31,18 +31,14 @@ If your platform is not listed above, there is still a chance you can manually b Clone the repository **including submodules**: ```shell -git clone --recurse-submodules https://github.com/ppy/osu +git clone https://github.com/ppy/osu cd osu ``` -> If you forgot the `--recurse-submodules` option, run this command inside the `osu` directory: -> -> `git submodule update --init --recursive` - To update the source code to the latest commit, run the following command inside the `osu` directory: ```shell -git pull --recurse-submodules +git pull ``` ## Building @@ -73,6 +69,10 @@ For example, you can run osu! with the following command: LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop ``` +## Testing with resource/framework modifications + +Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or osu-framework(https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages. + ## Code analysis Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice. From 8d4faafdbe2dae992af9dee2bf51dd96baeeb8f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 Jan 2019 18:41:57 +0900 Subject: [PATCH 08/11] Rename file to match class --- osu.Game.Tests/Resources/{Resource.cs => TestResources.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game.Tests/Resources/{Resource.cs => TestResources.cs} (100%) diff --git a/osu.Game.Tests/Resources/Resource.cs b/osu.Game.Tests/Resources/TestResources.cs similarity index 100% rename from osu.Game.Tests/Resources/Resource.cs rename to osu.Game.Tests/Resources/TestResources.cs From bbbedd2c3669e3f5b8a4fef635a93729aa6c4475 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Jan 2019 12:20:16 +0900 Subject: [PATCH 09/11] Remove iOS build configurations from main sln --- osu.sln | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.sln b/osu.sln index 0737a9fbd8..496e009894 100644 --- a/osu.sln +++ b/osu.sln @@ -31,10 +31,6 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Release|iPhone = Release|iPhone - Release|iPhoneSimulator = Release|iPhoneSimulator - Debug|iPhone = Debug|iPhone EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU From 910528b4cb82e4082fa10b7974e758cc510743cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Jan 2019 13:09:50 +0900 Subject: [PATCH 10/11] Update iOS project in line with changes --- .../osu.Game.Rulesets.Catch.Tests.iOS.csproj | 4 ---- .../osu.Game.Rulesets.Mania.Tests.iOS.csproj | 4 ---- .../osu.Game.Rulesets.Osu.Tests.iOS.csproj | 4 ---- .../osu.Game.Rulesets.Taiko.Tests.iOS.csproj | 4 ---- osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj | 4 ---- osu.iOS.props | 1 + osu.iOS.sln | 2 -- osu.iOS/osu.iOS.csproj | 4 ---- osu.sln | 2 -- 9 files changed, 1 insertion(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj index da053f7598..37e7c45a4e 100644 --- a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj @@ -39,10 +39,6 @@ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} osu.Game.Rulesets.Catch - - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} - osu.Game.Resources - diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj index 45ed2091a7..24abccb19d 100644 --- a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj @@ -39,10 +39,6 @@ {48F4582B-7687-4621-9CBE-5C24197CB536} osu.Game.Rulesets.Mania - - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} - osu.Game.Resources - diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj index 349e46e02d..9930a166e3 100644 --- a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj @@ -39,10 +39,6 @@ {C92A607B-1FDD-4954-9F92-03FF547D9080} osu.Game.Rulesets.Osu - - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} - osu.Game.Resources - diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj index 2ab0633786..d2817b743c 100644 --- a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj @@ -39,10 +39,6 @@ {F167E17A-7DE6-4AF5-B920-A5112296C695} osu.Game.Rulesets.Taiko - - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} - osu.Game.Resources - diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj index 636bedac13..ea5ab699f3 100644 --- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj +++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj @@ -51,10 +51,6 @@ {F167E17A-7DE6-4AF5-B920-A5112296C695} osu.Game.Rulesets.Taiko - - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} - osu.Game.Resources - diff --git a/osu.iOS.props b/osu.iOS.props index adc07d6bb8..d2410a2c25 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,6 +105,7 @@ + diff --git a/osu.iOS.sln b/osu.iOS.sln index fe9741d767..21d02d33ab 100644 --- a/osu.iOS.sln +++ b/osu.iOS.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}" diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index fda26ddc94..9c69dd40ba 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -57,10 +57,6 @@ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} osu.Game - - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} - osu.Game.Resources - {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} osu.Game.Rulesets.Catch diff --git a/osu.sln b/osu.sln index 496e009894..3c38309d86 100644 --- a/osu.sln +++ b/osu.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}" From 3a2919780ec7fce56519be3fd84e7a3ed76b3385 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 30 Jan 2019 11:37:11 +0900 Subject: [PATCH 11/11] Fix markdown error in readme change Co-Authored-By: peppy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62109d767e..94ab385bfd 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --projec ## Testing with resource/framework modifications -Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or osu-framework(https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages. +Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages. ## Code analysis