Repository navigation
Conversation
…Keys mods are active (#38228) Reported [on the forums](https://osu.ppy.sh/community/forums/topics/2221821?n=1).
See https://discord.com/channels/188630481301012481/380598781432823815/1522142729407037500 Needs testing and probably test coverage. Just PRing as draft for now for feedback. Alternative is undoing the optimisation chain, but it'll be a pain and adds significant overhead to the static diffcalc path.
abs(0) wasn't too great because it can cross over zero when two overlays are toggled. to avoid this issue, we check if the target is also zero before rounding the actual value down. Closes #38233.
Closes #26990. | | baseline (stable, unadulterated) | lazer | difference | | :-: | :-: | :-: | :-: | | **master** | <img width="528" height="528" alt="stable-untouched" src="https://github.com/user-attachments/assets/50575b95-6446-43f4-aa6a-529b9595e194" /> | <img width="528" height="528" alt="lazer-master" src="https://github.com/user-attachments/assets/81faae45-9e61-44a8-b7a3-cfb3fea88c47" /> | <img width="528" height="528" alt="stable-untouched-vs-lazer-master" src="https://github.com/user-attachments/assets/68fbfec8-cc6a-47b8-a27f-110b03d4d05f" /> | | **this PR** | <img width="528" height="528" alt="stable-untouched" src="https://github.com/user-attachments/assets/50575b95-6446-43f4-aa6a-529b9595e194" /> | <img width="528" height="528" alt="lazer-pr" src="https://github.com/user-attachments/assets/df2c5573-964d-418d-951c-01359692a25b" /> | <img width="528" height="528" alt="stable-untouched-vs-lazer-pr" src="https://github.com/user-attachments/assets/bcb0ec7c-3eeb-4afd-b86d-23018a4e478f" /> | --- To explain this change I will first need to explain stable. How kiai flashing works ----------------------- As per stable source[^1] linked in #26990 (comment), kiai flashing for a hitobject `h` works in the following way: - Take `h.CreateKiaiSprites()`. - For hit circles this is just `DimCollection[0].Clone()`[^2]. - Add `0.1f` to `Depth`. - Set additive blending. - Set colour of kiai sprite to accent colour of hitobject plus `max(25, 300 - R - G - B)` to each component. - Add a fade-out transform. There are two points of interest here to determine what stable does: what is `DimCollection[0]`, and what practical effect the `Depth` change has. To determine that, it is required to understand how a `HitCircleOsu` is rendered. stable hit circle rendering --------------------------- `HitCircleOsu` consists of the following sprites (listed in order of appearance in source and addition to `SpriteCollection`):[^3] | Member name | Texture name | Depth | `DimCollection` | | :--------------------- | ------------------ | --------------------------------------------------- | --------------- | | `SpriteApproachCircle` | `approachcircle` | `drawOrderFwdPrio(2000 + StartTime - LocalPreEmpt)` | not present | | `SpriteHitCircle1` | `hitcircle` | `drawOrderBwd(StartTime)` | index `0` | | `SpriteHitCircle2` | `hitcircleoverlay` | `drawOrderBwd(2000 + StartTime - LocalPreEmpt)` | index `1` | | `SpriteHitCircleText` | skin number font | `drawOrderBwd(2000 + StartTime - LocalPreEmpt)` | not present | The above already exposes one discrepancy compared to lazer. On master, the kiai effect is applied individually both to `hitcircle` and `hitcircleoverlay` - but stable never actually does the latter. However, it is still unclear at what level in the depth ordering of sprites the cloned `hitcircle` that represents the kiai flash resides. Further analysis to determine this follows below. Depth ordering analysis ----------------------- First, let's define the two functions referenced above in the depth column:[^4] ```csharp /// <summary> /// Used by hit values. Has a range of 0.8-1 and loops every 10000 seconds (over 1 hour). /// </summary> /// <param name = "number"></param> /// <returns></returns> internal static float drawOrderFwdPrio(float number) { return 0.8F + (number % 6000000) / 30000000; } /// <summary> /// Used by hitcircles. Has a range of 0.8-0.2 and loops every 6000 seconds (1 hour). /// </summary> /// <param name = "number"></param> /// <returns></returns> internal static float drawOrderBwd(float number) { return 0.8F - (number % 6000000) / 10000000; } ``` To simplify further deliberations, let's assume some variables. These assumptions are a bit shaky, but should not meaningfully disturb further deliberations. - `StartTime = 2000` - `LocalPreEmpt = 1200` (corresponds to AR=5), - `OverlayAboveNumber = true` (default). Given the above assumptions, we have: - `SpriteApproachCircle` with depth 0.8+(2000+2000-1200)/30000000 = 0.8000933333 - `SpriteHitCircle1` with depth 0.8-(2000/10000000) = 0.7998 - `SpriteHitCircle2` with depth 0.8-((2000-2)/10000000) = 0.7998002 - `SpriteHitCircleText` with depth 0.8-((2000-1)/10000000) = 0.7998001 - The kiai flashing sprite has depth of `SpriteHitCircle1` + 0.1 = 0.8998 Which would make the final ordering: 1. `SpriteHitCircle1` on the bottom 2. `SpriteHitCircleText` above (1) 3. `SpriteHitCircle2` above (2) 4. `SpriteApproachCircle` above (3) 5. The kiai flashing sprite above (4) and topmost. This exposes the second discrepancy: the kiai flashing sprite, despite being only a copy of `SpriteHitCircle1` / `hitcircle`, is positioned *above* `SpriteHitCircle2` / `hitcircleoverlay` and will in fact be faintly visible on some skins as a subtle halo on `hitcircleoverlay`. To illustrate this, see the following series of screenshots (recommend viewing these against a dark background): | stable, kiai sprite with initial alpha set to zero | stable, kiai sprite with initial alpha set to 1 | difference (with pink rings highlighting bounds of the `hitcircleoverlay` ring) | | :-: | :-: | :-: | | <img width="522" height="522" alt="stable-no-kiai-effect" src="https://github.com/user-attachments/assets/4fa1240d-daa9-4061-9b6c-6b9db4da13f6" /> | <img width="522" height="522" alt="stable-kiai-effect-exaggerated" src="https://github.com/user-attachments/assets/a7408207-04bc-4b68-93d3-f337caf55640" /> | <img width="522" height="522" alt="stable-kiai-difference" src="https://github.com/user-attachments/assets/27ad41bf-68d5-4813-a664-2e40f2dcdbef" /> | You should see a faint amount of green creep outside of the inner pink ring, which proves that on stable the kiai effect sprite is in front of `hitcircleoverlay`. The fix ------- To correct the above, the following is done: - The `hitcircleoverlay` sprite is no longer wrapped in a `LegacyKiaiFlashingDrawable` instance, because as discussed above, in stable it is not used for the kiai effect in any way. - The flashing sprite from the `LegacyKiaiFlashingDrawable` instance that is wrapping `hitcircle` is proxied out to be in front of `hitcircle`, `hitcircleoverlay`, and the combo number. This should match stable's depth ordering behaviour at least in the simple case. To disclaim from the get-go, I have not looked into worse cases like slider repeats, as the ordering is significantly more complicated in that case (#14561 (comment)). I am sort of hoping it will be fine, but I will double check if I am made to - I kind of want to see the reaction to what is in this diff already before expending even more effort towards this task. [^1]: Stable reference: [`Ruleset.UpdateKiai()`](https://github.com/peppy/osu-stable-reference/blob/0e0aa3b29b10c81ef917de0551421274d22cdc79/osu!/GameModes/Play/Rulesets/Ruleset.cs#L1400-L1459) [^2]: Stable reference: [`HitObject.CreateKiaiSprites()`](https://github.com/peppy/osu-stable-reference/blob/0e0aa3b29b10c81ef917de0551421274d22cdc79/osu!/GameplayElements/HitObjects/HitObject.cs#L326-L334) [^3]: Stable reference: [`HitCircleOsu` constructor](https://github.com/peppy/osu-stable-reference/blob/0e0aa3b29b10c81ef917de0551421274d22cdc79/osu!/GameplayElements/HitObjects/Osu/HitCircleOsu.cs#L81-L113) [^4]: Stable reference: [`SpriteManager`](https://github.com/peppy/osu-stable-reference/blob/0e0aa3b29b10c81ef917de0551421274d22cdc79/osu!/Graphics/Sprites/SpriteManager.cs#L755-L775)
…table (#38164) Fixes issue [#37532 ](#37532) Since slider body should start fading after head disappears and slider body fades in at same time as head, offset body fade out start by head fade out duration and decrease long duration by the same amount First ever open-source contribution, yay (I HAVE SAVED HD) https://github.com/user-attachments/assets/be44a6d6-4d89-49a0-a3db-f57daac6ac12
This is a very loose RFC that needs more testing, but first and foremost I would like to confirm that I am at least in the vaguely correct wheelhouse before proceeding further. Video demo: https://drive.google.com/file/d/1BWlrohNgfKWDLDEENDunhsNnl6W4sDmY/view?usp=share_link (too large to live on GitHub). ## [Add liveness probes to API](5562ed3) As described in #35736. Some ground rules: - I'm not going to attempt to decide where the probe should be hosted, this PR is mostly agnostic to that anyway. - When API is in online state, the probe is periodically queried every minute (interval up for debate). - If the probe URL is not set, nothing happens. - If the client can't reach the probe, nothing happens (or at least that's the intended design). This is such that client-local outages or inabilities to reach the probe don't knock the rest of the game offline *even though everything can be fine with it*. - If any other deserialisation error or anything else happens, nothing happens. - The only time where anything happens is when the probe is up and actively returns a result that shows that there is an active outage going on. In this case, API is instantly knocked to `Failing` state. - When API is in failing state, the probe is queried more actively (every 5 seconds as written, but this is also up for discussion). - If the probe actively returns a result that shows that there continues to be an active outage going on, the client does not attempt to get back online. - In *any other circumstance* (read: the probe being disabled, unreachable, or returning a result that indicates that there is no active outage), the client will try to get back online. - The side benefit to this is that this could provide relief from retry traffic when we have known outages going on. The reason this is designed this way is to be fail-safe. In particular, my concern here is that e.g. the probe being potentially unavailable to Russia users due to network blocks does not completely delete online functions for those users. ## [Skip attempting submission when API is in failing state](3d3caeb) Speeds up gameplay loading when loading is more or less doomed to fail anyway. Will also spam notifications about submission not happening. This could be probably made smarter if we want to (e.g. notify once until API comes back online), but I'm not super sure we *want* that, and maybe being super loud about submission failures is the preferred way to go instead. --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
… size (#38263) | before | after | | :-: | :-: | | <img width="291" height="71" alt="Screenshot 2026-07-09 at 14 44 15" src="https://github.com/user-attachments/assets/7625aaa7-9192-44aa-9220-1c0571b80370" /> | <img width="290" height="54" alt="Screenshot 2026-07-09 at 15 00 04" src="https://github.com/user-attachments/assets/29a2d014-65c8-4e64-be6a-3783cc41f319" /> | --- Closes #38255. Hardcoding a height is a pretty sucky fix but I'm not sure I see better alternatives and this works for all languages that we have in the game. This also includes a visual tests so it doesn't require running the game in release to visually review this. I'm not entirely sure that doing that is a good idea, I half-expect there to be hell in tests from touching locale. So maybe wait until this goes through CI green before clicking any buttons.
Ride inspection failing for this, no idea why.
| this PR | Web | | --- | --- | | <img width="491" height="251" alt="Screenshot 2026-07-01 at 10 13 20 PM" src="https://github.com/user-attachments/assets/01b8d8d0-53b2-45eb-bcc5-10cd03193402" /> | <img width="360" height="120" alt="Screenshot 2026-07-01 at 10 13 47 PM" src="https://github.com/user-attachments/assets/d01b6737-0165-40c4-bff7-6860c35cbebe" /> | --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
https://github.com/user-attachments/assets/a3f7cd65-271a-4604-adb3-94fdc4bac1dc - Default presets match stable (0.75x, 1.00x, 1.50x). - Set a non-standard velocity and press the green "+" button to create a new preset. - Middle-click or shift-right-click an existing preset to delete it. - Presets are stored to the `[Editor]` section of the `.osu`, therefore they are persistent when saved and will also be accessible to other people that open the map in the editor. --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
…ssing is ongoing (#38272) <img width="2298" height="656" alt="2026-07-11 01 17 52@2x" src="https://github.com/user-attachments/assets/7538bbb3-0d58-4974-ba21-7311bd5e75a1" /> <img width="846" height="356" alt="2026-07-11 01 18 33@2x" src="https://github.com/user-attachments/assets/7092c70b-1899-43ae-97d8-a728308366f5" />
Some people are having too much fun with it. Intentionally PR'ing against `master` so that it can be merged without waiting for the next pp deploy. <img width="1285" height="435" alt="image" src="https://github.com/user-attachments/assets/fbdd7e2e-4146-43d3-9c47-30a6fbb3e1b4" /> --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
"No Release" mod changes the beatmap's notes before "Invert" mod runs. "Invert" rebuilds the whole beatmap, replacing all the No Release hold notes with regular hold notes. This is a workaround, not a real fix — the two mods could compose correctly if IApplicableAfterBeatmapConversion mods were applied in a different order (currently determined by ModType). Reference issue: #37871 Co-authored-by: 汪钰楚 <wangyuchu@ous-MacBook-Pro.local>
Co-authored-by: Loreos <idontcare@mail.ru>
…d calculations (#38276) Due to `HarmonicSkill` weirdly storing `ObjectWeightSum`, calling `DifficultyValue` more than once on a single skill results in any strain count related operations doing weird things. This is fine outside of timed calculation, as there's never a reason to call `DifficultyValue` more than once. Definitely need to check timed calculation more frequently as part of the PP development process. As part of this change, I have updated the tests to assert _all_ attributes are equal between timed and not-timed, rather than just max combo and star rating. With this change, they are passing.
| master | PR | |-|-| | <img width="552" height="487" alt="image" src="https://github.com/user-attachments/assets/fcd170f8-84e0-43c0-927a-f05386ce786a" /> | <img width="551" height="493" alt="image" src="https://github.com/user-attachments/assets/50ffe642-ffeb-4824-b8c2-b2669d01ccad" /> |
Addresses #38301. Originally we just added the extras for mouse buttons, but no real reason not to do this. Feels more balanced. Of note, I've also changed the default ordering because it looks better in the UI. <img width="480" height="306" alt="osu! 2026-07-15 at 07 50 53" src="https://github.com/user-attachments/assets/c2f3238a-8903-4450-b086-af9805884fb9" /> --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
…es (#38314) RFC. The angle to this commit is to possibly close #26559. Enabling frame stability in the editor has been tried once before in #26382, and then reverted in #26521. The reason for it being reverted is that it caused a performance degradation, most visible in the mania editor. Even in #26382, an inline comment expressed the hope that "gameplay elements should not require frame stability". Before I go further, I feel like this comment warrants addressing. The problem here is that it is not so much the case that "gameplay elements require frame stability" for hitsounds to correctly play. The bigger problem here is that *the editor is reliant on accurate replay playback to show how gameplay looks like*. When frame-stable playback is off, the `FrameStabilityContainer` is allowed to *entirely skip frames* that hit some objects. Due to this, those objects *never become hit* and are *misses* instead, and *that* is why they do not play a hitsound. You can experimentally verify this by commenting out https://github.com/ppy/osu/blob/43897457fb7b0617125aa05a084e4078633ad4ac/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs#L42 and playing a beatmap such as https://osu.ppy.sh/beatmapsets/1252588#osu/3203995 in the editor. On my setup at least, there are several missed objects in the first 20 seconds of the map. Given the dependence of editor gameplay preview correctness on replay playback correctness, there do not appear to be many choices here other than: 1. Improve replay playback correctness as much as possible by enabling frame stability as often as possible. 2. Stop depending on replays for editor gameplay preview. I briefly explored option (2). The idea behind it was to completely dissociate from the replay subsystem and instead have editor-specific code that would simulate perfect gameplay *inside* `DrawableEditorRulesetWrapper` by forcing hits to happen in the correct time instants on the `DrawableHitObject`s. After some finagling, I got it to work... only in the osu! ruleset. The problem with this idea is that *it is not sufficient* to only operate on the `DrawableHitObject`s. Other rulesets have parts of the playfield that need to somehow show user input too. - taiko has the input drum (which notably is the one making sounds). - catch has the catcher. - mania has the keys (which notably are the ones making sounds, leaving aside foibles like maps keysounded via storyboard samples) Therefore, for that idea to work, *each ruleset* would have to bundle its appropriate logic for real-time simulation of gameplay, basically duplicating what replays / autoplay already is in a clunkier way. Thus I am offering this diff in earnest. The hope is the issues that were hit in #26382 can be avoided with additional heuristics. - Frame stability is only active when the editor clock is actually running. If it were to be enabled while the editor clock was *not* running, instant seeks could become non-instant. Moreover, the impact of it being off in that scenario is reduced as hitsounds do not play when the editor clock is paused anyway. - Autoplay regenerations turn off frame stability for a frame. This is because substituting the autoplay replay under the drawable ruleset while the editor clock is running would result in the drawable ruleset replaying the entirety of the new replay from the start until the editor clock's current time, which results in long frame times and many hitsounds playing at once. - Large seeks turn off frame stability as they would also provoke a clock catch-up, which will result in long frame times and many hitsounds playing at once. (This is unchanged from the original attempt.) It is very possible that in the future these heuristics will need to be expanded further to cover off other scenarios. For instance, I predict that frame stability may be disabled in the future in the case of live mapping, though the heuristics above (particularly the autoplay regeneration case) may be enough to handle that use case.
…#38316) This is mostly just to reduce visual clutter. The buttons look much less present when in a disabled state. https://github.com/user-attachments/assets/5d6275f2-77d8-4399-9602-7635d6b30008 --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
I don't think this will be the last pass on these (I want to make stuff more compact) but this was just to get things aligned for horizontal use of multiple form components. | Before | After | | :---: | :---: | | <img width="1342" height="1400" alt="2026-07-16 02 27 03@2x" src="https://github.com/user-attachments/assets/7ccd8064-6d41-4aeb-8fc5-1ea480e484f2" /> | <img width="1342" height="1400" alt="2026-07-16 02 26 20@2x" src="https://github.com/user-attachments/assets/dc999b07-0cfe-4bc8-b44f-a926a39d824e" /> | --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
See ppy/osu-beatmap-difficulty-lookup-cache#22 for rationale. Regardless of the linked issue, I think this makes more sense anyway. Keeping `Mods` around just for this case, which is much better solved by nullables, seems silly. Intentionally pointed at `master` since this is purely refactor and a package bump would be required to close the linked issue.
https://github.com/user-attachments/assets/2b35b65b-ce2c-48eb-a4e4-4d98a8ed1ecd --- - [x] Depends on ppy/osu-resources#441 - Part of #24996 --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
Closes #38036. Drive-by-fix which should make sense without visual check. And yes, I'm aware this affects gameplay visuals. None of these visuals were made to handle 10,000 bpm. Intentions is to roll out this change, limiting upper animation BPM to 1,200 and seeing if anyone complaints (in the other direction). I highly doubt that will be the case. Why was 50 ms / 1,200 bpm chosen? It's the lowest value which still allows the osu! logo to animate at all. --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
…area / leaderboard (#38105) Resolves #37977 Currently, long clicking on the empty background space in the beatmap details area does not trigger the background preview like it does on the song select carousel. This MR reverts the blanket changes in #33748, and replaces them with logic to filter wanted / unwanted OnMouseDown events in BeatmapDetailsArea. Any feedback here is appreciated! Before: https://github.com/user-attachments/assets/776e4de7-66e8-4488-831b-81fab456d5b0 After: https://github.com/user-attachments/assets/64b07d84-36ae-4a90-a4a2-6e794f748c4a --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
) - Builds off #28733 - Addresses #37901, #38410, #18654, #25068, #34798 - [x] Depends on ppy/osu-framework#6834 Caveats: - Intentionally called "hitsound volume", not "gameplay volume" because the intention is to specifically target hitsounds. Gameplay effects should still be adjusted by the effect volume, as far as I'm concerned. (alternative take: call this gameplay and include everything non-UI, then rename "effect" to "UI sounds" or something) - Affects everything in the playfield and overlay layers. This seems like a pretty good separation point, which includes things like the metronome from muted mod. It's about what players will expect from this. - Does not affect storyboards. I'm sure we're going to get people complaining about that meaning that "storyboarded hitsounds" are not affected, but I'm not sure whether this is a correct take or not. - The following now reads bad. It looks as if the "beatmap hitsounds" would be a toggle turning them off, not enabling/disabling beatmap skinned hitsounds. Open to suggestion: <img width="726" height="456" alt="CleanShot 2026-10-06 at 21 48 33@2x" src="https://github.com/user-attachments/assets/23cedcdf-fe2f-49c9-b3d6-b6204f1d9af0" /> There may be exceptions that come up which we need to handle separately. I may do a 180 based on how this is received and adjust more than one of the caveats above. Tachyon feedback will be important here. I also have started on a redesign of the volume overlay to better house this. Consider the one in this PR a temporary change. --- This brings a long-sought feature online. I'm not 100% sure on what this should or shouldn't cover, so any feedback is appreciated on how this works for you! <img width="3428" height="2154" alt="CleanShot 2026-10-06 at 21 50 49@2x" src="https://github.com/user-attachments/assets/72b714f3-f244-4987-b1bf-ca8e41d23ec9" />
…en mod select is open (#38221) - Closes #38146 When pressing Alt-F4, the mod select overlay never closes and does this in order: ```c# SetButton(); clearActiveOverlayContainer(); // inside SetButton() ``` Pressing home or exiting via Esc runs `clearActiveOverlayContainer()` first, and it doesn't trigger the bug because the `hiddenButtonsContainer` container gets cleared before the `temporarilyHiddenButtons` list does. Unsure why `SetButtons()` needs to clear `temporarilyHiddenButtons`. There's no regression when I tested. `Hide()`ing the overlay on the screen's `OnExiting()` is also a fix. `MultiplayerMatchSongSelect` already has `freeModSelect.Hide()`. I've applied both above as one makes sure the bug doesn't happen anymore when forgetting to `Hide()` the overlay on the screen's `OnExiting()` and the other fixes the no pop out animation. --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
Closes #38697. --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
…#39026) RFC. This is connected to [ongoing work on the new results screen](#24996). To justify it, allow me a wall of text. The concept of the game-global screen footer that lingered about in past designs for a while and was kicked into higher gear with song select V2 is a pretty neat concept, but it is also a large pain point with respect to skinnability. To function, the global footer must inevitably: - Be on top of everything (draw order wise). - Not be part of individual screens (transitions, etc.). - Must provide a limited API for screens to display content on it. - Must enforce a uniform look across screens to not look wrong. All of those are pretty large issues when it comes to skinning. If one were, for instance, to reimplement the stable results screen inside lazer (more on this... *later*), the new footer would still make the results screen look *wrong*, because overlaps aside, the aesthetics would just not match. What does this have to do with this refactor? Previously, a screen could only manipulate the global footer's content on entry - either it specified a global footer with some buttons, or it did not, and instead a single back button was optionally provided. This refactor makes it possible to manipulate the global footer at *any* point of the screen's lifetime, by introducing `IOsuScreen.FooterContent` as a plain bindable. This sort of exposition, in turn, makes it possible to perform the following parlor trick: Assume a skin component with no actual visuals of its own, that silently occupies the bottom area of the screen which coincidentally matches the screen estate taken by the global footer, is not movable, and is a singleton (only one instance of it can be present in the skin). Now that `IOsuScreen.FooterContent` exists, this component could do the following: - In its BDL, the component resolves the parenting screen and mutates its `FooterContent` such that the global footer gets displayed, with buttons specific to a given screen. - In its `Dispose()`, the component changes the `FooterContent` to nothing. The end result of this parlor trick is that you get a faux-"skinnable component", whose presence is equivalent with the presence of the global footer. Thus, it is a *facility to force or suppress it* on specific screens according to users' whims that already fits into the existing skinning system (well, save for the "immovable / singleton" parts, but again - more on this later). Heck, you could even feasibly outfit it with settings to allow limited control of said global footer content. The secondary argument for this change would be code quality. The initial iteration of the global footer resulted in a pretty contrived API; `IOsuScreen` had all of `BackButtonVisibility`, `ShowFooter`, and `CreateFooterButtons()`, and `OsuScreen` additionally had `InitialBackButtonVisibility` that by default *fell back* to another virtual (`AllowUserExit`). This refactor replaces all of those members with what is essentially a handrolled discriminated union. (Actual discriminated unions ***FINALLY!!!*** exist, but they only exist in C# 15 / .NET 11, so it's going to be a while until I can be their greatest shill.) Note that there is another reason why the existence of this discriminated union is particularly convenient. The results screen designs specified retry / save replay buttons on the far end of the footer, which is not currently a supported feature. The idea is that `ScreenFooterContent` could also feature a `RightButtons` member and this member would allow for implementing that part of the design. Without it, something like `OsuScreen.CreateRightFooterButtons()` or similar would need to be called into existence instead.
https://github.com/user-attachments/assets/9b1cf197-608d-4914-a8f9-19c2dc325760 Before any further comments, please note that all of the incoming argon results screen components are *first iterations* and not necessarily visually finalised, and this component is the most 'first iteration' out of all of them. --- - Part of #24996 The reasons why this is a "first iteration": - stable rank letter sprites are used because (a) I have nothing better that's approved for use (cc @peppy) and (b) they're being used on the ranked play results screen too. The one problem with this is that there is no dedicated sprite for F rank because stable didn't have one at all. Up in the air as to what happens with that. - Audio design is transplanted from the old results screen without too much thinking (cc @nekodex). Maybe it is no longer good or applicable. At this point the point is to have audio at all.
I guess we can see how this goes, even though it's experimental. Some things to note: - I have not tested on-device performance of tihs. - There _have_ been GC-related performance issues (which is exactly where I'd be concerned), on .NET 11 where this is no longer experimental. These appear to be on-going developments. See: dotnet/android#12236 - We have to drop support for `-arm` and `-x86` platforms, though `-arm` becomes re-available in .NET 11. Probably not an issue, but something to note. - This appears to be limited to Android for now - I have not been able to successfully build iOS with it. Likely available in .NET 11, but haven't tested. --------- Co-authored-by: Shiumano <takkunmail2005@gmail.com>
…9036) https://github.com/user-attachments/assets/d5260fe4-5d60-43d8-a202-95f34f72dbf8 --- - Part of #24996 All TODOs left intentionally and will be addressed in future follow-ups.
…al footer (#39035) https://github.com/user-attachments/assets/f5565bf5-348a-44a9-ae5d-cf7a25724821 --- To be used in the [upcoming results screen redesign](#24996). 667d776 is of particular note. To restate that commit's message with video demonstration: > This is something I noticed when implementing the support for buttons on the right end of the global footer. > > In general, the footer buttons have two pairs of transitions attached: one wherein the buttons move from/to below the screen, and one wherein they move to the side. The transitions below were supposed to play when transitioning from no buttons to some buttons, as well as vice versa (from some buttons to no buttoins), while the transitions to the side were supposed to play when transitioning from some buttons to *other* buttons. > > The issue here is that the side transition was silently broken by e74f687. The call to reset buttons to nothing on screen entry caused the transition to change from playing out horizontally, to playing out vertically. > > Of particular note, this only applies to *entering* a screen. It seems that *exiting* to an existing screen *still* plays out the horizontal transition: > > https://github.com/user-attachments/assets/a7bc737e-38bb-4225-8d84-78b7496448e8 > > This commit fixes this inconsistency as best as it can. The result is awkward, I will not argue otherwise, but I'm not sure I can see anything better to offer. Besides maybe completely axing either pair of transitions. > > https://github.com/user-attachments/assets/75202eb6-390d-4f38-b1e4-6e4bfa0ff68d
#38913) Merge error is from #30838, where the entire `TestScenePlaylistsRoomSubScreen` file gets deleted for some reason. Regressed in that PR too. Before: https://github.com/user-attachments/assets/7621195f-8993-4b66-9a9b-32546b01864a After: https://github.com/user-attachments/assets/c6bfbfad-c0ca-4c91-a652-06ca2a767407 --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
- [x] Depends on framework package containing ppy/osu-framework#6838 Like ["beatmap attribute text"](https://github.com/ppy/osu/blob/576dbb2a19b43f556c6ef82b14e90ebad15fea3d/osu.Game/Skinning/Components/BeatmapAttributeText.cs#L29), but for scores. This'll come in handy to implement the text in the top left corner of the legacy results screen design. And in general for people to make everything custom for themselves (to the degree that the text components allow). Supported placeholders: - `Username` - `TotalScore` - `MaxCombo` - `Accuracy` - `Date` - `PP` (where populated, which it won't be on local scores, but I'll worry about that later - the grid component also has this issue and I intend to not have both of them calculate pp locally twice *somehow*) - `Rank` - `Mods` - Statistics via `{HitResult}Label`, `{HitResult}`, and `{HitResult}Max` --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
I have no real inkling why (or inclination to find out the specific details why), but despite `ScoreAttributeText` inheriting `FontAdjustableSkinComponent`, the latter of which implements `ISerialisableDrawable`, the `IsEditable` override was not actually functioning. For it to function the interface has to be restated on `ScoreAttributeText`. This is best observed by turning the `IsEditable` property to an explicit interface implementation; without restating the `ISerialisableDrawable` interface, turning the property explicit results in a compiler error.
…web (#39063) Recent changes in web: https://github.com/ppy/osu-web/commits/master/app/Libraries/LocaleMeta.php Tested new language working by looking language section (stating the obvious because `es` and `es_419` are similar, and if I made a typo like `es_420` it fallbacks to `es`): <img width="394" height="192" alt="osu!_vORZt1wkiF" src="https://github.com/user-attachments/assets/3e42b527-1183-407c-8d1a-44855db6af09" />
Closes #39051. This one is a bit difficult to explain but I shall attempt using visual aids. The following discussion will be constrained to this helper method: https://github.com/ppy/osu/blob/44819244af116e8ae08fe2cbd29c6e489b5c9d4e/osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs#L297-L317 We have the following givens: - An axis-aligned rectangle defined by two points: $\texttt{lowerBounds} = (x_\min, y_\min)$ and $\texttt{upperBounds} = (x_\max, y_\max)$ - A point $p = (x_p, y_p)$. The method is trying to determine the range of scalar values of $\textbf{a} \in \mathbb{R}$ such that $\textbf{a} \cdot p$ is contained in the axis-aligned rectangle. The following drawing attempts to explain how this is done in the happy path, exploiting the [intercept theorem](https://en.wikipedia.org/wiki/Intercept_theorem):  The four intersection points of the ray starting at the coordinate origin and passing through p with the axis-aligned rectangle are computed, and thus also the scalar factors to bring $p$ to each edge of the rectangle. Taking the maximum of the factors applied to $p_1$ and $p_2$ yields the final lower bound, and taking the minimum of the factors applied to $p_3$ and $p_4$ yields the final upper bound. However, there is a distinct possibility that the following situation occurs:  In this situation, the ray never crosses the rectangle. The "intersection" points can still be computed the same, but they will not be actual intersection points anymore. Applying the same operation as in the first case will return a *result*, only an improper one - the final lower bound will be *bigger* than the final upper bound. Note that the point $p$ being outside of the rectangle is a *necessary*, but not *sufficient* requirement for this scenario to occur. Consider the following:  In this scenario, $\vec{p_1}$ does run into the special case, but $\vec{p_3}$ will not - its extension through the origin of the coordinate space crosses the rectangle, so it'll work fine. That is why this is not just a direct bounds check.
…39039) This PR changes the static 'hit' SFX played when doing damage in ranked play from a single sample to one of six, chosen dynamically based on context: Special situations: - K.O. / Final hit - Last stand / One-shot protection triggered Otherwise, it's based on the amount of damage done: - 1 damage done - easter egg - 2 - 99,999 - low damage variation - 100,000 - 499,999 - medium damage variation - 500,000+ - high damage variation The breakpoints are kinda arbitrary, so feedback is welcome if they need tweaking (and/or more breakpoints desired?) --- - [x] depends on ppy/osu-resources#446 --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
https://github.com/user-attachments/assets/62595a2f-62f0-45f4-9021-902c22f1ad98 Caveats: - osu!: geki and katu counts not available. - taiko: `hit100k` count not available. - custom rulesets: rudimentary support. - Sprite fallbacks may not work properly yet. Will be tested better against end user skins when everything is in place. --- - Part of #24996. - [x] Depends on resources package with ppy/osu-resources#447 for retro skin to look as on above video in test scene. Code sucks in places. I attempted to comment as required but in general I plead stable.
forot to commit before merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot]
Can you help keep this open source service alive? 💖 Please sponsor : )