Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate the working property. #2091

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
using osu.Game.Rulesets.Karaoke.Configuration;
using osu.Game.Rulesets.Karaoke.Edit.Utils;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Objects.Types;
using osu.Game.Rulesets.Karaoke.Objects.Workings;
using osu.Game.Rulesets.Karaoke.Stages;
using osu.Game.Rulesets.Karaoke.Stages.Types;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit;
Expand Down Expand Up @@ -233,13 +236,29 @@ protected void AssertWorkingPropertyInHitObjectValid()

return editorBeatmap.HitObjects.OfType<KaraokeHitObject>().All(hitObject => hitObject switch
{
Lyric lyric => lyric.GetAllInvalidWorkingProperties().Length == 0,
Note note => note.GetAllInvalidWorkingProperties().Length == 0,
Lyric lyric => !hasInvalidWorkingProperty(lyric),
Note note => !hasInvalidWorkingProperty(note),
_ => throw new NotSupportedException(),
});
});
}

private static bool hasInvalidWorkingProperty(Lyric lyric)
{
if (lyric is not (IHasWorkingProperty<LyricWorkingProperty, KaraokeBeatmap> workingProperty and IHasWorkingProperty<LyricStageWorkingProperty, StageInfo> stageWorkingProperty))
throw new NotSupportedException();

return workingProperty.HasInvalidWorkingProperty() || stageWorkingProperty.HasInvalidWorkingProperty();
}

private static bool hasInvalidWorkingProperty(Note note)
{
if (note is not (IHasWorkingProperty<NoteWorkingProperty, KaraokeBeatmap> workingProperty and IHasWorkingProperty<NoteStageWorkingProperty, StageInfo> stageWorkingProperty))
throw new NotSupportedException();

return workingProperty.HasInvalidWorkingProperty() || stageWorkingProperty.HasInvalidWorkingProperty();
}

