Bump framework to 2026.422.1; root Android Surface managed peer to fix SDLActivity SIGSEGV#242
Merged
winnerspiros merged 5 commits intomasterfrom Apr 22, 2026
Merged
Conversation
…ns while hopefully not looking buggy anymore (ppy#37463) RFC. See ppy#37453 (comment) for why. Of note: - To facilitate mutual exclusivity of playback `PlayerHandOfCards` maintains a bindable pointing at the currently playing song preview. - Because of how card drawables are passed between multiple parenting drawables, some of which are and some of which are not `PlayerHandOfCards` instances, DI fails horribly at working with this bindable unless it is manually managed. See relevant overrides in `PlayerHandOfCards`. - I renamed one of the overloads of `HandOfCards.RemoveCard()` to `DetachCard()` because I found the fact that there are two overloads of one method that do WILDLY DIFFERENT THINGS utterly *asinine*. (One overload scrapes the `RankedPlayCard` out for you to plop elsewhere. One *drops it on the floor entirely*.) This took way too long to write.
…ues (ppy#37477) Thing to make release happen. Reverts ppy#37453 Reverts ppy#37463 Alternative to ppy#37473 Not that I disagree with any of these but I'm just looking to return to what works so we can do a release because we're on a clock here for other reasons. Test which should work but doesn't, so I'm not adding: ```diff diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs index f747004..eb8e360d1e 100644 --- a/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs @@ -1,12 +1,17 @@ // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; +using NUnit.Framework; using osu.Framework.Extensions; +using osu.Framework.Testing; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; namespace osu.Game.Tests.Visual.RankedPlay { @@ -14,6 +19,8 @@ public partial class TestSceneOpponentPickScreen : RankedPlayTestScene { private RankedPlayScreen screen = null!; + private readonly BeatmapRequestHandler requestHandler = new BeatmapRequestHandler(); + public override void SetUpSteps() { base.SetUpSteps(); @@ -26,8 +33,6 @@ public override void SetUpSteps() AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); AddUntilStep("screen loaded", () => screen.IsLoaded); - var requestHandler = new BeatmapRequestHandler(); - AddStep("setup request handler", () => ((DummyAPIAccess)API).HandleRequest = requestHandler.HandleRequest); AddStep("set pick state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = 2).WaitSafely()); @@ -44,7 +49,11 @@ public override void SetUpSteps() }).WaitSafely(); } }); + } + [Test] + public void TestBasic() + { AddWaitStep("wait", 15); AddStep("play beatmap", () => MultiplayerClient.PlayUserCard(2, hand => hand[0]).WaitSafely()); @@ -54,5 +63,29 @@ public override void SetUpSteps() BeatmapID = requestHandler.Beatmaps[0].OnlineID }).WaitSafely()); } + + [Test] + public void TestPickPreviewPlayedOnOpponentPick() + { + RankedPlayCard.SongPreviewContainer? originalPreview = null; + + AddStep("hover first card", + () => InputManager.MoveMouseTo(this.ChildrenOfType<PlayerHandOfCards>().Single().Cards + .First(c => c.Item.PlaylistItem.Value != null && c.Item.PlaylistItem.Value.BeatmapID != requestHandler.Beatmaps[0].OnlineID))); + AddUntilStep("preview playing", () => originalPreview = this.ChildrenOfType<RankedPlayCard.SongPreviewContainer>().FirstOrDefault(p => p.IsRunning), () => Is.Not.Null); + + AddStep("play beatmap", () => MultiplayerClient.PlayUserCard(2, hand => hand[0]).WaitSafely()); + AddStep("reveal card", () => MultiplayerClient.RankedPlayRevealUserCard(2, hand => hand[0], new MultiplayerPlaylistItem + { + ID = 0, + BeatmapID = requestHandler.Beatmaps[0].OnlineID + }).WaitSafely()); + + AddUntilStep("wait for original preview stopped", () => originalPreview?.IsRunning, () => Is.False); + + AddUntilStep("preview playing is opponent's pick", + () => ((RankedPlayCard)this.ChildrenOfType<RankedPlayCard.SongPreviewContainer>().SingleOrDefault(p => p.IsRunning)?.Parent!).Item.PlaylistItem.Value?.BeatmapID, + () => Is.EqualTo(requestHandler.Beatmaps[0].OnlineID)); + } } } ``` --------- Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
…37477) - Merge upstream ppy/osu master through commit a4f79f7 (PR ppy#37477: ranked play single-thread audio fix, supersedes/reverts ppy#37463). - Resolve conflict in RankedPlayCard.SongPreview.cs in favour of our fork's existing late-bind approach (Enabled/CardHovered subscribed inside LoadComponentAsync callback so they never fire pre-load). - Pick up the new TestPreviewStopsOnEnteringGameplay regression test. Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
…Activity SIGSEGV Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/a8a91f1f-e013-42d6-a7e3-f0d1accb9b89 Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/a8a91f1f-e013-42d6-a7e3-f0d1accb9b89 Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
Copilot created this pull request from a session on behalf of
winnerspiros
April 22, 2026 19:30
View session
There was a problem hiding this comment.
Pull request overview
Updates the project to newer ppy.osu.Framework packages and applies an Android Surface lifetime fix intended to prevent SDLActivity JNI crashes after surface loss/recreation, plus a regression test around ranked-play song preview stopping when entering gameplay.
Changes:
- Bump
ppy.osu.Framework/ppy.osu.Framework.Android/ppy.osu.Framework.iOSto2026.422.1. - Root the Android
Surfacemanaged peer (heldSurface) alongside the JNI global ref, and serialize create/destroy to avoid releasing the Java peer while native code still holds a handle. - Add a visual test asserting ranked-play song previews stop once gameplay is requested; refresh local-packages documentation version reference.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
osu.iOS.props |
Bumps ppy.osu.Framework.iOS to 2026.422.1. |
osu.Android.props |
Bumps ppy.osu.Framework.Android to 2026.422.1. |
osu.Game/osu.Game.csproj |
Bumps ppy.osu.Framework to 2026.422.1 and updates the pinned-version comment. |
osu.Android/OsuGameActivity.cs |
Keeps the managed Surface peer alive and tightens create/destroy ordering to prevent JNI crashes. |
osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayScreen.cs |
Adds TestPreviewStopsOnEnteringGameplay regression coverage for song preview shutdown. |
local-packages/README.md |
Updates the referenced framework version to 2026.422.1. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| BeatmapID = requestHandler.Beatmaps[i2].OnlineID | ||
| }).WaitSafely()); | ||
| } | ||
|
|
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.
native_crash.logshows the APK looping through two phases: (1)Veldrid.VeldridException: The Swapchain's underlying surface has been lostaborts the Draw thread, then (2) on relaunchSDLActivitydies withSIGSEGVinsidelibart.soJNI handling. The root cause of (2) is thatOsuGameActivity.SurfaceCreatedonly kept a JNI global ref onsurface.Handle— the localSurfacewrapper became GC-eligible the moment the method returned, and .NET-for-Android's finaliser then released the underlying Java peer that the global ref still pointed into.Changes
Bump
ppy.osu.Framework{,.Android,.iOS}2026.420.2→2026.422.1(osu.Game.csproj,osu.Android.props,osu.iOS.props). Pulls in winnerspiros/osu-framework PR Freeze CatcherTrail animation at generation time #17:IAndroidGraphicsSurface.SurfaceHandleimmediately beforevkCreateAndroidSurfaceKHR(managed exception instead of driver SIGSEGV when the surface is destroyed concurrently).SwapBuffers/Resize(skip frame, force swapchain rebuild on nextBeginFrame, bail out only after 60 consecutive failures).f85dd26.Root the Android
Surfacemanaged peer (osu.Android/OsuGameActivity.cs):heldSurfacefield +surfaceLockserialiseSurfaceCreated/SurfaceDestroyedso SDL/Veldrid can never see a half-torn-down state.GetSurfaceGlobalRef()now usesVolatile.Readfor ordered unlocked reads on the SDL hot path.Catch up
ppy/masterthrougha4f79f7(PRs Refactor audio preview logic in ranked play cards to match expectations while hopefully not looking buggy anymore ppy/osu#37463 + Apply different workaround to fix ranked play single thread audio issues ppy/osu#37477, ranked play single-thread audio workaround). Conflict inRankedPlayCard.SongPreview.csresolved in favour of our existing late-bind approach (Enabled/CardHovered subscribed inside theLoadComponentAsynccallback, so they cannot fire pre-load — equivalent in effect to upstream's deferred-Schedule). NewTestPreviewStopsOnEnteringGameplaybrought in.Docs/CI: refresh stale
2026.421.1reference inlocal-packages/README.md. CI workflows already authenticate to the winnerspiros GitHub Packages feed in every restore job; no version pinning lives outside the.csproj/.props, so nothing else to touch.Crash-relevant snippet