From 2ff8a36ec542fe5403cb37c0bffb3fae477a875e Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:07:05 +0800 Subject: [PATCH 1/8] Fix the naming. --- .../Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs index 01cc75150..b02254057 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs @@ -55,12 +55,12 @@ public ClassicLyricTimingInfo() break; } - onPageChanged(); + onTimingChanged(); - void timeValueChanged(ValueChangedEvent e) => onPageChanged(); + void timeValueChanged(ValueChangedEvent e) => onTimingChanged(); }; - void onPageChanged() + void onTimingChanged() { SortedTimings = Timings.OrderBy(x => x.Time).ToList(); timingVersion.Value++; From 661526be43cb8657b2f0149bdc1d68aa71b35920 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:07:39 +0800 Subject: [PATCH 2/8] Make the code happy. --- .../Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs index b02254057..9421ef929 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs @@ -20,7 +20,7 @@ public class ClassicLyricTimingInfo private readonly Bindable timingVersion = new(); // todo: should be readonly. - public BindableList Timings = new BindableList(); + public BindableList Timings = new(); [JsonIgnore] public List SortedTimings { get; private set; } = new(); From a4e3b3add06407aff3a0e0c0b525bba11d9843cd Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:14:20 +0800 Subject: [PATCH 3/8] Implement the method for able to get the timing point order. --- .../Stages/Classic/ClassicLyricTimingInfoTest.cs | 15 +++++++++++++++ .../Stages/Classic/ClassicLyricTimingInfo.cs | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Stages/Classic/ClassicLyricTimingInfoTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Stages/Classic/ClassicLyricTimingInfoTest.cs index fa47298a3..eaa7cbd61 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Stages/Classic/ClassicLyricTimingInfoTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Stages/Classic/ClassicLyricTimingInfoTest.cs @@ -153,6 +153,21 @@ public void TestClearLyricFromMapping() #region Query + [Test] + public void TestGetTimingPointOrder() + { + var timingInfo = new ClassicLyricTimingInfo(); + timingInfo.Timings.AddRange(new[] { new ClassicLyricTimingPoint { Time = 1000 } }); + + var existTimingPoint = timingInfo.Timings.First(); + int? existTimingPointOrder = timingInfo.GetTimingPointOrder(existTimingPoint); + Assert.AreEqual(1, existTimingPointOrder); + + var notExistTimingPoint = new ClassicLyricTimingPoint { Time = 1000 }; + int? notExistTimingPointOrder = timingInfo.GetTimingPointOrder(notExistTimingPoint); + Assert.IsNull(notExistTimingPointOrder); + } + [Test] public void TestGetLyricTimingPoints() { diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs index 9421ef929..ed578f479 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Stages/Classic/ClassicLyricTimingInfo.cs @@ -175,6 +175,12 @@ public void ClearLyricFromMapping(Lyric lyric) #region Query + public int? GetTimingPointOrder(ClassicLyricTimingPoint point) + { + int index = SortedTimings.IndexOf(point); + return index == -1 ? null : index + 1; + } + public IEnumerable GetLyricTimingPoints(Lyric lyric) { if (!Mappings.TryGetValue(lyric.ID, out int[]? ids)) From 13f3ece38743f4aa9ecea035391b2bc20bd8560c Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:16:51 +0800 Subject: [PATCH 4/8] Implement method for able to get the target stage from the karaoke beatmap. --- osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmap.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmap.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmap.cs index 223eff717..73497a912 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmap.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmap.cs @@ -26,6 +26,8 @@ public class KaraokeBeatmap : Beatmap public int TotalColumns { get; set; } = 9; + public TStageInfo? GetStageInfo() => StageInfos.OfType().FirstOrDefault(); + public override IEnumerable GetStatistics() { int singers = SingerInfo.GetAllSingers().Count(); From 1dd70a0a69883b0e8743041f5be6bd88ef38efd8 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:16:58 +0800 Subject: [PATCH 5/8] Should be able to get the stage info in the provider. Also, should make sure that the classic stage info should be exist in the beatmap. --- .../Stages/Classic/Stage/IStageEditorStateProvider.cs | 3 +++ .../Screens/Edit/Stages/Classic/Stage/StageScreen.cs | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/IStageEditorStateProvider.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/IStageEditorStateProvider.cs index 7daaaa342..48124d88a 100644 --- a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/IStageEditorStateProvider.cs +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/IStageEditorStateProvider.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; +using osu.Game.Rulesets.Karaoke.Beatmaps.Stages.Classic; namespace osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic.Stage; @@ -18,4 +19,6 @@ public interface IStageEditorStateProvider StageEditorEditMode EditMode => BindableEditMode.Value; void ChangeEditMode(StageEditorEditMode mode); + + ClassicStageInfo StageInfo { get; } } diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs index 94e7c805d..9373a0fb8 100644 --- a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs @@ -1,11 +1,16 @@ // Copyright (c) andy840119 . Licensed under the GPL Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Diagnostics.CodeAnalysis; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Karaoke.Beatmaps; +using osu.Game.Rulesets.Karaoke.Beatmaps.Stages.Classic; using osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic.Stage.Settings; +using osu.Game.Screens.Edit; namespace osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic.Stage; @@ -21,6 +26,12 @@ public partial class StageScreen : ClassicStageScreen, IStageEditorStateProvider [Cached(typeof(IStageEditorVerifier))] private readonly StageEditorVerifier stageEditorVerifier; + [Resolved, AllowNull] + private EditorBeatmap editorBeatmap { get; set; } + + public ClassicStageInfo StageInfo => (editorBeatmap.PlayableBeatmap as KaraokeBeatmap)!.GetStageInfo() + ?? throw new InvalidOperationException(); + public StageScreen() : base(ClassicStageEditorScreenMode.Stage) { From c28ea215e773c6de5cfb1f265fd628d376425c36 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:34:49 +0800 Subject: [PATCH 6/8] Add missing injection. --- .../Screens/Edit/Stages/Classic/Stage/StageScreen.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs index 9373a0fb8..49729e5a6 100644 --- a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/StageScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Karaoke.Beatmaps; using osu.Game.Rulesets.Karaoke.Beatmaps.Stages.Classic; +using osu.Game.Rulesets.Karaoke.Edit.ChangeHandlers.Beatmaps; using osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic.Stage.Settings; using osu.Game.Screens.Edit; @@ -23,6 +24,9 @@ public partial class StageScreen : ClassicStageScreen, IStageEditorStateProvider private readonly Bindable bindableCategory = new(); private readonly Bindable bindableEditMode = new(); + [Cached(typeof(IBeatmapClassicStageChangeHandler))] + private readonly BeatmapClassicStageChangeHandler beatmapClassicStageChangeHandler; + [Cached(typeof(IStageEditorVerifier))] private readonly StageEditorVerifier stageEditorVerifier; @@ -35,6 +39,7 @@ public partial class StageScreen : ClassicStageScreen, IStageEditorStateProvider public StageScreen() : base(ClassicStageEditorScreenMode.Stage) { + AddInternal(beatmapClassicStageChangeHandler = new BeatmapClassicStageChangeHandler()); AddInternal(stageEditorVerifier = new StageEditorVerifier()); Child = new GridContainer From 29464af059d15e3422318243e2fbcbee06dfea52 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:34:41 +0800 Subject: [PATCH 7/8] Implement the timing info and apply into the setting section. --- .../Classic/Stage/Settings/StageSettings.cs | 1 + .../Stage/Settings/TimingPointsSection.cs | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/TimingPointsSection.cs diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/StageSettings.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/StageSettings.cs index 767539a45..22ced18a4 100644 --- a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/StageSettings.cs +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/StageSettings.cs @@ -61,6 +61,7 @@ private void load(OverlayColourProvider colourProvider, IStageEditorStateProvide StageEditorEditMode.Edit => new Drawable[] { new StageEditorEditModeSection(StageEditorEditCategory.Timing), + new TimingPointsSection(), }, StageEditorEditMode.Verify => new Drawable[] { diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/TimingPointsSection.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/TimingPointsSection.cs new file mode 100644 index 000000000..1b355b8bf --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Stages/Classic/Stage/Settings/TimingPointsSection.cs @@ -0,0 +1,87 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics.CodeAnalysis; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Localisation; +using osu.Game.Extensions; +using osu.Game.Rulesets.Karaoke.Beatmaps.Stages.Classic; +using osu.Game.Rulesets.Karaoke.Edit.ChangeHandlers.Beatmaps; +using osu.Game.Screens.Edit; + +namespace osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic.Stage.Settings; + +public partial class TimingPointsSection : EditorSection +{ + protected override LocalisableString Title => "Timings"; + + public TimingPointsSection() + { + Add(new SectionPageInfoEditor()); + } + + private partial class SectionPageInfoEditor : SectionTimingInfoItemsEditor + { + [BackgroundDependencyLoader] + private void load(IStageEditorStateProvider stageEditorStateProvider) + { + Items.BindTo(stageEditorStateProvider.StageInfo.LyricTimingInfo.Timings); + } + + protected override DrawableTimingInfoItem CreateTimingInfoDrawable(ClassicLyricTimingPoint item) => new DrawableTimingPoint(item); + + protected override EditorSectionButton? CreateCreateNewItemButton() => new CreateNewTimingPointButton(); + + private partial class DrawableTimingPoint : DrawableTimingInfoItem + { + private readonly IBindable timingPointsVersion = new Bindable(); + + [Resolved, AllowNull] + private IBeatmapClassicStageChangeHandler beatmapClassicStageChangeHandler { get; set; } + + public DrawableTimingPoint(ClassicLyricTimingPoint item) + : base(item) + { + } + + protected override void RemoveItem(ClassicLyricTimingPoint item) + { + beatmapClassicStageChangeHandler.RemoveTimingPoint(item); + } + + [BackgroundDependencyLoader] + private void load(IStageEditorStateProvider stageEditorStateProvider) + { + timingPointsVersion.BindTo(stageEditorStateProvider.StageInfo.LyricTimingInfo.TimingVersion); + timingPointsVersion.BindValueChanged(_ => + { + int? order = stageEditorStateProvider.StageInfo.LyricTimingInfo.GetTimingPointOrder(Item); + double time = Item.Time; + + ChangeDisplayOrder((int)time); + Text = $"#{order} {time.ToEditorFormattedString()}"; + }, true); + } + } + + private partial class CreateNewTimingPointButton : EditorSectionButton + { + [Resolved, AllowNull] + private IBeatmapClassicStageChangeHandler beatmapClassicStageChangeHandler { get; set; } + + [Resolved, AllowNull] + private EditorClock clock { get; set; } + + public CreateNewTimingPointButton() + { + Text = "Create new timing"; + Action = () => + { + double currentTime = clock.CurrentTime; + beatmapClassicStageChangeHandler.AddTimingPoint(x => x.Time = currentTime); + }; + } + } + } +} From 795a49098b77453d423cd3fcd6299dd6147df953 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 18 Jan 2023 22:34:29 +0800 Subject: [PATCH 8/8] Add the classic stage info into the test case for let the editor works. --- .../Edit/Stages/Classic/ClassicStageScreenTestScene.cs | 4 ++++ .../Edit/Stages/Classic/TestSceneClassicStageEditor.cs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/ClassicStageScreenTestScene.cs b/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/ClassicStageScreenTestScene.cs index 37e3a6d8f..c57d484d6 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/ClassicStageScreenTestScene.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/ClassicStageScreenTestScene.cs @@ -8,6 +8,7 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Karaoke.Beatmaps; +using osu.Game.Rulesets.Karaoke.Beatmaps.Stages.Classic; using osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic; using osu.Game.Rulesets.Karaoke.Tests.Beatmaps; using osu.Game.Screens.Edit; @@ -49,6 +50,9 @@ protected virtual KaraokeBeatmap CreateBeatmap() if (new KaraokeBeatmapConverter(beatmap, new KaraokeRuleset()).Convert() is not KaraokeBeatmap karaokeBeatmap) throw new ArgumentNullException(nameof(karaokeBeatmap)); + // add classic stage info for testing purpose. + karaokeBeatmap.StageInfos.Add(new ClassicStageInfo()); + return karaokeBeatmap; } } diff --git a/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/TestSceneClassicStageEditor.cs b/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/TestSceneClassicStageEditor.cs index 32001cb9f..135838e00 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/TestSceneClassicStageEditor.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Screens/Edit/Stages/Classic/TestSceneClassicStageEditor.cs @@ -7,6 +7,7 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Karaoke.Beatmaps; +using osu.Game.Rulesets.Karaoke.Beatmaps.Stages.Classic; using osu.Game.Rulesets.Karaoke.Screens.Edit.Stages.Classic; using osu.Game.Rulesets.Karaoke.Tests.Beatmaps; using osu.Game.Screens.Edit; @@ -29,6 +30,10 @@ public TestSceneClassicStageEditor() { var beatmap = new TestKaraokeBeatmap(new KaraokeRuleset().RulesetInfo); var karaokeBeatmap = new KaraokeBeatmapConverter(beatmap, new KaraokeRuleset()).Convert() as KaraokeBeatmap; + + // add classic stage info for testing purpose. + karaokeBeatmap!.StageInfos.Add(new ClassicStageInfo()); + editorBeatmap = new EditorBeatmap(karaokeBeatmap); }