private partial class MockEditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler
{
public event Action? OnStateChange;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings;

public abstract class HitObjectWorkingPropertyValidatorTest<THitObject, TFlag>
public abstract class HitObjectWorkingPropertyValidatorTest<THitObject, TFlag, TFillProperty>
where TFlag : struct, Enum
where THitObject : KaraokeHitObject, IHasWorkingProperty<TFlag>, new()
where THitObject : KaraokeHitObject, IHasWorkingProperty<TFlag, TFillProperty>, new()
{
[Test]
public void CheckInitialState([Values] TFlag flag)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) andy840119 <[email protected]>. 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.Stages.Classic;
using osu.Game.Rulesets.Karaoke.Objects.Workings;
using osu.Game.Rulesets.Karaoke.Stages;
using osu.Game.Rulesets.Karaoke.Stages.Classic;

namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings;

public class LyricStageWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest<Lyric, LyricStageWorkingProperty, StageInfo>
{
[Test]
public void TestStartTime()
{
var lyric = new Lyric();

// state is valid because assign the property.
Assert.DoesNotThrow(() => lyric.StartTime = 1000);
AssetIsValid(lyric, LyricStageWorkingProperty.StartTime, true);
}

[Test]
public void TestDuration()
{
var lyric = new Lyric();

// state is valid because assign the property.
Assert.DoesNotThrow(() => lyric.Duration = 1000);
AssetIsValid(lyric, LyricStageWorkingProperty.Duration, true);
}

[Test]
public void TestTiming()
{
var lyric = new Lyric();

// state is still invalid because duration is not assign.
Assert.DoesNotThrow(() => lyric.StartTime = 1000);
AssetIsValid(lyric, LyricStageWorkingProperty.Timing, false);

// ok, should be valid now.
Assert.DoesNotThrow(() => lyric.Duration = 1000);
AssetIsValid(lyric, LyricStageWorkingProperty.Timing, true);
}

[Test]
public void TestEffectApplier()
{
var lyric = new Lyric();

// state is valid because assign the property.
Assert.DoesNotThrow(() => lyric.EffectApplier = new LyricClassicStageEffectApplier(Array.Empty<StageElement>(), new ClassicStageDefinition()));
AssetIsValid(lyric, LyricStageWorkingProperty.EffectApplier, true);
}

protected override bool IsInitialStateValid(LyricStageWorkingProperty flag)
{
return new LyricStageWorkingPropertyValidator(new Lyric()).IsValid(flag);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,14 @@
using osu.Game.Rulesets.Karaoke.Beatmaps;
using osu.Game.Rulesets.Karaoke.Beatmaps.Metadatas;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Objects.Stages.Classic;
using osu.Game.Rulesets.Karaoke.Objects.Workings;
using osu.Game.Rulesets.Karaoke.Stages;
using osu.Game.Rulesets.Karaoke.Stages.Classic;
using osu.Game.Rulesets.Karaoke.Tests.Extensions;
using osu.Game.Rulesets.Karaoke.Tests.Helper;

namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings;

public class LyricWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest<Lyric, LyricWorkingProperty>
public class LyricWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest<Lyric, LyricWorkingProperty, KaraokeBeatmap>
{
[Test]
public void TestStartTime()
{
var lyric = new Lyric();

// state is valid because assign the property.
Assert.DoesNotThrow(() => lyric.StartTime = 1000);
AssetIsValid(lyric, LyricWorkingProperty.StartTime, true);
}

[Test]
public void TestDuration()
{
var lyric = new Lyric();

// state is valid because assign the property.
Assert.DoesNotThrow(() => lyric.Duration = 1000);
AssetIsValid(lyric, LyricWorkingProperty.Duration, true);
}

[Test]
public void TestTiming()
{
var lyric = new Lyric();

// state is still invalid because duration is not assign.
Assert.DoesNotThrow(() => lyric.StartTime = 1000);
AssetIsValid(lyric, LyricWorkingProperty.Timing, false);

// ok, should be valid now.
Assert.DoesNotThrow(() => lyric.Duration = 1000);
AssetIsValid(lyric, LyricWorkingProperty.Timing, true);
}

[Test]
public void TestSingers()
{
Expand Down Expand Up @@ -189,16 +152,6 @@ public void TestReferenceLyric()
Assert.Throws<InvalidWorkingPropertyAssignException>(() => lyric.ReferenceLyric = null);
}

[Test]
public void TestEffectApplier()
{
var lyric = new Lyric();

// state is valid because assign the property.
Assert.DoesNotThrow(() => lyric.EffectApplier = new LyricClassicStageEffectApplier(Array.Empty<StageElement>(), new ClassicStageDefinition()));
AssetIsValid(lyric, LyricWorkingProperty.EffectApplier, true);
}

protected override bool IsInitialStateValid(LyricWorkingProperty flag)
{
return new LyricWorkingPropertyValidator(new Lyric()).IsValid(flag);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
// Copyright (c) andy840119 <[email protected]>. 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.Beatmaps;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Objects.Stages.Classic;
using osu.Game.Rulesets.Karaoke.Objects.Workings;
using osu.Game.Rulesets.Karaoke.Stages;
using osu.Game.Rulesets.Karaoke.Stages.Classic;
using osu.Game.Rulesets.Karaoke.Tests.Extensions;
using osu.Game.Rulesets.Karaoke.Tests.Helper;

namespace osu.Game.Rulesets.Karaoke.Tests.Objects.Workings;

public class NoteWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest<Note, NoteWorkingProperty>
public class NoteWorkingPropertyValidatorTest : HitObjectWorkingPropertyValidatorTest<Note, NoteWorkingProperty, KaraokeBeatmap>
{
[Test]
public void TestPage()
Expand Down Expand Up @@ -75,16 +72,6 @@ public void TestReferenceLyric()
Assert.Throws<InvalidWorkingPropertyAssignException>(() => note.ReferenceLyric = null);
}

[Test]
public void TestEffectApplier()
{
var note = new Note();

// page state is valid because assign the property.
Assert.DoesNotThrow(() => note.EffectApplier = new NoteClassicStageEffectApplier(Array.Empty<StageElement>(), new ClassicStageDefinition()));
AssetIsValid(note, NoteWorkingProperty.EffectApplier, true);
}

protected override bool IsInitialStateValid(NoteWorkingProperty flag)
{
return new NoteWorkingPropertyValidator(new Note()).IsValid(flag);
Expand Down
18 changes: 14 additions & 4 deletions osu.Game.Rulesets.Karaoke/Beatmaps/KaraokeBeatmapProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Beatmaps;
Expand Down Expand Up @@ -41,10 +42,10 @@ private void applyStage(KaraokeBeatmap beatmap)
// should invalidate the working property here because the stage info is changed.
beatmap.HitObjects.OfType<Lyric>().ForEach(x =>
{
x.InvalidateWorkingProperty(LyricWorkingProperty.Timing);
x.InvalidateWorkingProperty(LyricWorkingProperty.EffectApplier);
x.InvalidateWorkingProperty(LyricStageWorkingProperty.Timing);
x.InvalidateWorkingProperty(LyricStageWorkingProperty.EffectApplier);
});
beatmap.HitObjects.OfType<Note>().ForEach(x => x.InvalidateWorkingProperty(NoteWorkingProperty.EffectApplier));
beatmap.HitObjects.OfType<Note>().ForEach(x => x.InvalidateWorkingProperty(NoteStageWorkingProperty.EffectApplier));
}

if (beatmap.CurrentStageInfo is IHasCalculatedProperty calculatedProperty)
Expand All @@ -60,9 +61,18 @@ private void applyInvalidProperty(KaraokeBeatmap beatmap)
{
// should convert to array here because validate the working property might change the start-time and the end time.
// which will cause got the wrong item in the array.
foreach (var hitObject in beatmap.HitObjects.OfType<IHasWorkingProperty>().ToArray())
foreach (var hitObject in beatmap.HitObjects.OfType<IHasWorkingProperty<KaraokeBeatmap>>().ToArray())
{
hitObject.ValidateWorkingProperty(beatmap);
}

var stageInfo = beatmap.CurrentStageInfo;
if (stageInfo == null)
throw new InvalidCastException();

foreach (var hitObject in beatmap.HitObjects.OfType<IHasWorkingProperty<StageInfo>>().ToArray())
{
hitObject.ValidateWorkingProperty(stageInfo);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ protected void PerformOnSelection<T>(Action<T> action) where T : HitObject
protected void InvalidateAllHitObjectWorkingProperty<TWorkingProperty>(TWorkingProperty property)
where TWorkingProperty : struct, Enum
{
foreach (var hitObject in KaraokeBeatmap.HitObjects.OfType<IHasWorkingProperty<TWorkingProperty>>())
foreach (var hitObject in KaraokeBeatmap.HitObjects.OfType<IHasWorkingProperty<TWorkingProperty, KaraokeBeatmap>>())
{
hitObject.InvalidateWorkingProperty(property);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private void performTimingInfoChanged(Action<ClassicLyricTimingInfo> action)
{
action(stageInfo.LyricTimingInfo);

InvalidateAllHitObjectWorkingProperty(LyricWorkingProperty.Timing);
InvalidateAllHitObjectWorkingProperty(LyricStageWorkingProperty.Timing);
});
}
}
6 changes: 3 additions & 3 deletions osu.Game.Rulesets.Karaoke/Mods/ModStage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public override void ApplyToBeatmap(IBeatmap beatmap)
// has the same logic in the beatmap processor.
beatmap.HitObjects.OfType<Lyric>().ForEach(x =>
{
x.InvalidateWorkingProperty(LyricWorkingProperty.Timing);
x.InvalidateWorkingProperty(LyricWorkingProperty.EffectApplier);
x.InvalidateWorkingProperty(LyricStageWorkingProperty.Timing);
x.InvalidateWorkingProperty(LyricStageWorkingProperty.EffectApplier);
});
beatmap.HitObjects.OfType<Note>().ForEach(x => x.InvalidateWorkingProperty(NoteWorkingProperty.EffectApplier));
beatmap.HitObjects.OfType<Note>().ForEach(x => x.InvalidateWorkingProperty(NoteStageWorkingProperty.EffectApplier));
}

protected abstract void ApplyToCurrentStageInfo(TStageInfo stageInfo);
Expand Down
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Karaoke/Objects/Lyric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ public IReferenceLyricPropertyConfig? ReferenceLyricConfig
public Lyric()
{
workingPropertyValidator = new LyricWorkingPropertyValidator(this);
stageWorkingPropertyValidator = new LyricStageWorkingPropertyValidator(this);

initInternalBindingEvent();
initReferenceLyricEvent();
Expand Down
Loading