diff --git a/osu.Android.props b/osu.Android.props index 6ff9416e47..0b41d5cda4 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -53,7 +53,7 @@ - + diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index 386bcbb724..ee2cec1bbd 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -22,26 +22,15 @@ namespace osu.Game.Rulesets.Mania.UI.Components private readonly IBindable direction = new Bindable(); - private readonly Container hitTargetLine; - private readonly Drawable hitTargetBar; + private readonly Drawable hitTarget; public ColumnHitObjectArea(HitObjectContainer hitObjectContainer) { InternalChildren = new[] { - hitTargetBar = new Box + hitTarget = new DefaultHitTarget { RelativeSizeAxes = Axes.X, - Height = NotePiece.NOTE_HEIGHT, - Alpha = 0.6f, - Colour = Color4.Black - }, - hitTargetLine = new Container - { - RelativeSizeAxes = Axes.X, - Height = hit_target_bar_height, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } }, hitObjectContainer }; @@ -55,17 +44,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components { Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - hitTargetBar.Anchor = hitTargetBar.Origin = anchor; - hitTargetLine.Anchor = hitTargetLine.Origin = anchor; + hitTarget.Anchor = hitTarget.Origin = anchor; }, true); } - protected override void LoadComplete() - { - base.LoadComplete(); - updateColours(); - } - private Color4 accentColour; public Color4 AccentColour @@ -78,21 +60,86 @@ namespace osu.Game.Rulesets.Mania.UI.Components accentColour = value; - updateColours(); + if (hitTarget is IHasAccentColour colouredHitTarget) + colouredHitTarget.AccentColour = accentColour; } } - private void updateColours() + private class DefaultHitTarget : CompositeDrawable, IHasAccentColour { - if (!IsLoaded) - return; + private readonly IBindable direction = new Bindable(); - hitTargetLine.EdgeEffect = new EdgeEffectParameters + private readonly Container hitTargetLine; + private readonly Drawable hitTargetBar; + + public DefaultHitTarget() { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = accentColour.Opacity(0.5f), - }; + InternalChildren = new[] + { + hitTargetBar = new Box + { + RelativeSizeAxes = Axes.X, + Height = NotePiece.NOTE_HEIGHT, + Alpha = 0.6f, + Colour = Color4.Black + }, + hitTargetLine = new Container + { + RelativeSizeAxes = Axes.X, + Height = hit_target_bar_height, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + }, + }; + } + + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(dir => + { + Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + + hitTargetBar.Anchor = hitTargetBar.Origin = anchor; + hitTargetLine.Anchor = hitTargetLine.Origin = anchor; + }, true); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateColours(); + } + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + if (accentColour == value) + return; + + accentColour = value; + + updateColours(); + } + } + + private void updateColours() + { + if (!IsLoaded) + return; + + hitTargetLine.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = accentColour.Opacity(0.5f), + }; + } } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs index eff4d919b0..c9b3d08a22 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs @@ -33,8 +33,8 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(CircularDistanceSnapGrid) }; - [Cached(typeof(IEditorBeatmap))] - private readonly EditorBeatmap editorBeatmap; + [Cached(typeof(EditorBeatmap))] + private readonly EditorBeatmap editorBeatmap; [Cached] private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Tests public TestSceneOsuDistanceSnapGrid() { - editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + editorBeatmap = new EditorBeatmap(new OsuBeatmap()); } [SetUp] diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index a2c1a5f5f4..49624ea733 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -91,10 +91,10 @@ namespace osu.Game.Rulesets.Osu.Edit if (sourceIndex == -1) return null; - OsuHitObject sourceObject = EditorBeatmap.HitObjects[sourceIndex]; + HitObject sourceObject = EditorBeatmap.HitObjects[sourceIndex]; int targetIndex = sourceIndex + targetOffset; - OsuHitObject targetObject = null; + HitObject targetObject = null; // Keep advancing the target object while its start time falls before the end time of the source object while (true) @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Edit targetIndex++; } - return new OsuDistanceSnapGrid(sourceObject, targetObject); + return new OsuDistanceSnapGrid((OsuHitObject)sourceObject, (OsuHitObject)targetObject); } } } diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs index aaf113f216..c31b07344d 100644 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -26,10 +26,6 @@ namespace osu.Game.Rulesets.Taiko.Audio var centre = s.GetSampleInfo(); var rim = s.GetSampleInfo(HitSampleInfo.HIT_CLAP); - // todo: this is ugly - centre.Namespace = "taiko"; - rim.Namespace = "taiko"; - mappings[s.Time] = new DrumSample { Centre = addSound(centre), diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 2da5a9c403..b9d31ff906 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -166,8 +166,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // Normal and clap samples are handled by the drum protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP); - protected override string SampleNamespace => "taiko"; - protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); /// diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 4b234b56d4..48eb33976e 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -121,41 +121,13 @@ namespace osu.Game.Rulesets.Taiko.Replays var nextHitObject = GetNextObject(i); // Get the next object that requires pressing the same button bool canDelayKeyUp = nextHitObject == null || nextHitObject.StartTime > endTime + KEY_UP_DELAY; - double calculatedDelay = canDelayKeyUp ? KEY_UP_DELAY : (nextHitObject.StartTime - endTime) * 0.9; - Frames.Add(new TaikoReplayFrame(endTime + calculatedDelay)); - if (i < Beatmap.HitObjects.Count - 1) - { - double waitTime = Beatmap.HitObjects[i + 1].StartTime - 1000; - if (waitTime > endTime) - Frames.Add(new TaikoReplayFrame(waitTime)); - } - hitButton = !hitButton; } return Replay; } - - protected override HitObject GetNextObject(int currentIndex) - { - Type desiredType = Beatmap.HitObjects[currentIndex].GetType(); - - for (int i = currentIndex + 1; i < Beatmap.HitObjects.Count; i++) - { - var currentObj = Beatmap.HitObjects[i]; - - if (currentObj.GetType() == desiredType || - // Un-press all keys before a DrumRoll or Swell - currentObj is DrumRoll || currentObj is Swell) - { - return Beatmap.HitObjects[i]; - } - } - - return null; - } } } diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitclap.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitclap.wav new file mode 100755 index 0000000000..9ea2be5855 Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitclap.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitfinish.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitfinish.wav new file mode 100755 index 0000000000..af270ae12a Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitfinish.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitnormal.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitnormal.wav new file mode 100755 index 0000000000..3d8024c6ae Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitnormal.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitwhistle.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitwhistle.wav new file mode 100755 index 0000000000..16d254cc87 Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitwhistle.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitclap.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitclap.wav new file mode 100755 index 0000000000..b4cfa26265 Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitclap.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitfinish.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitfinish.wav new file mode 100755 index 0000000000..97804a5a61 Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitfinish.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitnormal.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitnormal.wav new file mode 100755 index 0000000000..67f02877a8 Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitnormal.wav differ diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitwhistle.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitwhistle.wav new file mode 100755 index 0000000000..10206cd228 Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitwhistle.wav differ diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs new file mode 100644 index 0000000000..381cd14cd4 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Taiko.Skinning +{ + public class TaikoLegacySkinTransformer : ISkin + { + private readonly ISkinSource source; + + public TaikoLegacySkinTransformer(ISkinSource source) + { + this.source = source; + } + + public Drawable GetDrawableComponent(ISkinComponent component) => source.GetDrawableComponent(component); + + public Texture GetTexture(string componentName) => source.GetTexture(componentName); + + public SampleChannel GetSample(ISampleInfo sampleInfo) => source.GetSample(new LegacyTaikoSampleInfo(sampleInfo)); + + public IBindable GetConfig(TLookup lookup) => source.GetConfig(lookup); + + private class LegacyTaikoSampleInfo : ISampleInfo + { + private readonly ISampleInfo source; + + public LegacyTaikoSampleInfo(ISampleInfo source) + { + this.source = source; + } + + public IEnumerable LookupNames + { + get + { + foreach (var name in source.LookupNames) + yield return $"taiko-{name}"; + + foreach (var name in source.LookupNames) + yield return name; + } + } + + public int Volume => source.Volume; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 777b68a993..536cbdc562 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -21,6 +21,8 @@ using osu.Game.Rulesets.Taiko.Difficulty; using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Scoring; using System; +using osu.Game.Rulesets.Taiko.Skinning; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko { @@ -34,6 +36,8 @@ namespace osu.Game.Rulesets.Taiko public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this); + public override ISkin CreateLegacySkinProvider(ISkinSource source) => new TaikoLegacySkinTransformer(source); + public const string SHORT_NAME = "taiko"; public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] diff --git a/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs b/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs index 98e630abd2..12d729d09f 100644 --- a/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestHitObjectAddEvent() { - var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); HitObject addedObject = null; editorBeatmap.HitObjectAdded += h => addedObject = h; @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Beatmaps public void HitObjectRemoveEvent() { var hitCircle = new HitCircle(); - var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); HitObject removedObject = null; editorBeatmap.HitObjectRemoved += h => removedObject = h; @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Beatmaps public void TestInitialHitObjectStartTimeChangeEvent() { var hitCircle = new HitCircle(); - var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); HitObject changedObject = null; editorBeatmap.StartTimeChanged += h => changedObject = h; @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestAddedHitObjectStartTimeChangeEvent() { - var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); HitObject changedObject = null; editorBeatmap.StartTimeChanged += h => changedObject = h; @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Beatmaps public void TestRemovedHitObjectStartTimeChangeEvent() { var hitCircle = new HitCircle(); - var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); HitObject changedObject = null; editorBeatmap.StartTimeChanged += h => changedObject = h; @@ -110,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestAddHitObjectInMiddle() { - var editorBeatmap = new EditorBeatmap(new OsuBeatmap + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { @@ -134,7 +134,7 @@ namespace osu.Game.Tests.Beatmaps public void TestResortWhenStartTimeChanged() { var hitCircle = new HitCircle { StartTime = 1000 }; - var editorBeatmap = new EditorBeatmap(new OsuBeatmap + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { diff --git a/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs index fe3cc375ea..2d336bd19c 100644 --- a/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs @@ -2,11 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit; using osu.Game.Tests.Visual; @@ -17,6 +18,9 @@ namespace osu.Game.Tests.Editor { private TestHitObjectComposer composer; + [Cached(typeof(EditorBeatmap))] + private readonly EditorBeatmap editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + [SetUp] public void Setup() => Schedule(() => { @@ -183,7 +187,7 @@ namespace osu.Game.Tests.Editor private class TestHitObjectComposer : OsuHitObjectComposer { - public new EditorBeatmap EditorBeatmap => base.EditorBeatmap; + public new EditorBeatmap EditorBeatmap => base.EditorBeatmap; public TestHitObjectComposer() : base(new OsuRuleset()) diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs new file mode 100644 index 0000000000..5deb136c85 --- /dev/null +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -0,0 +1,74 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using NUnit.Framework; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.IO.Stores; +using osu.Game.Audio; +using osu.Game.Skinning; +using osu.Game.Tests.Resources; +using osu.Game.Tests.Visual; + +namespace osu.Game.Tests.Gameplay +{ + public class TestSceneStoryboardSamples : OsuTestScene + { + [Test] + public void TestRetrieveTopLevelSample() + { + ISkin skin = null; + SampleChannel channel = null; + + AddStep("create skin", () => skin = new TestSkin("test-sample", Audio)); + AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample"))); + + AddAssert("sample is non-null", () => channel != null); + } + + [Test] + public void TestRetrieveSampleInSubFolder() + { + ISkin skin = null; + SampleChannel channel = null; + + AddStep("create skin", () => skin = new TestSkin("folder/test-sample", Audio)); + AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample"))); + + AddAssert("sample is non-null", () => channel != null); + } + + private class TestSkin : LegacySkin + { + public TestSkin(string resourceName, AudioManager audioManager) + : base(DefaultLegacySkin.Info, new TestResourceStore(resourceName), audioManager, "skin.ini") + { + } + } + + private class TestResourceStore : IResourceStore + { + private readonly string resourceName; + + public TestResourceStore(string resourceName) + { + this.resourceName = resourceName; + } + + public byte[] Get(string name) => name == resourceName ? TestResources.GetStore().Get("Resources/test-sample.mp3") : null; + + public Task GetAsync(string name) => name == resourceName ? TestResources.GetStore().GetAsync("Resources/test-sample.mp3") : null; + + public Stream GetStream(string name) => name == resourceName ? TestResources.GetStore().GetStream("Resources/test-sample.mp3") : null; + + public IEnumerable GetAvailableResources() => new[] { resourceName }; + + public void Dispose() + { + } + } + } +} diff --git a/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus.osz b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus.osz new file mode 100644 index 0000000000..987dbea6db Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus.osz differ diff --git a/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus_virtual.osz b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus_virtual.osz new file mode 100644 index 0000000000..8a92423d35 Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus_virtual.osz differ diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index be9f1dd9b0..7588e27b3e 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Resources public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}"); - public static Stream GetTestBeatmapStream(bool virtualTrack = false) => new DllResourceStore(OsuResources.ResourceAssembly).GetStream($"Beatmaps/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz"); + public static Stream GetTestBeatmapStream(bool virtualTrack = false) => OpenResource($"Archives/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz"); public static string GetTestBeatmapForImport(bool virtualTrack = false) { diff --git a/osu.Game.Tests/Resources/test-sample.mp3 b/osu.Game.Tests/Resources/test-sample.mp3 new file mode 100644 index 0000000000..f7c344f39a Binary files /dev/null and b/osu.Game.Tests/Resources/test-sample.mp3 differ diff --git a/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs index 9f16e1d781..3562689482 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs @@ -4,6 +4,8 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose; namespace osu.Game.Tests.Visual.Editor @@ -11,10 +13,21 @@ namespace osu.Game.Tests.Visual.Editor [TestFixture] public class TestSceneComposeScreen : EditorClockTestScene { + [Cached(typeof(EditorBeatmap))] + private readonly EditorBeatmap editorBeatmap = + new EditorBeatmap(new OsuBeatmap + { + BeatmapInfo = + { + Ruleset = new OsuRuleset().RulesetInfo + } + }); + [BackgroundDependencyLoader] private void load() { - Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + Child = new ComposeScreen(); } } diff --git a/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs index 39b4bf7218..847d168e51 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Beatmaps; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components; using osuTK; @@ -21,15 +20,15 @@ namespace osu.Game.Tests.Visual.Editor private const double beat_length = 100; private static readonly Vector2 grid_position = new Vector2(512, 384); - [Cached(typeof(IEditorBeatmap))] - private readonly EditorBeatmap editorBeatmap; + [Cached(typeof(EditorBeatmap))] + private readonly EditorBeatmap editorBeatmap; [Cached(typeof(IDistanceSnapProvider))] private readonly SnapProvider snapProvider = new SnapProvider(); public TestSceneDistanceSnapGrid() { - editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + editorBeatmap = new EditorBeatmap(new OsuBeatmap()); editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length }); } diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs index ed6bc5fe0c..29575cb42e 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Editor { Beatmap.Value = new WaveformTestBeatmap(audio); - var editorBeatmap = new EditorBeatmap((Beatmap)Beatmap.Value.Beatmap); + var editorBeatmap = new EditorBeatmap((Beatmap)Beatmap.Value.Beatmap); Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs index b7c7028b52..c001c83877 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components; using osuTK; @@ -59,9 +60,12 @@ namespace osu.Game.Tests.Visual.Editor }, }); + var editorBeatmap = new EditorBeatmap(Beatmap.Value.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); + var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; Dependencies.CacheAs(clock); Dependencies.CacheAs(clock); + Dependencies.CacheAs(editorBeatmap); Child = new OsuHitObjectComposer(new OsuRuleset()); } diff --git a/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs index 121853d8d0..adfed9a299 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs @@ -5,7 +5,8 @@ using System; using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Timing; namespace osu.Game.Tests.Visual.Editor @@ -25,10 +26,13 @@ namespace osu.Game.Tests.Visual.Editor typeof(RowAttribute) }; + [Cached(typeof(EditorBeatmap))] + private readonly EditorBeatmap editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + [BackgroundDependencyLoader] private void load() { - Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); Child = new TimingScreen(); } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 63b8acb234..63b46c991f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online typeof(ProfileHeader), typeof(RankGraph), typeof(LineGraph), - typeof(OverlayHeaderTabControl), + typeof(TabControlOverlayHeader.OverlayHeaderTabControl), typeof(CentreHeaderContainer), typeof(BottomHeaderContainer), typeof(DetailHeaderContainer), diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbs.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs similarity index 92% rename from osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbs.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs index 554696765e..19eebc89b6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbs.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs @@ -10,11 +10,11 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneBreadcrumbs : OsuTestScene + public class TestSceneBreadcrumbControl : OsuTestScene { private readonly BreadcrumbControl breadcrumbs; - public TestSceneBreadcrumbs() + public TestSceneBreadcrumbControl() { Add(breadcrumbs = new BreadcrumbControl { diff --git a/osu.Game/Audio/HitSampleInfo.cs b/osu.Game/Audio/HitSampleInfo.cs index 23a74d3fa6..f6b0107bd2 100644 --- a/osu.Game/Audio/HitSampleInfo.cs +++ b/osu.Game/Audio/HitSampleInfo.cs @@ -17,11 +17,6 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - /// - /// An optional ruleset namespace. - /// - public string Namespace; - /// /// The bank to load the sample from. /// @@ -49,15 +44,6 @@ namespace osu.Game.Audio { get { - if (!string.IsNullOrEmpty(Namespace)) - { - if (!string.IsNullOrEmpty(Suffix)) - yield return $"{Namespace}/{Bank}-{Name}{Suffix}"; - - yield return $"{Namespace}/{Bank}-{Name}"; - } - - // check non-namespace as a fallback even when we have a namespace if (!string.IsNullOrEmpty(Suffix)) yield return $"{Bank}-{Name}{Suffix}"; diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index 93ea6bbbe6..e2438cc4cd 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -15,14 +15,13 @@ namespace osu.Game.Graphics.UserInterface public class BreadcrumbControl : OsuTabControl { private const float padding = 10; - private const float item_chevron_size = 10; protected override TabItem CreateTabItem(T value) => new BreadcrumbTabItem(value) { AccentColour = AccentColour, }; - protected override float StripWidth() => base.StripWidth() - (padding + item_chevron_size); + protected override float StripWidth => base.StripWidth - TabContainer.FirstOrDefault()?.Padding.Right ?? 0; public BreadcrumbControl() { @@ -41,8 +40,10 @@ namespace osu.Game.Graphics.UserInterface }; } - private class BreadcrumbTabItem : OsuTabItem, IStateful + protected class BreadcrumbTabItem : OsuTabItem, IStateful { + protected virtual float ChevronSize => 10; + public event Action StateChanged; public readonly SpriteIcon Chevron; @@ -90,12 +91,12 @@ namespace osu.Game.Graphics.UserInterface { Text.Font = Text.Font.With(size: 18); Text.Margin = new MarginPadding { Vertical = 8 }; - Padding = new MarginPadding { Right = padding + item_chevron_size }; + Padding = new MarginPadding { Right = padding + ChevronSize }; Add(Chevron = new SpriteIcon { Anchor = Anchor.CentreRight, Origin = Anchor.CentreLeft, - Size = new Vector2(item_chevron_size), + Size = new Vector2(ChevronSize), Icon = FontAwesome.Solid.ChevronRight, Margin = new MarginPadding { Left = padding }, Alpha = 0f, diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 064cba6adf..ed8904db7e 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -28,8 +28,7 @@ namespace osu.Game.Graphics.UserInterface protected override TabItem CreateTabItem(T value) => new OsuTabItem(value); - protected virtual float StripWidth() => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X; - protected virtual float StripHeight() => 1; + protected virtual float StripWidth => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X; /// /// Whether entries should be automatically populated if is an type. @@ -46,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Height = StripHeight(), + Height = 1, Colour = Color4.White.Opacity(0), }); @@ -99,7 +98,7 @@ namespace osu.Game.Graphics.UserInterface // dont bother calculating if the strip is invisible if (strip.Colour.MaxAlpha > 0) - strip.Width = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth(), 0, 500, Easing.OutQuint); + strip.Width = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth, 0, 500, Easing.OutQuint); } public class OsuTabItem : TabItem, IHasAccentColour diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index ff3618b263..fe8756a4d2 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -34,11 +34,21 @@ namespace osu.Game.Graphics.UserInterface public override bool OnPressed(PlatformAction action) { - // Shift+delete is handled via PlatformAction on macOS. this is not so useful in the context of a SearchTextBox - // as we do not allow arrow key navigation in the first place (ie. the caret should always be at the end of text) - // Avoid handling it here to allow other components to potentially consume the shortcut. - if (action.ActionType == PlatformActionType.CharNext && action.ActionMethod == PlatformActionMethod.Delete) - return false; + switch (action.ActionType) + { + case PlatformActionType.LineEnd: + case PlatformActionType.LineStart: + return false; + + // Shift+delete is handled via PlatformAction on macOS. this is not so useful in the context of a SearchTextBox + // as we do not allow arrow key navigation in the first place (ie. the caret should always be at the end of text) + // Avoid handling it here to allow other components to potentially consume the shortcut. + case PlatformActionType.CharNext: + if (action.ActionMethod == PlatformActionMethod.Delete) + return false; + + break; + } return base.OnPressed(action); } diff --git a/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs b/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs new file mode 100644 index 0000000000..8a82b1f0c0 --- /dev/null +++ b/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays +{ + public abstract class BreadcrumbControlOverlayHeader : OverlayHeader + { + protected OverlayHeaderBreadcrumbControl BreadcrumbControl; + + protected override TabControl CreateTabControl() => BreadcrumbControl = new OverlayHeaderBreadcrumbControl(); + + public class OverlayHeaderBreadcrumbControl : BreadcrumbControl + { + public OverlayHeaderBreadcrumbControl() + { + RelativeSizeAxes = Axes.X; + } + + protected override TabItem CreateTabItem(string value) => new ControlTabItem(value); + + private class ControlTabItem : BreadcrumbTabItem + { + protected override float ChevronSize => 8; + + public ControlTabItem(string value) + : base(value) + { + Text.Font = Text.Font.With(size: 14); + Chevron.Y = 3; + Bar.Height = 0; + } + } + } + } +} diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index 3b6f0d778d..7e47a3e29f 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Changelog { - public class ChangelogHeader : OverlayHeader + public class ChangelogHeader : BreadcrumbControlOverlayHeader { public readonly Bindable Current = new Bindable(); @@ -23,12 +23,12 @@ namespace osu.Game.Overlays.Changelog public UpdateStreamBadgeArea Streams; - private const string listing_string = "Listing"; + private const string listing_string = "listing"; public ChangelogHeader() { - TabControl.AddItem(listing_string); - TabControl.Current.ValueChanged += e => + BreadcrumbControl.AddItem(listing_string); + BreadcrumbControl.Current.ValueChanged += e => { if (e.NewValue == listing_string) ListingSelected?.Invoke(); @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Changelog [BackgroundDependencyLoader] private void load(OsuColour colours) { - TabControl.AccentColour = colours.Violet; + BreadcrumbControl.AccentColour = colours.Violet; TitleBackgroundColour = colours.GreyVioletDarker; ControlBackgroundColour = colours.GreyVioletDark; } @@ -56,12 +56,12 @@ namespace osu.Game.Overlays.Changelog private void showBuild(ValueChangedEvent e) { if (e.OldValue != null) - TabControl.RemoveItem(e.OldValue.ToString()); + BreadcrumbControl.RemoveItem(e.OldValue.ToString()); if (e.NewValue != null) { - TabControl.AddItem(e.NewValue.ToString()); - TabControl.Current.Value = e.NewValue.ToString(); + BreadcrumbControl.AddItem(e.NewValue.ToString()); + BreadcrumbControl.Current.Value = e.NewValue.ToString(); Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == e.NewValue.UpdateStream.Name); @@ -69,7 +69,7 @@ namespace osu.Game.Overlays.Changelog } else { - TabControl.Current.Value = listing_string; + BreadcrumbControl.Current.Value = listing_string; Streams.Current.Value = null; title.Version = null; } diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index fbc9dfcbd9..15b0079277 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -158,7 +158,8 @@ namespace osu.Game.Overlays private Task initialFetchTask; - private void performAfterFetch(Action action) => fetchListing()?.ContinueWith(_ => Schedule(action)); + private void performAfterFetch(Action action) => fetchListing()?.ContinueWith(_ => + Schedule(action), TaskContinuationOptions.OnlyOnRanToCompletion); private Task fetchListing() { @@ -185,10 +186,10 @@ namespace osu.Game.Overlays tcs.SetResult(true); }); - req.Failure += _ => + req.Failure += e => { initialFetchTask = null; - tcs.SetResult(false); + tcs.SetException(e); }; await API.PerformAsync(req); diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index c1c5113c5e..4ad8e95512 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -9,21 +10,25 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.Direct { - public abstract class DirectPanel : Container + public abstract class DirectPanel : OsuClickableContainer, IHasContextMenu { public readonly BeatmapSetInfo SetInfo; @@ -32,8 +37,6 @@ namespace osu.Game.Overlays.Direct private Container content; - private BeatmapSetOverlay beatmapSetOverlay; - public PreviewTrack Preview => PlayButton.Preview; public Bindable PreviewPlaying => PlayButton?.Playing; @@ -44,6 +47,8 @@ namespace osu.Game.Overlays.Direct protected override Container Content => content; + protected Action ViewBeatmap; + protected DirectPanel(BeatmapSetInfo setInfo) { Debug.Assert(setInfo.OnlineBeatmapSetID != null); @@ -70,8 +75,6 @@ namespace osu.Game.Overlays.Direct [BackgroundDependencyLoader(permitNulls: true)] private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) { - this.beatmapSetOverlay = beatmapSetOverlay; - AddInternal(content = new Container { RelativeSizeAxes = Axes.Both, @@ -88,6 +91,12 @@ namespace osu.Game.Overlays.Direct }, } }); + + Action = ViewBeatmap = () => + { + Debug.Assert(SetInfo.OnlineBeatmapSetID != null); + beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value); + }; } protected override void Update() @@ -120,13 +129,6 @@ namespace osu.Game.Overlays.Direct base.OnHoverLost(e); } - protected override bool OnClick(ClickEvent e) - { - Debug.Assert(SetInfo.OnlineBeatmapSetID != null); - beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value); - return true; - } - protected override void LoadComplete() { base.LoadComplete(); @@ -203,5 +205,10 @@ namespace osu.Game.Overlays.Direct Value = value; } } + + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem("View Beatmap", MenuItemType.Highlighted, ViewBeatmap), + }; } } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index e3cf58ed0a..fc88c86df2 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -12,7 +12,7 @@ using System; namespace osu.Game.Overlays.News { - public class NewsHeader : OverlayHeader + public class NewsHeader : BreadcrumbControlOverlayHeader { private const string front_page_string = "frontpage"; @@ -24,9 +24,9 @@ namespace osu.Game.Overlays.News public NewsHeader() { - TabControl.AddItem(front_page_string); + BreadcrumbControl.AddItem(front_page_string); - TabControl.Current.ValueChanged += e => + BreadcrumbControl.Current.ValueChanged += e => { if (e.NewValue == front_page_string) ShowFrontPage?.Invoke(); @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.News [BackgroundDependencyLoader] private void load(OsuColour colours) { - TabControl.AccentColour = colours.Violet; + BreadcrumbControl.AccentColour = colours.Violet; TitleBackgroundColour = colours.GreyVioletDarker; ControlBackgroundColour = colours.GreyVioletDark; } @@ -46,18 +46,18 @@ namespace osu.Game.Overlays.News private void showPost(ValueChangedEvent e) { if (e.OldValue != null) - TabControl.RemoveItem(e.OldValue); + BreadcrumbControl.RemoveItem(e.OldValue); if (e.NewValue != null) { - TabControl.AddItem(e.NewValue); - TabControl.Current.Value = e.NewValue; + BreadcrumbControl.AddItem(e.NewValue); + BreadcrumbControl.Current.Value = e.NewValue; title.IsReadingPost = true; } else { - TabControl.Current.Value = front_page_string; + BreadcrumbControl.Current.Value = front_page_string; title.IsReadingPost = false; } } diff --git a/osu.Game/Overlays/OverlayHeader.cs b/osu.Game/Overlays/OverlayHeader.cs index 7a397d10c6..53da2da634 100644 --- a/osu.Game/Overlays/OverlayHeader.cs +++ b/osu.Game/Overlays/OverlayHeader.cs @@ -5,6 +5,7 @@ using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osuTK.Graphics; @@ -12,8 +13,6 @@ namespace osu.Game.Overlays { public abstract class OverlayHeader : Container { - protected readonly OverlayHeaderTabControl TabControl; - private readonly Box titleBackground; private readonly Box controlBackground; private readonly Container background; @@ -85,14 +84,7 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = Color4.Gray, }, - TabControl = new OverlayHeaderTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 30, - Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN }, - } + CreateTabControl().With(control => control.Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN }) } }, CreateContent() @@ -106,5 +98,7 @@ namespace osu.Game.Overlays protected virtual Drawable CreateContent() => new Container(); protected abstract ScreenTitle CreateTitle(); + + protected abstract TabControl CreateTabControl(); } } diff --git a/osu.Game/Overlays/OverlayHeaderTabControl.cs b/osu.Game/Overlays/OverlayHeaderTabControl.cs deleted file mode 100644 index 7d0cdad6d8..0000000000 --- a/osu.Game/Overlays/OverlayHeaderTabControl.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.UserInterface; - -namespace osu.Game.Overlays -{ - public class OverlayHeaderTabControl : OverlayTabControl - { - protected override TabItem CreateTabItem(string value) => new OverlayHeaderTabItem(value) - { - AccentColour = AccentColour, - }; - - private class OverlayHeaderTabItem : OverlayTabItem - { - public OverlayHeaderTabItem(string value) - : base(value) - { - Text.Text = value; - } - } - } -} diff --git a/osu.Game/Overlays/OverlayTabControl.cs b/osu.Game/Overlays/OverlayTabControl.cs index 4c396eabc1..812f8963c9 100644 --- a/osu.Game/Overlays/OverlayTabControl.cs +++ b/osu.Game/Overlays/OverlayTabControl.cs @@ -43,6 +43,11 @@ namespace osu.Game.Overlays set => TabContainer.Padding = value; } + protected float BarHeight + { + set => bar.Height = value; + } + protected OverlayTabControl() { TabContainer.Masking = false; @@ -63,8 +68,7 @@ namespace osu.Game.Overlays protected class OverlayTabItem : TabItem { - private readonly ExpandingBar bar; - + protected readonly ExpandingBar Bar; protected readonly OsuSpriteText Text; private Color4 accentColour; @@ -78,7 +82,7 @@ namespace osu.Game.Overlays return; accentColour = value; - bar.Colour = value; + Bar.Colour = value; updateState(); } @@ -99,7 +103,7 @@ namespace osu.Game.Overlays Anchor = Anchor.BottomLeft, Font = OsuFont.GetFont(), }, - bar = new ExpandingBar + Bar = new ExpandingBar { Anchor = Anchor.BottomCentre, ExpandedSize = 7.5f, @@ -149,13 +153,13 @@ namespace osu.Game.Overlays protected virtual void HoverAction() { - bar.Expand(); + Bar.Expand(); Text.FadeColour(Color4.White, 120, Easing.InQuad); } protected virtual void UnhoverAction() { - bar.Collapse(); + Bar.Collapse(); Text.FadeColour(AccentColour, 120, Easing.InQuad); } } diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 4a792f7375..59e64dfc26 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -15,7 +15,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.Profile { - public class ProfileHeader : OverlayHeader + public class ProfileHeader : TabControlOverlayHeader { private UserCoverBackground coverContainer; @@ -30,8 +30,8 @@ namespace osu.Game.Overlays.Profile User.ValueChanged += e => updateDisplay(e.NewValue); - TabControl.AddItem("Info"); - TabControl.AddItem("Modding"); + TabControl.AddItem("info"); + TabControl.AddItem("modding"); centreHeaderContainer.DetailsVisible.BindValueChanged(visible => detailHeaderContainer.Expanded = visible.NewValue, true); } diff --git a/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs b/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs index 37478d902b..5975e94ffc 100644 --- a/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs +++ b/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; namespace osu.Game.Overlays.SearchableList { @@ -61,21 +62,20 @@ namespace osu.Game.Overlays.SearchableList scrollContainer = new Container { RelativeSizeAxes = Axes.Both, - Children = new[] + Child = new OsuContextMenuContainer { - new OsuScrollContainer + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, - Children = new[] + Child = ScrollFlow = new FillFlowContainer { - ScrollFlow = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Horizontal = WIDTH_PADDING, Bottom = 50 }, - Direction = FillDirection.Vertical, - }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = WIDTH_PADDING, Bottom = 50 }, + Direction = FillDirection.Vertical, }, }, }, diff --git a/osu.Game/Overlays/TabControlOverlayHeader.cs b/osu.Game/Overlays/TabControlOverlayHeader.cs new file mode 100644 index 0000000000..f3521b66c8 --- /dev/null +++ b/osu.Game/Overlays/TabControlOverlayHeader.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osuTK; + +namespace osu.Game.Overlays +{ + public abstract class TabControlOverlayHeader : OverlayHeader + { + protected OverlayHeaderTabControl TabControl; + + protected override TabControl CreateTabControl() => TabControl = new OverlayHeaderTabControl(); + + public class OverlayHeaderTabControl : OverlayTabControl + { + public OverlayHeaderTabControl() + { + BarHeight = 1; + RelativeSizeAxes = Axes.None; + AutoSizeAxes = Axes.X; + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + Height = 35; + } + + protected override TabItem CreateTabItem(string value) => new OverlayHeaderTabItem(value) + { + AccentColour = AccentColour, + }; + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + }; + + private class OverlayHeaderTabItem : OverlayTabItem + { + public OverlayHeaderTabItem(string value) + : base(value) + { + Text.Text = value; + Text.Font = OsuFont.GetFont(size: 14); + Bar.ExpandedSize = 5; + } + } + } + } +} diff --git a/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs b/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs index 4710465536..89e7866707 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Edit private readonly DrawableRuleset drawableRuleset; [Resolved] - private IEditorBeatmap beatmap { get; set; } + private EditorBeatmap beatmap { get; set; } public DrawableEditRulesetWrapper(DrawableRuleset drawableRuleset) { diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 22d94abcb9..bfaa7e8872 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; @@ -35,20 +34,20 @@ namespace osu.Game.Rulesets.Edit { protected IRulesetConfigManager Config { get; private set; } - protected new EditorBeatmap EditorBeatmap { get; private set; } - protected readonly Ruleset Ruleset; [Resolved] protected IFrameBasedClock EditorClock { get; private set; } + [Resolved] + protected EditorBeatmap EditorBeatmap { get; private set; } + [Resolved] private IAdjustableClock adjustableClock { get; set; } [Resolved] private BindableBeatDivisor beatDivisor { get; set; } - private Beatmap playableBeatmap; private IBeatmapProcessor beatmapProcessor; private DrawableEditRulesetWrapper drawableRulesetWrapper; @@ -68,9 +67,17 @@ namespace osu.Game.Rulesets.Edit [BackgroundDependencyLoader] private void load(IFrameBasedClock framedClock) { + beatmapProcessor = Ruleset.CreateBeatmapProcessor(EditorBeatmap.PlayableBeatmap); + + EditorBeatmap.HitObjectAdded += addHitObject; + EditorBeatmap.HitObjectRemoved += removeHitObject; + EditorBeatmap.StartTimeChanged += UpdateHitObject; + + Config = Dependencies.Get().GetConfigFor(Ruleset); + try { - drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, playableBeatmap)) + drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap)) { Clock = framedClock, ProcessCustomClock = false @@ -140,28 +147,6 @@ namespace osu.Game.Rulesets.Edit blueprintContainer.SelectionChanged += selectionChanged; } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var parentWorkingBeatmap = parent.Get>().Value; - - playableBeatmap = (Beatmap)parentWorkingBeatmap.GetPlayableBeatmap(Ruleset.RulesetInfo); - - beatmapProcessor = Ruleset.CreateBeatmapProcessor(playableBeatmap); - - base.EditorBeatmap = EditorBeatmap = new EditorBeatmap(playableBeatmap); - EditorBeatmap.HitObjectAdded += addHitObject; - EditorBeatmap.HitObjectRemoved += removeHitObject; - EditorBeatmap.StartTimeChanged += UpdateHitObject; - - var dependencies = new DependencyContainer(parent); - dependencies.CacheAs(EditorBeatmap); - dependencies.CacheAs>(EditorBeatmap); - - Config = dependencies.Get().GetConfigFor(Ruleset); - - return base.CreateChildDependencies(dependencies); - } - protected override void LoadComplete() { base.LoadComplete(); @@ -234,7 +219,7 @@ namespace osu.Game.Rulesets.Edit scheduledUpdate = Schedule(() => { beatmapProcessor?.PreProcess(); - hitObject?.ApplyDefaults(playableBeatmap.ControlPointInfo, playableBeatmap.BeatmapInfo.BaseDifficulty); + hitObject?.ApplyDefaults(EditorBeatmap.ControlPointInfo, EditorBeatmap.BeatmapInfo.BaseDifficulty); beatmapProcessor?.PostProcess(); }); } @@ -333,11 +318,6 @@ namespace osu.Game.Rulesets.Edit /// public abstract IEnumerable HitObjects { get; } - /// - /// An editor-specific beatmap, exposing mutation events. - /// - public IEditorBeatmap EditorBeatmap { get; protected set; } - /// /// Whether the user's cursor is currently in an area of the that is valid for placement. /// diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index a959fee9be..4ac30fe7fb 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -31,9 +31,6 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public readonly Bindable AccentColour = new Bindable(Color4.Gray); - // Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first - protected virtual string SampleNamespace => null; - protected SkinnableSound Samples { get; private set; } protected virtual IEnumerable GetSamples() => HitObject.Samples; @@ -154,11 +151,7 @@ namespace osu.Game.Rulesets.Objects.Drawables + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); } - samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray(); - foreach (var s in samples) - s.Namespace = SampleNamespace; - - AddInternal(Samples = new SkinnableSound(samples)); + AddInternal(Samples = new SkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)))); } private void onDefaultsApplied() => apply(HitObject); diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 195bc663f1..cafaddc39e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Edit.Compose.Components private HitObjectComposer composer { get; set; } [Resolved] - private IEditorBeatmap beatmap { get; set; } + private EditorBeatmap beatmap { get; set; } public BlueprintContainer() { diff --git a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs index 00326d04f7..53c5cf97fa 100644 --- a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Edit.Compose.Components protected IDistanceSnapProvider SnapProvider { get; private set; } [Resolved] - private IEditorBeatmap beatmap { get; set; } + private EditorBeatmap beatmap { get; set; } [Resolved] private BindableBeatDivisor beatDivisor { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectDisplay.cs index db4aca75e5..b20f2fa11d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectDisplay.cs @@ -16,9 +16,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { internal class TimelineHitObjectDisplay : TimelinePart { - private IEditorBeatmap beatmap { get; } + private EditorBeatmap beatmap { get; } - public TimelineHitObjectDisplay(IEditorBeatmap beatmap) + public TimelineHitObjectDisplay(EditorBeatmap beatmap) { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 5d9757778d..1a6aae294a 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -32,6 +32,6 @@ namespace osu.Game.Screens.Edit.Compose return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(composer)); } - protected override Drawable CreateTimelineContent() => composer == null ? base.CreateTimelineContent() : new TimelineHitObjectDisplay(composer.EditorBeatmap); + protected override Drawable CreateTimelineContent() => composer == null ? base.CreateTimelineContent() : new TimelineHitObjectDisplay(EditorBeatmap); } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 1b4964c068..14d69cddd1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -23,6 +23,7 @@ using osuTK.Input; using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; +using osu.Game.Beatmaps; using osu.Game.Graphics.Cursor; using osu.Game.Input.Bindings; using osu.Game.Screens.Edit.Compose; @@ -49,9 +50,11 @@ namespace osu.Game.Screens.Edit private EditorScreen currentScreen; private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - private EditorClock clock; + private IBeatmap playableBeatmap; + private EditorBeatmap editorBeatmap; + private DependencyContainer dependencies; private GameHost host; @@ -73,9 +76,13 @@ namespace osu.Game.Screens.Edit clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false }; clock.ChangeSource(sourceClock); + playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); + editorBeatmap = new EditorBeatmap(playableBeatmap); + dependencies.CacheAs(clock); dependencies.CacheAs(clock); dependencies.Cache(beatDivisor); + dependencies.CacheAs(editorBeatmap); EditorMenuBar menuBar; diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index c3a322ea36..6ed74dfdb0 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections; using System.Collections.Generic; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -11,30 +12,30 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Edit { - public class EditorBeatmap : IEditorBeatmap - where T : HitObject + public class EditorBeatmap : IBeatmap { /// - /// Invoked when a is added to this . + /// Invoked when a is added to this . /// public event Action HitObjectAdded; /// - /// Invoked when a is removed from this . + /// Invoked when a is removed from this . /// public event Action HitObjectRemoved; /// - /// Invoked when the start time of a in this was changed. + /// Invoked when the start time of a in this was changed. /// public event Action StartTimeChanged; - private readonly Dictionary> startTimeBindables = new Dictionary>(); - private readonly Beatmap beatmap; + public readonly IBeatmap PlayableBeatmap; - public EditorBeatmap(Beatmap beatmap) + private readonly Dictionary> startTimeBindables = new Dictionary>(); + + public EditorBeatmap(IBeatmap playableBeatmap) { - this.beatmap = beatmap; + PlayableBeatmap = playableBeatmap; foreach (var obj in HitObjects) trackStartTime(obj); @@ -42,82 +43,83 @@ namespace osu.Game.Screens.Edit public BeatmapInfo BeatmapInfo { - get => beatmap.BeatmapInfo; - set => beatmap.BeatmapInfo = value; + get => PlayableBeatmap.BeatmapInfo; + set => PlayableBeatmap.BeatmapInfo = value; } - public BeatmapMetadata Metadata => beatmap.Metadata; + public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; - public ControlPointInfo ControlPointInfo => beatmap.ControlPointInfo; + public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; - public List Breaks => beatmap.Breaks; + public List Breaks => PlayableBeatmap.Breaks; - public double TotalBreakTime => beatmap.TotalBreakTime; + public double TotalBreakTime => PlayableBeatmap.TotalBreakTime; - public IReadOnlyList HitObjects => beatmap.HitObjects; + public IReadOnlyList HitObjects => PlayableBeatmap.HitObjects; - IReadOnlyList IBeatmap.HitObjects => beatmap.HitObjects; + public IEnumerable GetStatistics() => PlayableBeatmap.GetStatistics(); - public IEnumerable GetStatistics() => beatmap.GetStatistics(); + public IBeatmap Clone() => (EditorBeatmap)MemberwiseClone(); - public IBeatmap Clone() => (EditorBeatmap)MemberwiseClone(); + private IList mutableHitObjects => (IList)PlayableBeatmap.HitObjects; /// - /// Adds a to this . + /// Adds a to this . /// /// The to add. - public void Add(T hitObject) + public void Add(HitObject hitObject) { trackStartTime(hitObject); // Preserve existing sorting order in the beatmap - var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); - beatmap.HitObjects.Insert(insertionIndex + 1, hitObject); + var insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime); + mutableHitObjects.Insert(insertionIndex + 1, hitObject); HitObjectAdded?.Invoke(hitObject); } /// - /// Removes a from this . + /// Removes a from this . /// /// The to add. - public void Remove(T hitObject) + public void Remove(HitObject hitObject) { - if (beatmap.HitObjects.Remove(hitObject)) - { - var bindable = startTimeBindables[hitObject]; - bindable.UnbindAll(); + if (!mutableHitObjects.Contains(hitObject)) + return; - startTimeBindables.Remove(hitObject); - HitObjectRemoved?.Invoke(hitObject); - } + mutableHitObjects.Remove(hitObject); + + var bindable = startTimeBindables[hitObject]; + bindable.UnbindAll(); + + startTimeBindables.Remove(hitObject); + HitObjectRemoved?.Invoke(hitObject); } - private void trackStartTime(T hitObject) + private void trackStartTime(HitObject hitObject) { startTimeBindables[hitObject] = hitObject.StartTimeBindable.GetBoundCopy(); startTimeBindables[hitObject].ValueChanged += _ => { // For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required. - beatmap.HitObjects.Remove(hitObject); + mutableHitObjects.Remove(hitObject); - var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); - beatmap.HitObjects.Insert(insertionIndex + 1, hitObject); + var insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime); + mutableHitObjects.Insert(insertionIndex + 1, hitObject); StartTimeChanged?.Invoke(hitObject); }; } - /// - /// Adds a to this . - /// - /// The to add. - public void Add(HitObject hitObject) => Add((T)hitObject); + private int findInsertionIndex(IReadOnlyList list, double startTime) + { + for (int i = 0; i < list.Count; i++) + { + if (list[i].StartTime > startTime) + return i - 1; + } - /// - /// Removes a from this . - /// - /// The to add. - public void Remove(HitObject hitObject) => Remove((T)hitObject); + return list.Count - 1; + } } } diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 1b57c703ae..d42447ac4b 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -17,6 +17,9 @@ namespace osu.Game.Screens.Edit [Resolved] protected IBindable Beatmap { get; private set; } + [Resolved] + protected EditorBeatmap EditorBeatmap { get; private set; } + protected override Container Content => content; private readonly Container content; diff --git a/osu.Game/Screens/Edit/IEditorBeatmap.cs b/osu.Game/Screens/Edit/IEditorBeatmap.cs deleted file mode 100644 index 3e3418ef79..0000000000 --- a/osu.Game/Screens/Edit/IEditorBeatmap.cs +++ /dev/null @@ -1,41 +0,0 @@ -// 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 osu.Game.Beatmaps; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects; - -namespace osu.Game.Screens.Edit -{ - /// - /// Interface for the contained by the see . - /// Children of may resolve the beatmap via or . - /// - public interface IEditorBeatmap : IBeatmap - { - /// - /// Invoked when a is added to this . - /// - event Action HitObjectAdded; - - /// - /// Invoked when a is removed from this . - /// - event Action HitObjectRemoved; - - /// - /// Invoked when the start time of a in this was changed. - /// - event Action StartTimeChanged; - } - - /// - /// Interface for the contained by the see . - /// Children of may resolve the beatmap via or . - /// - public interface IEditorBeatmap : IEditorBeatmap, IBeatmap - where T : HitObject - { - } -} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 48c520986a..671d37fda4 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -175,7 +175,7 @@ namespace osu.Game.Skinning { foreach (var lookup in sampleInfo.LookupNames) { - var sample = Samples?.Get(getFallbackName(lookup)); + var sample = Samples?.Get(lookup); if (sample != null) return sample; diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 18dbd212cc..8926c76018 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual } [Resolved] - private AudioManager audio { get; set; } + protected AudioManager Audio { get; private set; } protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset); @@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual CreateWorkingBeatmap(CreateBeatmap(ruleset), null); protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => - new ClockBackedTestWorkingBeatmap(beatmap, storyboard, Clock, audio); + new ClockBackedTestWorkingBeatmap(beatmap, storyboard, Clock, Audio); [BackgroundDependencyLoader] private void load(RulesetStore rulesets) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 806aadde84..565608b40f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -22,7 +22,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 230ff01cce..60355b8592 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -73,7 +73,7 @@ - + diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index 5ceccdf99f..249474b1d7 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -14,8 +14,6 @@ 0.1.0 LSRequiresIPhoneOS - LSSupportsOpeningDocumentsInPlace - MinimumOSVersion 10.0 UIDeviceFamily @@ -23,6 +21,8 @@ 1 2 + UIFileSharingEnabled + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -51,7 +51,7 @@ UTTypeConformsTo - + public.data UTTypeIdentifier sh.ppy.osu.items @@ -105,6 +105,8 @@ Owner CFBundleTypeName Supported osu! files + CFBundleTypeRole + Viewer LSItemContentTypes sh.ppy.osu.items