Add support for LayeredHitSounds skin option#8683
Add support for LayeredHitSounds skin option#8683Fire937 wants to merge 20 commits intoppy:masterfrom
Conversation
The 5th argument of a timing point was not read properly. When equal to 0 the sample used should be osu!'s default hitsound. This commit resolves this problem by adding an 'IsCustom' attribute to HitSampleInfo.
As suggested by @bdach it makes much more sense to test the IsCustom attribute to LegacySkin, that way SkinnableSound doesn't need to know how the skin is supposed to behave.
The LayeredHitSounds option if set to 1 will force hitnormal to be played along all the other hitsounds on each hitobject. This option is disabled in osu:mania. In order to implement this behaviour, an AllowsLayeredHitSounds attribute was added to the ConvertHitObjectParser so that it knows if it has to artificially add the hitnormal sample or not. LegacySkin can then verify if a hitsample was artificially added thanks to HitSampleInfo's IsLayered attribute. It can then decide to return the hitsample or not based on the value of LayeredHitSounds.
…rk-mania These two branches are tightly related for the most part because of the changes to LegacySkin:GetSample.
LayeredHitSounds was previously in SkinInfo but that caused some issues so it was moved to LegacySkinConfiguration.
The use of a LayeredHitSounds property in Configuration was redundant. The value of the LayeredHitSounds property could already be retrieved from SkinConfiguration:ConfigDictionary.
The LayeredHitSounds property can now be accessed via the LegacySetting enum rather than by string.
bdach
left a comment
There was a problem hiding this comment.
I really dislike how complicated LegacySkin.GetSample() is starting to be. I'd say it needs unit tests at the least, and a refactoring on top to decrease complexity if possible.
| } | ||
| }; | ||
| CustomSampleBank = bankInfo.CustomSampleBank, | ||
| IsLayered = !type.HasFlag(LegacyHitSoundType.Normal) |
There was a problem hiding this comment.
I feel like this is backwards. Shouldn't this just use AllowsLayeredHitSounds? If both the flag is set and AllowsLayeredHitSounds is true, won't this wrongly consider the sample non-layered?
There was a problem hiding this comment.
The thing is that the beatmap could actually explicitly indicate that the sample to be played (among others) should be hitnormal. In this case, whether AllowLayeredHitSounds is true or false should not affect the fact that the sample is not layered. That means it should always be played even in osu!mania. That's why this problem doesn't appear in other beatmap as they use hitnormal as opposed to this map that uses hitfinish and the others but not hitnormal.
I'm actually concerned about the naming of this flag, maybe IsForced would make more sense?
There was a problem hiding this comment.
With application of the above comments, the outer condition can once again be removed and this can remain here.
This test makes sure the layered hitsounds are handled properly by LegacySkin:GetSample. - If the LayeredHitSounds skin property is set to true, the sample should be played whether it is layered or not. - If the LayeredHitSounds skin property is set to false, the sample should be played only if it is not layered.
Makes sure that LegacySkin.GetSample() returns the right samples according to the IsCustom flag.
| case LegacySkinConfiguration.LegacySetting legacySetting when legacySetting == LegacySkinConfiguration.LegacySetting.Version: | ||
| return SkinUtils.As<TValue>(new Bindable<decimal>(Configuration.LegacyVersion ?? LegacySkinConfiguration.LATEST_VERSION)); |
There was a problem hiding this comment.
this is less readable than the original, and there may be even more legacy settings. please revert.
| /// <summary> | ||
| /// Whether the sample is custom or if it uses osu!'s default hitsounds. | ||
| /// </summary> | ||
| public bool IsCustom { get; set; } |
There was a problem hiding this comment.
This should not exist. Please update this branch using the changes made in #8756
| // 0 means osu!'s default hitsounds | ||
| baseInfo.IsCustom = CustomSampleBank != 0; | ||
|
|
There was a problem hiding this comment.
Same here, can be removed
|
|
||
| protected bool FirstObject { get; private set; } = true; | ||
|
|
||
| protected bool AllowLayeredHitSounds { get; set; } = true; |
There was a problem hiding this comment.
This cannot exist in the parser - it should only exist within the legacy skin itself.
The mania override can be done inside LegacyManiaSkinTransformer.
That is to say, layered hitsounds should always be added.
| /// True if the sample is a <c>hitnormal</c> sample added artificially due to the skin having | ||
| /// the <see cref="osu.Game.Skinning.LegacySkinConfiguration.LegacySetting.LayeredHitSounds"/> option set. | ||
| /// </summary> | ||
| public bool IsLayered { get; set; } |
There was a problem hiding this comment.
This must only exist within ConvertHitObjectParser.LegacyHitSampleInfo.
| } | ||
| }; | ||
| CustomSampleBank = bankInfo.CustomSampleBank, | ||
| IsLayered = !type.HasFlag(LegacyHitSoundType.Normal) |
There was a problem hiding this comment.
With application of the above comments, the outer condition can once again be removed and this can remain here.
| public ConvertHitObjectParser(double offset, int formatVersion) | ||
| : base(offset, formatVersion) | ||
| { | ||
| AllowLayeredHitSounds = false; |
| namespace osu.Game.Tests.Skins | ||
| { | ||
| [HeadlessTest] | ||
| public class TestSceneLegacySkin : OsuTestScene |
There was a problem hiding this comment.
This testing is inadequate because it doesn't test the result of gameplay loading. You want to add a test to TestSceneHitObjectSamples.
I'm fairly certain the implementation in this PR (inside LegacySkin) will fail, since SkinnableSound will fall back to the default lazer sample store if null is returned.
| foreach (var lookup in sampleInfo.LookupNames) | ||
| var hsi = sampleInfo as HitSampleInfo; | ||
|
|
||
| if (hsi?.IsLayered == true && GetConfig<LegacySkinConfiguration.LegacySetting, bool>(LegacySkinConfiguration.LegacySetting.LayeredHitSounds)?.Value == false) |
There was a problem hiding this comment.
This isn't being read from the skin configuration. You need to add a value to the LegacySetting switch above.
|
@Fire937 just looping back – are you intending to apply the remaining review? |
|
@peppy yes I will try and commit in not too long. |
|
Seeing that there stlll has been no changes here in a while, I would be looking to supersede this PR over the coming days. I don't usually do that but this one would take too much work to fix up - I would basically have to revert all of the changes here, and even then there are major issues left unaddressed (such as how to make the sample fallback logic stick to a silent sample if layered hit sounds are to be disabled). |
Closes #8595
The current behaviour of osu!lazer is to add the hitnormal sample on top of the other samples for every single skin/beatmap/ruleset/hitobject, even in osu!mania, that is what causes the issue. Moreover osu!stable uses a LayeredHitSounds skin property that tells osu! whether it should add the hitnormal sample artificially or not based on the skin used (defaults to yes). LayeredHitSounds is also ignored when in osu!mania mode: osu!stable never adds the hitnormal sample artificially in osu!mania mode.
Currently the
LayeredHitSoundsproperty is included inLegacySkinConfiguration,however i am not sure about whether it belongs here or not. Maybe it should be moved toSkinInfo.A ruleset can override the value of
AllowsLayeredHitSoundsin itsConvertHitObjectParserto disable theLayeredHitSoundsproperty.