Mostly closes https://github.com/ppy/osu/issues/33505.
Compare
https://github.com/ppy/osu/blob/97e6187f0d7c3dbee896596a623e34627135bf0e/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs#L56-L59
I say "mostly" here because I'm rather skeptical that this is 100% rock
solid still, for one reason - namely that the game stores path control
point coordinates relative to the head, then turns them into absolute
coordinates when encoding, and then on decoding turns them back into
coordinates relative to the head, which in floating-point world is a Bad
Idea because of round-off error. But I'm not fixing that without
introducing a completely new beatmap format or rewriting half the
editor to address that, so I'll just pretend that I don't know any
of this until someone notices.
Having these be separate implementations sounded awesome at the time,
but it only ever led to confusion. There's no practical difference if,
for example, catch sees hitobjects with `IHasPosition` instead of
`IHasXPosition`.
The equality of samples is generally used to compare the sample
equality, not its full properties. For instance, we don't compare
`Volume` in the base implementation.
Having `IsLayered` here breaks actual usages of equality, ie. for
pooling purposes.
This is quite a breaking change, but I think it is beneficial due to the large amount of usage of this class.
I originally intended just to remove the allocations of the two delegates handling the `Changed` flow internally, but as nothing was really using the bindables for anything more than a general "point has changed" case, this felt like a better direction.