diff --git a/osu.Game.Rulesets.Karaoke.Tests/Objects/HitObjectValidatorTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Flags/FlagStateTest.cs similarity index 91% rename from osu.Game.Rulesets.Karaoke.Tests/Objects/HitObjectValidatorTest.cs rename to osu.Game.Rulesets.Karaoke.Tests/Flags/FlagStateTest.cs index 5a323fd0c..8373d3ea1 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Objects/HitObjectValidatorTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Flags/FlagStateTest.cs @@ -4,11 +4,11 @@ using System; using System.Linq; using NUnit.Framework; -using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Karaoke.Flags; -namespace osu.Game.Rulesets.Karaoke.Tests.Objects; +namespace osu.Game.Rulesets.Karaoke.Tests.Flags; -public class HitObjectValidatorTest +public class FlagStateTest { [TestCase(default, new[] { TestEnum.Enum0, TestEnum.Enum1, TestEnum.Enum2 })] [TestCase(TestEnum.Enum0, new[] { TestEnum.Enum1, TestEnum.Enum2 })] @@ -18,7 +18,7 @@ public class HitObjectValidatorTest [TestCase(TestEnum.Enum0 | TestEnum.Enum0, new[] { TestEnum.Enum1, TestEnum.Enum2 })] // Test edge case. public void TestInvalidate(TestEnum invalidFlags, TestEnum[] expectedValue) { - var validator = new HitObjectValidator(); + var validator = new FlagState(); validator.ValidateAll(); // check the value. @@ -43,7 +43,7 @@ public void TestInvalidate(TestEnum invalidFlags, TestEnum[] expectedValue) [TestCase(TestEnum.Enum0 | TestEnum.Enum0)] // Test edge case. public void TestInvalidateAll(TestEnum defaultFlags) { - var validator = new HitObjectValidator(); + var validator = new FlagState(); validator.Validate(defaultFlags); // check the value. @@ -61,7 +61,7 @@ public void TestInvalidateAll(TestEnum defaultFlags) [TestCase(TestEnum.Enum2 | TestEnum.Enum2, new[] { TestEnum.Enum2 })] // Test edge case. public void TestValidate(TestEnum validateFlags, TestEnum[] expectedValue) { - var validator = new HitObjectValidator(); + var validator = new FlagState(); // check the value. validator.Validate(validateFlags); @@ -85,7 +85,7 @@ public void TestValidate(TestEnum validateFlags, TestEnum[] expectedValue) [TestCase(TestEnum.Enum0 | TestEnum.Enum0)] // Test edge case. public void TestValidateAll(TestEnum validateFlags) { - var validator = new HitObjectValidator(); + var validator = new FlagState(); // check the value. validator.ValidateAll(); @@ -104,7 +104,7 @@ public void TestValidateAll(TestEnum validateFlags) [TestCase(TestEnum.Enum2 | TestEnum.Enum2, TestEnum.Enum2, true)] // Test edge case. public void TestIsValid(TestEnum validateFlags, TestEnum validFlag, bool expectedValue) { - var validator = new HitObjectValidator(); + var validator = new FlagState(); // check the value. validator.Validate(validateFlags); @@ -114,7 +114,7 @@ public void TestIsValid(TestEnum validateFlags, TestEnum validFlag, bool expecte [Test] public void TestGetAllValidFlags() { - var validator = new HitObjectValidator(); + var validator = new FlagState(); // Should be possible to get all tags. validator.ValidateAll(); @@ -128,7 +128,7 @@ public void TestGetAllValidFlags() [Test] public void TestGetAllInvalidFlags() { - var validator = new HitObjectValidator(); + var validator = new FlagState(); // Should be possible to get all tags. validator.ValidateAll(); diff --git a/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/HitObjectWorkingPropertyValidatorTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/HitObjectWorkingPropertyValidatorTest.cs new file mode 100644 index 000000000..a7243643b --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/HitObjectWorkingPropertyValidatorTest.cs @@ -0,0 +1,38 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using NUnit.Framework; +using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Karaoke.Objects.Workings; + +namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings; + +public abstract class HitObjectWorkingPropertyValidatorTest + where TFlag : struct, Enum + where THitObject : KaraokeHitObject, new() +{ + protected abstract HitObjectWorkingPropertyValidator GetValidatorFromHitObject(THitObject hitObject); + + [Test] + public void RunAllInvalidateTest([Values] TFlag flag) + { + // run this test case just make sure that all working property are checked. + var validator = GetValidatorFromHitObject(new THitObject()); + Assert.DoesNotThrow(() => validator.Invalidate(flag)); + } + + [Test] + public void RunAllValidateTest([Values] TFlag flag) + { + // run this test case just make sure that all working property are checked. + var validator = GetValidatorFromHitObject(new THitObject()); + Assert.DoesNotThrow(() => validator.Validate(flag)); + } + + protected void AssetIsValid(THitObject hitObject, TFlag flag, bool isValid) + { + var validator = GetValidatorFromHitObject(hitObject); + Assert.AreEqual(isValid, validator.IsValid(flag)); + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/LyricWorkingPropertyValidatorTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/LyricWorkingPropertyValidatorTest.cs new file mode 100644 index 000000000..605b7cf01 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/LyricWorkingPropertyValidatorTest.cs @@ -0,0 +1,64 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Karaoke.Objects.Workings; + +namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings; + +public class LyricWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest +{ + protected override HitObjectWorkingPropertyValidator GetValidatorFromHitObject(Lyric hitObject) + => hitObject.WorkingPropertyValidator; + + [Test] + public void TestPage() + { + var lyric = new Lyric(); + + // should be invalid on the first load. + AssetIsValid(lyric, LyricWorkingProperty.Page, false); + + // page state is valid because assign the property. + Assert.DoesNotThrow(() => lyric.PageIndex = 1); + AssetIsValid(lyric, LyricWorkingProperty.Page, true); + } + + [Test] + public void TestReferenceLyric() + { + var lyric = new Lyric(); + + // should be invalid on the first load. + AssetIsValid(lyric, LyricWorkingProperty.ReferenceLyric, false); + + // should be valid if change the reference lyric id. + Assert.DoesNotThrow(() => + { + lyric.ReferenceLyricId = null; + lyric.ReferenceLyric = null; + }); + AssetIsValid(lyric, LyricWorkingProperty.ReferenceLyric, true); + + // should be valid if change the reference lyric id. + Assert.DoesNotThrow(() => + { + lyric.ReferenceLyricId = 1; + lyric.ReferenceLyric = new Lyric { ID = 1 }; + }); + AssetIsValid(lyric, LyricWorkingProperty.ReferenceLyric, true); + + // should be invalid if change the reference lyric id. + Assert.DoesNotThrow(() => lyric.ReferenceLyricId = 2); + AssetIsValid(lyric, LyricWorkingProperty.ReferenceLyric, false); + + // should be valid again if assign the reference lyric to the matched lyric. + Assert.DoesNotThrow(() => lyric.ReferenceLyric = new Lyric { ID = 2 }); + AssetIsValid(lyric, LyricWorkingProperty.ReferenceLyric, true); + + // should throw the exception if assign the working reference lyric to the unmatched reference lyric id. + Assert.Throws(() => lyric.ReferenceLyric = new Lyric { ID = 3 }); + Assert.Throws(() => lyric.ReferenceLyric = null); + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/NoteWorkingPropertyValidatorTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/NoteWorkingPropertyValidatorTest.cs new file mode 100644 index 000000000..f03836644 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Objects/Workings/NoteWorkingPropertyValidatorTest.cs @@ -0,0 +1,64 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Karaoke.Objects.Workings; + +namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings; + +public class NoteWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest +{ + protected override HitObjectWorkingPropertyValidator GetValidatorFromHitObject(Note hitObject) + => hitObject.WorkingPropertyValidator; + + [Test] + public void TestPage() + { + var note = new Note(); + + // should be invalid on the first load. + AssetIsValid(note, NoteWorkingProperty.Page, false); + + // page state is valid because assign the property. + Assert.DoesNotThrow(() => note.PageIndex = 1); + AssetIsValid(note, NoteWorkingProperty.Page, true); + } + + [Test] + public void TestReferenceLyric() + { + var note = new Note(); + + // should be invalid on the first load. + AssetIsValid(note, NoteWorkingProperty.ReferenceLyric, false); + + // should be valid if change the reference lyric id. + Assert.DoesNotThrow(() => + { + note.ReferenceLyricId = null; + note.ReferenceLyric = null; + }); + AssetIsValid(note, NoteWorkingProperty.ReferenceLyric, true); + + // should be valid if change the reference lyric id. + Assert.DoesNotThrow(() => + { + note.ReferenceLyricId = 1; + note.ReferenceLyric = new Lyric { ID = 1 }; + }); + AssetIsValid(note, NoteWorkingProperty.ReferenceLyric, true); + + // should be invalid if change the reference lyric id. + Assert.DoesNotThrow(() => note.ReferenceLyricId = 2); + AssetIsValid(note, NoteWorkingProperty.ReferenceLyric, false); + + // should be valid again if assign the reference lyric to the matched lyric. + Assert.DoesNotThrow(() => note.ReferenceLyric = new Lyric { ID = 2 }); + AssetIsValid(note, NoteWorkingProperty.ReferenceLyric, true); + + // should throw the exception if assign the working reference lyric to the unmatched reference lyric id. + Assert.Throws(() => note.ReferenceLyric = new Lyric { ID = 3 }); + Assert.Throws(() => note.ReferenceLyric = null); + } +} diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmapProcessor.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmapProcessor.cs index 6b05666b6..8c149da21 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmapProcessor.cs @@ -6,6 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Karaoke.Beatmaps.Patterns; using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Karaoke.Objects.Workings; namespace osu.Game.Rulesets.Karaoke.Beatmaps { @@ -32,19 +33,17 @@ private void applyInvalidProperty(IBeatmap beatmap) switch (hitObject) { case Lyric lyric: - foreach (var flag in lyric.Validator.GetAllInvalidFlags()) + foreach (var flag in lyric.WorkingPropertyValidator.GetAllInvalidFlags()) { applyInvalidProperty(lyric, flag); - lyric.Validator.Validate(flag); } break; case Note note: - foreach (var flag in note.Validator.GetAllInvalidFlags()) + foreach (var flag in note.WorkingPropertyValidator.GetAllInvalidFlags()) { applyInvalidProperty(note, flag); - note.Validator.Validate(flag); } break; @@ -52,20 +51,17 @@ private void applyInvalidProperty(IBeatmap beatmap) } } - private void applyInvalidProperty(Lyric lyric, LyricInvalidation flag) + private void applyInvalidProperty(Lyric lyric, LyricWorkingProperty flag) { switch (flag) { - case LyricInvalidation.Page: + case LyricWorkingProperty.Page: var pageInfo = Beatmap.PageInfo; lyric.PageIndex = pageInfo.GetPageIndexAt(lyric.LyricStartTime); break; - case LyricInvalidation.ReferenceLyric: - if (lyric.ReferenceLyric != null || lyric.ReferenceLyricId == null) - return; - - lyric.ReferenceLyric = findLyricById(lyric.ReferenceLyricId.Value); + case LyricWorkingProperty.ReferenceLyric: + lyric.ReferenceLyric = findLyricById(lyric.ReferenceLyricId); break; default: @@ -73,20 +69,17 @@ private void applyInvalidProperty(Lyric lyric, LyricInvalidation flag) } } - private void applyInvalidProperty(Note note, NoteInvalidation flag) + private void applyInvalidProperty(Note note, NoteWorkingProperty flag) { switch (flag) { - case NoteInvalidation.Page: + case NoteWorkingProperty.Page: var pageInfo = Beatmap.PageInfo; note.PageIndex = pageInfo.GetPageIndexAt(note.StartTime); break; - case NoteInvalidation.ReferenceLyric: - if (note.ReferenceLyric != null || note.ReferenceLyricId == null) - return; - - note.ReferenceLyric = findLyricById(note.ReferenceLyricId.Value); + case NoteWorkingProperty.ReferenceLyric: + note.ReferenceLyric = findLyricById(note.ReferenceLyricId); break; default: @@ -94,8 +87,8 @@ private void applyInvalidProperty(Note note, NoteInvalidation flag) } } - private Lyric findLyricById(int id) => - Beatmap.HitObjects.OfType().Single(x => x.ID == id); + private Lyric? findLyricById(int? id) => + id == null ? null : Beatmap.HitObjects.OfType().Single(x => x.ID == id); public override void PostProcess() { diff --git a/osu.Game.Rulesets.Karaoke/Flags/FlagState.cs b/osu.Game.Rulesets.Karaoke/Flags/FlagState.cs new file mode 100644 index 000000000..02f3b3d5f --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Flags/FlagState.cs @@ -0,0 +1,67 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; + +namespace osu.Game.Rulesets.Karaoke.Flags; + +public class FlagState where TFlag : struct, Enum +{ + #region Public interface + + private int value; + + public bool Invalidate(TFlag flags) + { + if (!CanInvalidate(flags)) + return false; + + value &= ~Convert.ToInt32(flags); + + return true; + } + + public void InvalidateAll() + { + foreach (TFlag flag in Enum.GetValues(typeof(TFlag))) + { + Invalidate(flag); + } + } + + public bool Validate(TFlag flags) + { + if (!CanValidate(flags)) + return false; + + value |= Convert.ToInt32(flags); + + return true; + } + + public void ValidateAll() + { + foreach (TFlag flag in Enum.GetValues(typeof(TFlag))) + { + Validate(flag); + } + } + + public bool IsValid(TFlag flags) + { + return (value & Convert.ToInt32(flags)) == Convert.ToInt32(flags); + } + + public TFlag[] GetAllValidFlags() + => Enum.GetValues().Where(IsValid).ToArray(); + + public TFlag[] GetAllInvalidFlags() + => Enum.GetValues().Where(x => !IsValid(x)).ToArray(); + + #endregion + + protected virtual bool CanInvalidate(TFlag flags) => true; + + protected virtual bool CanValidate(TFlag flags) => true; +} diff --git a/osu.Game.Rulesets.Karaoke/Objects/HitObjectValidator.cs b/osu.Game.Rulesets.Karaoke/Objects/HitObjectValidator.cs deleted file mode 100644 index ffec7f89c..000000000 --- a/osu.Game.Rulesets.Karaoke/Objects/HitObjectValidator.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) andy840119 . Licensed under the GPL Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Linq; - -namespace osu.Game.Rulesets.Karaoke.Objects; - -public class HitObjectValidator where T : struct, Enum -{ - private int value; - - public void Invalidate(T flags) - { - value &= ~Convert.ToInt32(flags); - } - - public void InvalidateAll() - { - value = 0; - } - - public void Validate(T flags) - { - value |= Convert.ToInt32(flags); - } - - public void ValidateAll() - { - InvalidateAll(); - - foreach (int flag in Enum.GetValues(typeof(T))) - { - value |= flag; - } - } - - public bool IsValid(T flags) - { - return (value & Convert.ToInt32(flags)) == Convert.ToInt32(flags); - } - - public T[] GetAllValidFlags() - => Enum.GetValues().Where(IsValid).ToArray(); - - public T[] GetAllInvalidFlags() - => Enum.GetValues().Where(x => !IsValid(x)).ToArray(); -} diff --git a/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs b/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs index 9f08c55a7..fc9ddddb7 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Karaoke.Judgements; using osu.Game.Rulesets.Karaoke.Objects.Properties; using osu.Game.Rulesets.Karaoke.Objects.Types; +using osu.Game.Rulesets.Karaoke.Objects.Workings; using osu.Game.Rulesets.Karaoke.Scoring; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; @@ -178,12 +179,7 @@ public int? ReferenceLyricId set { referenceLyricId = value; - - if (referenceLyricId == ReferenceLyric?.ID) - return; - - // should trying to reload the reference lyric. - Validator.Invalidate(LyricInvalidation.ReferenceLyric); + WorkingPropertyValidator.Invalidate(LyricWorkingProperty.ReferenceLyric); } } @@ -213,6 +209,7 @@ public Lyric() { initInternalBindingEvent(); initReferenceLyricEvent(); + initWorkingPropertyValidator(); } public override Judgement CreateJudgement() => new KaraokeLyricJudgement(); diff --git a/osu.Game.Rulesets.Karaoke/Objects/Lyric_Working.cs b/osu.Game.Rulesets.Karaoke/Objects/Lyric_Working.cs index b0a98d993..c84f936ab 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Lyric_Working.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Lyric_Working.cs @@ -14,8 +14,13 @@ namespace osu.Game.Rulesets.Karaoke.Objects; /// public partial class Lyric { + private void initWorkingPropertyValidator() + { + WorkingPropertyValidator = new LyricWorkingPropertyValidator(this); + } + [JsonIgnore] - public HitObjectValidator Validator { get; } = new(); + public LyricWorkingPropertyValidator WorkingPropertyValidator { get; private set; } = null!; [JsonIgnore] public double LyricStartTime { get; private set; } @@ -58,7 +63,11 @@ public override double StartTime public int? PageIndex { get => PageIndexBindable.Value; - set => PageIndexBindable.Value = value; + set + { + PageIndexBindable.Value = value; + WorkingPropertyValidator.Validate(LyricWorkingProperty.Page); + } } [JsonIgnore] @@ -75,11 +84,7 @@ public Lyric? ReferenceLyric set { ReferenceLyricBindable.Value = value; - - if (value?.ID != ReferenceLyricId) - { - throw new InvalidWorkingPropertyAssignException(); - } + WorkingPropertyValidator.Validate(LyricWorkingProperty.ReferenceLyric); } } } diff --git a/osu.Game.Rulesets.Karaoke/Objects/Note.cs b/osu.Game.Rulesets.Karaoke/Objects/Note.cs index 0c4a34b1d..226659aec 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Note.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Note.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Karaoke.Configuration; using osu.Game.Rulesets.Karaoke.Judgements; using osu.Game.Rulesets.Karaoke.Objects.Types; +using osu.Game.Rulesets.Karaoke.Objects.Workings; using osu.Game.Rulesets.Karaoke.Scoring; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; @@ -106,12 +107,7 @@ public int? ReferenceLyricId set { referenceLyricId = value; - - if (referenceLyricId == ReferenceLyric?.ID) - return; - - // should trying to reload the reference lyric. - Validator.Invalidate(NoteInvalidation.ReferenceLyric); + WorkingPropertyValidator.Invalidate(NoteWorkingProperty.ReferenceLyric); } } @@ -128,6 +124,7 @@ public Note() { initInternalBindingEvent(); initReferenceLyricEvent(); + initWorkingPropertyValidator(); } public override Judgement CreateJudgement() => new KaraokeNoteJudgement(); diff --git a/osu.Game.Rulesets.Karaoke/Objects/Note_Working.cs b/osu.Game.Rulesets.Karaoke/Objects/Note_Working.cs index 27fe8d8fc..a534c3d36 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Note_Working.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Note_Working.cs @@ -16,8 +16,13 @@ namespace osu.Game.Rulesets.Karaoke.Objects; /// public partial class Note { + private void initWorkingPropertyValidator() + { + WorkingPropertyValidator = new NoteWorkingPropertyValidator(this); + } + [JsonIgnore] - public HitObjectValidator Validator { get; } = new(); + public NoteWorkingPropertyValidator WorkingPropertyValidator { get; private set; } = null!; [JsonIgnore] public readonly Bindable PageIndexBindable = new(); @@ -29,7 +34,11 @@ public partial class Note public int? PageIndex { get => PageIndexBindable.Value; - set => PageIndexBindable.Value = value; + set + { + PageIndexBindable.Value = value; + WorkingPropertyValidator.Validate(NoteWorkingProperty.Page); + } } /// @@ -78,11 +87,7 @@ public Lyric? ReferenceLyric set { ReferenceLyricBindable.Value = value; - - if (value?.ID != ReferenceLyricId) - { - throw new InvalidWorkingPropertyAssignException(); - } + WorkingPropertyValidator.Validate(NoteWorkingProperty.ReferenceLyric); } } diff --git a/osu.Game.Rulesets.Karaoke/Objects/Workings/HitObjectWorkingPropertyValidator.cs b/osu.Game.Rulesets.Karaoke/Objects/Workings/HitObjectWorkingPropertyValidator.cs new file mode 100644 index 000000000..50d23adce --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Objects/Workings/HitObjectWorkingPropertyValidator.cs @@ -0,0 +1,49 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Rulesets.Karaoke.Beatmaps; +using osu.Game.Rulesets.Karaoke.Flags; + +namespace osu.Game.Rulesets.Karaoke.Objects.Workings; + +/// +/// This class is used to check the working property is same as data property in the . +/// Should mark as invalid when data property is changed. +/// Should mark as valid when working property is synced with data property +/// +/// +/// +public abstract class HitObjectWorkingPropertyValidator : FlagState + where TFlag : struct, Enum +{ + private readonly THitObject hitObject; + + protected HitObjectWorkingPropertyValidator(THitObject hitObject) + { + this.hitObject = hitObject; + } + + /// + /// This method is called after assign the working property changed in the by . + /// We should make sure that the working property is same as data property. + /// + /// + public new bool Validate(TFlag flag) + { + if (!CanValidate(flag)) + throw new InvalidWorkingPropertyAssignException(); + + return base.Validate(flag); + } + + protected sealed override bool CanInvalidate(TFlag flags) + => CanCheckWorkingPropertySync(hitObject, flags) || NeedToSyncWorkingProperty(hitObject, flags); + + protected sealed override bool CanValidate(TFlag flags) + => CanCheckWorkingPropertySync(hitObject, flags) || !NeedToSyncWorkingProperty(hitObject, flags); + + protected abstract bool CanCheckWorkingPropertySync(THitObject hitObject, TFlag flags); + + protected abstract bool NeedToSyncWorkingProperty(THitObject hitObject, TFlag flags); +} diff --git a/osu.Game.Rulesets.Karaoke/Objects/LyricInvalidation.cs b/osu.Game.Rulesets.Karaoke/Objects/Workings/LyricWorkingProperty.cs similarity index 86% rename from osu.Game.Rulesets.Karaoke/Objects/LyricInvalidation.cs rename to osu.Game.Rulesets.Karaoke/Objects/Workings/LyricWorkingProperty.cs index 7d6ca4928..ef3d91be2 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/LyricInvalidation.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Workings/LyricWorkingProperty.cs @@ -3,13 +3,13 @@ using System; -namespace osu.Game.Rulesets.Karaoke.Objects; +namespace osu.Game.Rulesets.Karaoke.Objects.Workings; /// /// Specifies which properties in the are being invalidated. /// [Flags] -public enum LyricInvalidation +public enum LyricWorkingProperty { /// /// is being invalidated. diff --git a/osu.Game.Rulesets.Karaoke/Objects/Workings/LyricWorkingPropertyValidator.cs b/osu.Game.Rulesets.Karaoke/Objects/Workings/LyricWorkingPropertyValidator.cs new file mode 100644 index 000000000..7f1133e21 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Objects/Workings/LyricWorkingPropertyValidator.cs @@ -0,0 +1,30 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Rulesets.Karaoke.Objects.Workings; + +public class LyricWorkingPropertyValidator : HitObjectWorkingPropertyValidator +{ + public LyricWorkingPropertyValidator(Lyric hitObject) + : base(hitObject) + { + } + + protected override bool CanCheckWorkingPropertySync(Lyric hitObject, LyricWorkingProperty flags) => + flags switch + { + LyricWorkingProperty.Page => true, // there's no way to check working page is sync to the page info. + LyricWorkingProperty.ReferenceLyric => false, + _ => throw new ArgumentOutOfRangeException(nameof(flags), flags, null) + }; + + protected override bool NeedToSyncWorkingProperty(Lyric hitObject, LyricWorkingProperty flags) => + flags switch + { + LyricWorkingProperty.Page => false, + LyricWorkingProperty.ReferenceLyric => hitObject.ReferenceLyric?.ID != hitObject.ReferenceLyricId, + _ => throw new ArgumentOutOfRangeException(nameof(flags), flags, null) + }; +} diff --git a/osu.Game.Rulesets.Karaoke/Objects/NoteInvalidation.cs b/osu.Game.Rulesets.Karaoke/Objects/Workings/NoteWorkingProperty.cs similarity index 86% rename from osu.Game.Rulesets.Karaoke/Objects/NoteInvalidation.cs rename to osu.Game.Rulesets.Karaoke/Objects/Workings/NoteWorkingProperty.cs index fea949484..649413f40 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/NoteInvalidation.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Workings/NoteWorkingProperty.cs @@ -3,13 +3,13 @@ using System; -namespace osu.Game.Rulesets.Karaoke.Objects; +namespace osu.Game.Rulesets.Karaoke.Objects.Workings; /// /// Specifies which properties in the are being invalidated. /// [Flags] -public enum NoteInvalidation +public enum NoteWorkingProperty { /// /// is being invalidated. diff --git a/osu.Game.Rulesets.Karaoke/Objects/Workings/NoteWorkingPropertyValidator.cs b/osu.Game.Rulesets.Karaoke/Objects/Workings/NoteWorkingPropertyValidator.cs new file mode 100644 index 000000000..ba61ca0f8 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Objects/Workings/NoteWorkingPropertyValidator.cs @@ -0,0 +1,30 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Rulesets.Karaoke.Objects.Workings; + +public class NoteWorkingPropertyValidator : HitObjectWorkingPropertyValidator +{ + public NoteWorkingPropertyValidator(Note hitObject) + : base(hitObject) + { + } + + protected override bool CanCheckWorkingPropertySync(Note hitObject, NoteWorkingProperty flags) => + flags switch + { + NoteWorkingProperty.Page => true, // there's no way to check working page is sync to the page info. + NoteWorkingProperty.ReferenceLyric => false, + _ => throw new ArgumentOutOfRangeException(nameof(flags), flags, null) + }; + + protected override bool NeedToSyncWorkingProperty(Note hitObject, NoteWorkingProperty flags) => + flags switch + { + NoteWorkingProperty.Page => false, + NoteWorkingProperty.ReferenceLyric => hitObject.ReferenceLyric?.ID != hitObject.ReferenceLyricId, + _ => throw new ArgumentOutOfRangeException(nameof(flags), flags, null) + }; +}