1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-19 03:19:52 +08:00
Commit Graph

10 Commits

  • Attempt to properly quantify the impact of mania Hard Rock / Easy mod application on overall difficulty
    In stable mania, Hard Rock and Easy mods do not work the same way as
    they do on all of the rulesets. The difference is that mania HR and EZ,
    rather than apply a multiplier to the map's original Overall Difficulty,
    apply multipliers to *the durations of hit windows themselves*.
    
    Prior to the last release, lazer was oblivious to this reality and just
    treated mania HR / EZ as it did every other ruleset. Last release, for
    the sake for gameplay parity across rulesets, the mods in question were
    adjusted to match stable, but in the process, it started looking like HR
    / EZ did not change OD anymore.
    
    The problem is that they do, but applying a multiplier to the map's OD
    and applying a multiplier to the hit window duration is not the same
    thing. The second thing is actually *much harsher* in magnitude, to the
    point where applying HR to any map is almost guaranteed to exceed "the
    effective OD" of 10, and applying EZ to any map is almost guaranteed to
    result in "negative effective OD".
    
    This change attempts to convey that reality by displaying "effective
    OD", similar to what's already done in other rulesets when rate-changing
    mods are active. Note that the values this will display *do not match*
    stable *and that is correct*, because stable song select *lies* about
    the actual impact on OD by just assuming it can treat all rulesets in
    the same way.
    
    ---
    
    Would close https://github.com/ppy/osu/issues/34150 I guess.
    
    And yes I would like *all of the above* to land on the changelog if
    possible if this is merged.
    
    For further convincing that this makes any semblance of sense please see
    the following: https://www.desmos.com/calculator/yigt7jycdv
  • Fix mania Hard Rock & Easy mods not matching stable
    The implementation in `master` was presuming that Hard Rock and Easy
    worked the same way across all rulesets, but actually, in stable mania,
    the two mods have special treatment as per
    
    	https://github.com/peppy/osu-stable-reference/blob/996648fba06baf4e7d2e0b248959399444017895/osu!/GameplayElements/HitObjectManagerMania.cs#L147-L150
    
    The open question here would be what this means for existing scores set
    on lazer using this mod.
  • Support mania-specific hit window quirks
    The quirks in question being that lazer's hit windows in mania preceding
    this change are used in stable *if and only if* Score V2 is active. If
    Score V2 is *not* active, stable has two disparate other sets of hit
    window ranges, dependent on whether the beatmap is a convert or not.
    
    With this commit, those hit windows are used in lazer when the Classic
    mod is active.
    
    Open points for discussion would be:
    
    - What does this mean for plays already set on lazer using the Classic
      mod? Are there even enough of them to care about? Also, on `master`
      the Classic mod does precisely nothing, so maybe such scores should
      just have Classic mod stripped from them?
    
    - What does this mean for the mod multiplier of Classic in mania? (I don't
      expect an answer to this one.)
  • Apply flooring and half-millisecond-adjustments to hit windows
    This is a "two-birds-with-one-stone" change, which addresses both
    https://github.com/ppy/osu/issues/28744 and
    https://github.com/ppy/osu/issues/11311 simultaneously.
    
    - The replay stability issue caused by time instants being rounded to
      nearest integer is fixed by this, because flooring and
      subtracting/adding 0.5 from the hit window threshold makes it
      impossible for a judgement to switch to anything else after replay
      rounding is applied - all hit windows are always a full integer plus
      0.5 milliseconds, which immunizes them to rounding-to-full-ms issues.
    
    - The direction of applying the 0.5 adjustment additionally fixes the
      disparity with stable - in osu! and taiko 0.5 is subtracted as
      hit window ranges in those rulesets are exclusive on stable, while in
      mania 0.5 is added, as the hit window ranges there are *inclusive* on
      stable.
    
    As should be obvious, this materially changes hit windows. To what degree
    this is a *significant* change is up for discussion; I would say "no"
    since hitting half a millisecond changes would require 2000fps input
    recording, and we're still timestamping inputs using the update thread's
    clock, that gives a 1ms resolution at best.
    
    In the worst case, in osu! and taiko, this can change a hit window range
    by 1.5ms (e.g. 300.9ms -> floored to 300ms -> 299.5ms after subtraction
    of the half). It's more than the best-case resolution of input
    timestamps, but not by much. Considering how cleanly this resolves the
    issues in question, I see it as an acceptable tradeoff.
  • Refactor hit windows class structure to reduce rigidity
    This change pulls back a significant degree of overspecialisation and
    rigidity in the class structure of `HitWindows` to make subsequent
    changes to hit windows, whose purpose is to improve replay playback
    accuracy, possible to do cleanly.
    
    Notably:
    
    - `HitWindows` is full abstract now. In a few use cases, and as a
      reference for ruleset implementors, `DefaultHitWindows` is provided as
      a separate class instead.
    
      This fixes the weirdness wherein `HitWindows` always declared 6 fields
      for result types but some of them would never be set to a non-zero
      value or read.
    
    - `HitWindow.GetRanges()` is deleted because it is overspecialised and
      prevents being able to adjust hitwindows by ±0.5ms cleanly which will
      be required later.
    
      The fallout of this is that the assertion that used `GetRanges()` in
      the `HitWindows` ctor must use something else now, and the closest
      thing to it was `GetAllAvailableWindows()`, which didn't return
      the miss window - so I made it return the miss window and fixed the
      one consumer that didn't want it (bar hit error meter) to skip it.
    
    - Diff also contains some clean-up around `DifficultyRange` to unify
      handling of it.