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

IApplicableToDrawableHitObjects is inconsistent between pooled and non-pooled hit objects #13301

Open
ekrctb opened this issue Jun 2, 2021 · 2 comments

Comments

@ekrctb
Copy link
Collaborator

ekrctb commented Jun 2, 2021

The doc comment of the interface

/// <summary>
/// Applies this <see cref="IApplicableToDrawableHitObjects"/> to a list of <see cref="DrawableHitObject"/>s.
/// This will only be invoked with top-level <see cref="DrawableHitObject"/>s. Access <see cref="DrawableHitObject.NestedHitObjects"/> if adjusting nested objects is necessary.
/// </summary>
/// <param name="drawables">The list of <see cref="DrawableHitObject"/>s to apply to.</param>
void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables);

says it is only applied to top-level DHOs.
However, when the hit object is pooled, the mod is applied to nested hit objects as well:

// If this is the first time this DHO is being used, then apply the DHO mods.
// This is done before Apply() so that the state is updated once when the hitobject is applied.
if (mods != null)
{
foreach (var m in mods.OfType<IApplicableToDrawableHitObjects>())
m.ApplyToDrawableHitObjects(dho.Yield());
}

However, this behavior is already used. If I disable the mod application to nested DHOs, osu!standard hidden mod breaks (slider head remains visible).
Also, the doc comment of IApplicableToDrawableHitObject mentions to use NestedHitObjects, but it cannot be used for pooled hit objects because the mod is applied before Apply, no nested hit objects are created for the DHO yet.

Proposed solution:

  • Redefine the mod interface (breaking changes).
  • The mod is always applied to nested hit objects as well.
  • If the user wants to just apply it to the top-level hit objects, a ParentHitObject == null guard can be added (so ParentHitObject has to be set before mod is applied).

By the way, I think the interface should be defined as ApplyToDrawableHitObject(DrawableHitObject), as every mod is using a foreach for the IEnumerable<DrawableHitObject>.

@peppy
Copy link
Member

peppy commented Jun 2, 2021

At some point we did decide that it should be applied to nested hit objects as well, so the documentation is definitely out of date.

Can also agree with the change to the interface definition, as long as it works in all existing usages. May need to give consideration to the fact that other rulesets are likely implementing this interface, so the previous method will need to existing as an Obsoleted (and be called for both top-level and nested? for the time being).

@ekrctb
Copy link
Collaborator Author

ekrctb commented Jun 3, 2021

If the mod registers ApplyCustomUpdateState (example: ModWithVisibilityAdjustment), it is propagated to nested DHOs.

It means, for nested pooled DHOs, ApplyCustomUpdateState will be registered multiple times. It has been unnoticed because transforms are idempotent.

By changing ApplyToDrawableHitObjects to be called for nested non-pooled hit objects as well, ApplyCustomUpdateState propagation can be removed, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants