Fix steam client#1
Merged
Merged
Conversation
Co-authored-by: Phobos665 <5970062+phobos665@users.noreply.github.com>
…hdalal#1133) * feat: update wine-mono version to 11.0.0 in installer scripts * fix: bump_version in ImageFsInstaller.java, will trigger extraction for all existing containers that are on Mono 9.0.0 and install 11.0.0.
* feat: add fake HDR screen effect * fix: remove quick menu darkening scrim * chore: shorten HDR effect description * refactor: rename HDR effect to vivid mode * i18n: add vivid mode translations
DownloadService caches directory listings for 5s. After deleteApp, the cache still holds the deleted directory, so the subsequent LibraryInstallStatusChanged refresh sees stale data. Invalidate the cache after deletion so the next scan picks up the change.
…tkarshdalal#1191) * fix: correct steam game dlc licensing logic and enhance dlc display in content Cross-references resolved depots with owned DLC package information to ensure depots are attributed to the correct DLC app ID. This ensures accurate DLC identification for titles like Don't Starve, Halo MCC, and Cyberpunk 2077. * refactor getMainAppDepots to calculate the logic to be used in getDownloadableDepots
…dalal#918) Also use state.isSteamConnected (Compose-observable StateFlow) instead of SteamService.isConnected (static boolean invisible to recomposition) for banner visibility.
* fix: case-insensitive .exe filter in getWindowsLaunchInfos * removed bug around appLaunchInfo null opening wfm.exe * fixed build * addressed coderabbit * more coderabbit --------- Co-authored-by: Dan Brooke <mail@danbrooke.net> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com>
…s to steamcloud (utkarshdalal#1100) * migrate GSE Saves to steam userdata, always upload userdata files to steam cloud fix tests * move migrateGSESavesToSteamUserdata just before beginLaunchApp * also migrateGSESavesToSteamUserdata just before forceSyncUserFiles * also migrateGSESavesToSteamUserdata in SteamUtils ensureSteamSettings * use Files.move for migrating files * check dir empty to exit earlier, update logging * preserve file attributes like timestamp and permission during migration
* Add reusable ini game fix for Imperivm * Avoid rereading ini fixes after migration * Remove ini migration marker tracking
…ior (utkarshdalal#1014) * feat: disable IME extract UI and centralize singleLine keyboard behavior * fix: convert remaining OutlinedTextField to NoExtractOutlinedTextField
…al#1199) Maintains the original modification time from Steam Cloud for downloaded files. This ensures that games which rely on file timestamps for save loading and ordering, such as Skyrim, function correctly.
* feat: added multi-controller support
- physical controller handler services now acommodate multi controller
state management via deviceId
- new autoassign func
- windhandler accomodated MAX_PLAYERS = 4 suppot, multi-controller state
management
- new MultiControllerTest.kt test suite
fix: address multi-controller rumble and device identifier bugs
- prevent missed rumble on secondary slots when controller is adopted
after a rumble command arrives by deferring the "delivered" marker
- remove unreachable vendor/product fallback in device identifier
lookup since getDescriptor() is available on all supported API
levels
revert to original controller manager handling legacy cases and added test case
* handled respect disabled slots when reusing an existing assignment
* reset rumble state when a slot adopts a new controller
* magic number removed using dedicated WinHandler.MAX_PLAYERS const
* removed more magic numbers - using dedicated MAX_PLAYERS const and remove null controller phone vibrate case with some docs on why
---------
Co-authored-by: = <=>
* feat: add quick menu fsr and sharpness controls * refactor: port fsr passes from official gpuopen source * feat: add true fsr render-scale upscaling * chore: remove fsr toggle description * refactor: derive fsr input from container resolution * feat: add live scaling modes * chore: move scaling controls to top of screen effects * fix: match default fsr rcas denoise behavior * fix: save quick menu scrim removal before master sync * fix(renderer): only override render target size for scaled scenes
…shdalal#1136) * fix: clear stale container state on task swipe and app restart when the user swipes the app from the task switcher while a container is running, keepAlive stays true but xEnvironment is gone. on next launch the app is stuck thinking a container is running. extract shutdownEnvironment() from XServerScreen.exit() so the same full teardown runs in both the normal exit path and the crash recovery path. each step is wrapped in runCatching so one failure doesn't prevent the rest. - onCreate: if keepAlive is set but xEnvironment is null, run shutdownEnvironment() to clear stale state - onDestroy: emit ActivityDestroyed before super (so exit() listeners still fire), then force shutdownEnvironment() if keepAlive persists - exit(): delegates teardown to shutdownEnvironment(), keeps only winHandler.stop() and trash cleanup (container-specific) * fix: stop all foreground services on task swipe when idle Steam/GOG/Epic services had no onTaskRemoved — foreground notification persisted after swipe because nothing told the service to stop itself.
…edge cases (utkarshdalal#1157) * fix: recognize WindowsHome UFS root as PathType.Root for cloud save sync Steam PICS can specify `root: WindowsHome` in save file patterns (e.g. Stellar Blade, app 3489700). PathType.from() did not handle this token, causing it to fall through to PathType.None. None.isWindows is false, so the pattern was silently dropped in getLocalUserFilesAsPrefixMap and the saves were never scanned or synced. WindowsHome is the Windows user home directory (C:\users\xuser\ in Wine), which is exactly what PathType.Root maps to. Fix by recognising "windowshome", "%windowshome%", and "root" in PathType.from() as Root, and adding Root to the isWindows set so it passes the save pattern filter. * fix: recognize SteamCloudDocuments UFS root as WinMyDocuments for cloud save sync Steam PICS can specify `root: SteamCloudDocuments` in save file patterns (e.g. Sonic Mania, app 584400). PathType.from() did not handle this token, causing it to fall through to PathType.None and be silently dropped during save pattern filtering. SteamCloudDocuments is Steam's name for the user's Documents folder, which maps to WinMyDocuments (C:\users\xuser\Documents\) in Wine. Fix by recognising "steamclouddocuments" and "%steamclouddocuments%" in PathType.from() as WinMyDocuments. * fix: normalize '.' save path to empty string to prevent broken cloud keys Steam PICS manifests sometimes use `path: .` to mean "root of this path type, no subdirectory" (common in Unity games). When a Windows rootoverride also has a non-empty addpath, the dot was appended literally — producing paths like "Thunder Lotus Games/Spiritfarer/." and uploadPath = "." — which caused cloudPrefixToLocalPath to build a key like "%GameInstall%." that never matches the bare "%GameInstall%" prefix the cloud API returns, so downloaded files landed in the wrong directory. Fix by normalising "." to "" at parse time in KeyValueUtils, consistent with how UserFileInfo.prefix already treats cloudPath == ".". Affected games: Spiritfarer and CrossCode. * fix: recognize WinProgramData and SteamUserBaseStorage UFS path types, handle oslist in rootoverrides - Add WinProgramData PathType mapping to drive_c/ProgramData/ - Alias SteamUserBaseStorage to SteamUserData in PathType.from() - Check oslist field alongside os when filtering Windows rootoverrides * fix: bump CURRENT_UFS_PARSE_VERSION to 2 to force re-parse of cached UFS data Ensures existing cached SteamApp rows are re-parsed to pick up the path normalization and oslist rootoverride fixes from this branch. * fix: lowercase Root/ROOT_MOD aliases and add wrapped %root% form in PathType.from() * fix: add %steamuserbasestorage% as suggested by coderabbit
* fix(hud): measure fps from render frames * fix(hud): track fps against topmost app window
…lal#1169) * fix: show conflict dialog when cloud sync cache is missing, regardless of change number the old gate (localAppChangeNumber >= 0) skipped the conflict dialog for first-time offline players whose change number is -1. this meant local saves were silently overwritten by cloud on reconnect. remove the gate: if cache is absent and local files exist, always treat as conflict. * test: cloud sync decision matrix covering all cache/CN/cloud states 12 scenarios covering: cache present/absent, local changes/none, cloud ahead/same, preferred save location, first-time offline play. also fixes existing download test (cloud filenames, mock params, deprecated API). * fix: split cache-absent conflict into upgrade vs first-offline cases * test: revert modifications to existing tests, keep only new additions
* feat: streaming download+assembly for Epic/GOG to reduce disk usage replace two-phase (download all chunks → assemble all files) with a unified loop that assembles files front-to-back as their chunks land and deletes consumed chunks immediately. peak disk usage drops from ~2x install size to ~1x. - StreamingAssembly: shared pure logic for chunk ordering, last-file tracking, readiness checks, and safe deletion decisions - EpicDownloadManager: downloadAndAssembleEpicChunks replaces separate download+assembly phases for both base game and DLC - GOGDownloadManager: downloadAndAssembleChunks with secure link refresh, used by both main game and dependency downloads. removed dead downloadChunksSimple and assembleFiles. - 14 unit tests covering ordering, deduplication, shared chunks, cleanup safety, and full batch-loop simulations * fix: run final assembly pass for zero-chunk Epic files mirrors the GOG fix — when all files have zero chunks, the chunk loop never executes and assembly never runs without a trailing pass. * fix: allow all-zero-chunk Epic manifests to reach assembly * Resolved conflicts, sped up GOG, made resuming downloads for GOG work better, made downloading UI progress smoother * handle retries correctly for assembly for GOG * addressed coderabbit comments * More AI fixes --------- Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com>
…hdalal#1220) * Aligned epic downloads to GOG to make it faster from eg India * coderabbit comments, removed xserverscreen mistake changes --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com>
…karshdalal#1224) This reverts commit 2334981.
…#1143) * Added launch dependency tests * Added game fix registry tests * Added preinstall step tests * Some AI improvements + moved gamefixes tests to new types folder
* Added recommendations to game page + library, added toggle to hide recommendations, * Added review scores to recommended games * Added date to recommended app screen like the others * coderabit comments --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com>
…hdalal#1228) destructive db migration wipes file_change_lists cache, making every steam game trigger conflict on first launch post-update. check if local state is byte-identical to remote manifest (by filename + SHA) before declaring conflict; if so, rehydrate cache and report UpToDate silently. also populates real timestamps on the genuine-divergence path (was showing epoch). test: dbCleared_localMatchesRemote_rehydratesSilently_noConflict
* chore(): openApi specs for Gog, Epic & Amazon * chore(): Update the epic token to look more fake. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* added toggle to disable posthog tracking * Updated readme to include analytics info --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com>
…ng original behaviour + tests) (utkarshdalal#1052) * Reapply "Refactored default Proton downloads to launch deps" (utkarshdalal#1050) This reverts commit 1cd84b4. * Moved proton download to original location by moving launch deps call * Removed deletion since previously we didnt do that either. * Added test for new launch dep
## Summary
Stabilizes the "real Steam client" launch path (`steam.exe -applaunch`) so
games like Darkest Dungeon and 868-HACK boot cleanly without the multi-minute
"gray Play" reconcile loop, and adds a per-container toggle to disable the
Steam overlay. Also hardens cloud sync and GSE→userdata migration against
mode switches between emu and real-Steam launches.
## Changes
### Steamworks Common Redistributables (228980) manifest
- `SteamUtils.writeSteamworksCommonManifest` now writes only the depots whose
`_CommonRedist/<folder>/installscript.vdf` is actually present on disk
(typically 228985 vcredist 2013 + 228989 vcredist 2022) instead of the full
24 PICS-declared depots. The SKIP check compares against the same
present-depot baseline, so a correct manifest survives across launches.
- `SteamUtils.createAppManifest` emits a `SharedDepots` block in the child
game's acf for any depot whose parent app id is known (via
`DepotInfo.depotFromApp`). Declaring shared ownership up front stops Steam
from reparenting depots and cascading `Update Queued` onto the child on
every launch.
- Removed the now-unused `canonical228980SizeOnDisk`,
`canonical228980BytesToDownload`, and `canonical228980BytesToStage`
constants; size-on-disk is summed from the present depots and
bytes-to-download is `0`.
Why: writing all 24 depots made Steam prune 22 phantoms every boot (~3 min of
gray Play). Writing an empty manifest made Steam try to download ~52 MB,
hang `Suspended`, and permanently cascade `Update Queued`. The 2-depot +
`SharedDepots` shape is the only combination that survives Steam's reconcile.
### Disable Steam Overlay toggle
- New per-container `disableSteamOverlay` flag (`Container.java`,
`ContainerData.kt`, `PrefManager.kt`, `strings.xml`).
- Toggle surfaced in the container dialog's General tab, visible only when
"Launch Real Steam" is enabled (`GeneralTab.kt`).
- When enabled, `XServerScreen` exports `DISABLE_VK_LAYER_VALVE_steam_overlay_1=1`
and `SteamNoOverlayUIDrawing=1` into the Wine env so the overlay DLL never
injects.
### Real-Steam-mode aware sync & migration
- `SteamService.beginLaunchApp` / `syncUserFiles` / `closeApp` now take an
`isLaunchRealSteam` flag. In real-Steam mode the Goldberg achievement sync
and the GSE→Steam userdata migration are skipped so the real client owns
its own save state.
- `MainViewModel` tracks the last launch mode (`lastSteamMode` extra) and,
on real→emu transitions, cleans up artifacts from the previous mode to
avoid mixing GSE and real-client save layouts.
- `PluviaMain` threads the launch-mode flag through to `syncUserFiles`.
### Cloud conflict handling
- `SteamAutoCloud` refactors the byte-identical detection into a shared
lambda and adds a "cache lost but local == remote" branch that silently
rehydrates the cache instead of surfacing a spurious conflict prompt.
### Launch diagnostics
- `MainViewModel` adds `SteamFixDiagnostics` (last mapped window class,
game-window-mapped flag, last unmatched window class) and a helper
window-class filter (`STEAM_HELPER_WINDOW_CLASSES`) so stall reports
distinguish the real game window from Steam's own helper UI.
- `XServerScreen` integrates a 60 s stall watchdog and logs window-mapping
events for post-mortem analysis of gray-Play hangs.
### Supporting changes
- `SteamTokenLogin`, `PreInstallSteps`, `preInstallSteps/VcRedistStep`,
`ContainerUtils`, and `ImageFsInstaller` receive small wiring changes to
support the real-Steam-client launch path (vcredist gating, container
defaults, ImageFs layout).
## Test plan
- [ ] Launch Darkest Dungeon (262060) three times in a row — Play button
should auto-dismiss; no multi-minute gray Play.
- [ ] Launch 868-HACK — clean boot via real Steam client.
- [ ] Switch a container between emu and real-Steam mode; verify saves from
the prior mode are not blended into the new one.
- [ ] Toggle "Disable Steam Overlay" on a real-Steam container and confirm
the overlay DLL does not inject at runtime.
- [ ] With a stale cloud cache matching remote, confirm no conflict dialog
appears.
Three fixes to real-Steam-client launch path, all in SteamUtils.kt: 1. applySteamInstallScriptShim (new): writes HKLM\Software\Valve\Steam\Apps and \InstallScripts entries for appId, 228980, and all 24 canonical 228980 depots with Installed=1 / Run=1. This stops Steam from re-running bundled vc_redist.x86.exe / vc_redist.x64.exe / DXSETUP.exe on every launch, which was racing against the game's own MSVC loader and (on Unity titles) triggering UnityCrashHandler. Called from restoreSteamApi after createAppManifest. 2. verifyRestoredState: no longer requires a .orig sibling next to steam_api*.dll. Games with useLegacyDRM=false never go through replaceSteamApi and so never produce a .orig, which caused the old check to log "DLL marker desync" on every launch and needlessly re-copy pipe DLLs. Now compares the on-disk DLL hash against the pipe asset hash: match = still pipe (bad), mismatch = restored (good). 3. createAppManifest regularDepots-empty path: downgraded from W to I when the existing appmanifest already has a valid buildId + depots + UpdateResult=0. The PICS "regularDepots empty" result is a transient refresh flake and not actionable when the acf is otherwise healthy. Validated on Shiren (2178480) and Darkest Dungeon (262060): shim writes 300 reg entries, vcredist windows no longer appear on 2nd+ launches, DLL hash check logs "DLL marker + hash ok, skipping DLL copy" instead of desync warnings.
The real-Steam launch path is stable across DD / 868-HACK / Shotgun King /
Baba Is You — fold in the remaining structural fixes and strip the
investigation-era diagnostic scaffolding that was left behind.
SteamUtils.kt:
- Replace hardcoded canonical228980Depots table with a runtime PICS resolver
driven by the child acf's SharedDepots. Fixes permanent "gray Play" on
games whose shared-redist depot set diverges from DD's (was silently
writing InstalledDepots{} + BytesToDownload=52MB on those).
- Add SHA-256 verify-and-reheal to STEAM_DLL_REPLACED / STEAM_DLL_RESTORED
markers in replaceSteamApi/restoreSteamApi so a stale marker can no
longer lie about on-disk state (2nd-launch black-screen repro).
- Add validateAcfShape() self-check: after writing any child or 228980
manifest, log Timber.e on shapes known to cause gray Play (Update
Required bit set, BytesToDownload > 0, InstalledDepots empty when it
shouldn't be). Catches future regressions loudly instead of silently.
Diagnostic cleanup:
- Drop SteamFixDiagnostics object, STEAM_HELPER_WINDOW_CLASSES,
REAL_STEAM_STALL_WATCHDOG_MS, and all Timber.tag("SteamFix") log lines
across SteamUtils, SteamService, SteamAutoCloud, SteamTokenLogin,
MainViewModel, XServerScreen, ImageFsInstaller.
- Rewrite the comments that referenced the investigation's numbered
SteamFix list (utkarshdalal#8, utkarshdalal#9, utkarshdalal#11, utkarshdalal#16–utkarshdalal#24) so they stand on their own.
UX default:
- Default disableSteamOverlay to true in Container.java, ContainerData.kt,
and PrefManager.kt. Overlay-on is an opt-in now.
Housekeeping:
- .gitignore: exclude .claude/ session state.
- Drop tracked .claude/scheduled_tasks.lock.
Addresses three related issues seen when launching games in real-Steam mode. 1. Suppress Wine-hosted Steam client's cloud sync (Option B) The Wine-hosted Steam client was racing GameNative's SteamKit cloud sync on every launch/exit. Per-app gates now disable the Wine client's cloud path in userdata/<steamID>/config/localconfig.vdf (cloud_enabled=0, cce=0) for both the existing-file and new-file branches, with a setOrReplaceKey helper to avoid duplicates. 2. Graceful red-exit with 5s grace window The quick-menu EXIT_GAME action previously went straight to a SIGKILL of the Wine process tree, giving games no chance to flush saves. It now sends WM_CLOSE to the game exe (and to steam.exe when real-Steam mode is on), waits 5s, then proceeds with the existing exit path. A second tap within the grace window cancels the wait and force-quits. 3. Filter localhost pending-operations in real-Steam mode Steam's server reports the Wine-hosted client's self-registered session as machineName="localhost" with UploadPending, causing a spurious "Pending Upload" dialog before every real-Steam launch. beginLaunchApp now filters pendingRemoteOperations by machineName="localhost" when isLaunchRealSteam is true. Genuine entries from other devices still surface the dialog, and the kickPlayingSession path is unaffected. 4. Fix inverted uploadsRequired flag on exit sync signalAppExitSyncDone was passing uploadsRequired = (... == false), producing impossible states like "upload succeeded but wasn't required". Flipped to == true so Steam's server gets a truthful signal and stops holding stale pending markers. Also: ignore .claude/ session state directory.
SysVSharedMemory.delete(int) mutated the shmemories SparseArray without
synchronizing on it, while every other mutator (get, attach, detach,
deleteAll) held synchronized(shmemories). delete is invoked from the
SysV SHM connector thread (SysVSHMRequestHandler), and detach is invoked
from the X11 connector thread (MITSHMExtension), so the two can run
concurrently on the same array.
When delete ran mid-iteration in detach, SparseArray's internal DELETED
sentinel (a bare Object) could surface at valueAt(i), producing:
java.lang.ClassCastException: java.lang.Object cannot be cast to
com.winlator.sysvshm.SysVSharedMemory$SHMemory
at SysVSharedMemory.detach(SysVSharedMemory.java:117)
at SHMSegmentManager.detach(SHMSegmentManager.java:26)
at MITSHMExtension.detach(MITSHMExtension.java:74)
Fix: wrap the body of delete(int) in synchronized(shmemories). The lock
is reentrant, so deleteAll (which already holds it while calling delete
per-id) is unaffected.
Files:
app/src/main/java/com/winlator/sysvshm/SysVSharedMemory.java
Three audit findings from the Fix-Steam-Client branch review: - XServerScreen: cancel gracefulExitJob in DisposableEffect.onDispose. If the screen disposed during the 5s force-quit grace window, the coroutine leaked (only exitWatchJob was cancelled). - SteamUtils.createAppManifest: filter shared depots whose depotFromApp is 0 before writing the SharedDepots block. Writing `"<id>" "0"` told Steam the depot belonged to a nonexistent app 0, which could re-trigger the PICS reconcile / gray-Play cascade this branch was built to prevent. Unowned shared depots are now logged and omitted. - SteamUtils.applySteamInstallScriptShim: narrow the blanket `catch (Exception)` to IOException + SecurityException so programming errors (NPE, ISE) surface instead of being silently swallowed.
TideGear
added a commit
that referenced
this pull request
May 2, 2026
DRI3Extension.pixmapFromFd - Move drawable.setOnDestroyListener(onDestroyDrawableListener) so it only fires after createPixmap succeeds. Registering it earlier caused a double-unmap on the failure path: removeDrawable() invoked the listener (unmap #1), then the finally block unmapped again because handedOffToDrawable was still false. (Bug introduced by my earlier SHM-leak fix.) GeneralTab SdkCloudSaveSubdirField - Drop the wasBlank/meaningful/confirm-dialog gate from the typing path entirely. The original wasBlank-on-first-keystroke check fired the confirm dialog on the first character and disrupted typing; my length>1 patch made it never fire because by char 2 wasBlank was already false. Manual typing is intentional — commit each keystroke directly. The first-activation confirmation is reserved for auto-filled values from the Recommend / Detect buttons below, which the user didn't type. SteamService phantom dismiss - Filter probed pending ops by machineName before auto-dismissing. Only entries from our machineName (or "localhost") are treated as phantoms; any cross-device entry blocks the auto-dismiss path so legitimate cloud conflicts surface to the SYNC_CONFLICT dialog instead of getting silently wiped by ignorePendingOperations=true. SteamService beginLaunchApp offline gate - Move the isOffline/!isConnected early-return below the GSE→userdata migrate, inside the existing try block. Local prep should run even offline (one-shot file moves, not cloud-dependent). The cloud RPCs below the gate continue to short-circuit when offline. PluviaMain SDK-cloud-bridge prompt - Don't fire the prompt for non-game launches: bootToContainer (Open Container), useTemporaryOverride, or skipCloudSync flows. The post- prompt `relaunch` lambda doesn't carry those flags forward, so an Open-Container that triggered the prompt would silently turn into a game launch on dismiss. Easier to gate the prompt out than thread every flag through the relaunch. SteamUtils verifyReplacedState / verifyRestoredState - Treat a missing pipe-asset hash as a verification FAILURE rather than a silent skip. The previous `?: return@forEach` would skip the file and leave the function returning true — meaning a future build that drops a pipe DLL asset would silently let the marker check pass and suppress DLL repair. Fail closed instead. LudusaviRegistry.ensureLoaded - Wrap the fetch + disk-write + memoryCache-populate path in a kotlinx.coroutines Mutex with a double-check on entry. Without it, concurrent primeCache() + lookup() callers could both pass the null check and both fetch the 5 MB manifest. Now the second waiter sees the populated cache after the first finishes. Findings flagged but not changed: - SteamUtils SDK cloud mirror nested directories (third time): mirror is by design for Dead Cells flat saves; recursive expansion remains scope creep.
TideGear
added a commit
that referenced
this pull request
May 3, 2026
DRI3Extension.pixmapFromFd - Move drawable.setOnDestroyListener(onDestroyDrawableListener) so it only fires after createPixmap succeeds. Registering it earlier caused a double-unmap on the failure path: removeDrawable() invoked the listener (unmap #1), then the finally block unmapped again because handedOffToDrawable was still false. (Bug introduced by my earlier SHM-leak fix.) GeneralTab SdkCloudSaveSubdirField - Drop the wasBlank/meaningful/confirm-dialog gate from the typing path entirely. The original wasBlank-on-first-keystroke check fired the confirm dialog on the first character and disrupted typing; my length>1 patch made it never fire because by char 2 wasBlank was already false. Manual typing is intentional — commit each keystroke directly. The first-activation confirmation is reserved for auto-filled values from the Recommend / Detect buttons below, which the user didn't type. SteamService phantom dismiss - Filter probed pending ops by machineName before auto-dismissing. Only entries from our machineName (or "localhost") are treated as phantoms; any cross-device entry blocks the auto-dismiss path so legitimate cloud conflicts surface to the SYNC_CONFLICT dialog instead of getting silently wiped by ignorePendingOperations=true. SteamService beginLaunchApp offline gate - Move the isOffline/!isConnected early-return below the GSE→userdata migrate, inside the existing try block. Local prep should run even offline (one-shot file moves, not cloud-dependent). The cloud RPCs below the gate continue to short-circuit when offline. PluviaMain SDK-cloud-bridge prompt - Don't fire the prompt for non-game launches: bootToContainer (Open Container), useTemporaryOverride, or skipCloudSync flows. The post- prompt `relaunch` lambda doesn't carry those flags forward, so an Open-Container that triggered the prompt would silently turn into a game launch on dismiss. Easier to gate the prompt out than thread every flag through the relaunch. SteamUtils verifyReplacedState / verifyRestoredState - Treat a missing pipe-asset hash as a verification FAILURE rather than a silent skip. The previous `?: return@forEach` would skip the file and leave the function returning true — meaning a future build that drops a pipe DLL asset would silently let the marker check pass and suppress DLL repair. Fail closed instead. LudusaviRegistry.ensureLoaded - Wrap the fetch + disk-write + memoryCache-populate path in a kotlinx.coroutines Mutex with a double-check on entry. Without it, concurrent primeCache() + lookup() callers could both pass the null check and both fetch the 5 MB manifest. Now the second waiter sees the populated cache after the first finishes. Findings flagged but not changed: - SteamUtils SDK cloud mirror nested directories (third time): mirror is by design for Dead Cells flat saves; recursive expansion remains scope creep.
TideGear
added a commit
that referenced
this pull request
May 4, 2026
DRI3Extension.pixmapFromFd - Move drawable.setOnDestroyListener(onDestroyDrawableListener) so it only fires after createPixmap succeeds. Registering it earlier caused a double-unmap on the failure path: removeDrawable() invoked the listener (unmap #1), then the finally block unmapped again because handedOffToDrawable was still false. (Bug introduced by my earlier SHM-leak fix.) GeneralTab SdkCloudSaveSubdirField - Drop the wasBlank/meaningful/confirm-dialog gate from the typing path entirely. The original wasBlank-on-first-keystroke check fired the confirm dialog on the first character and disrupted typing; my length>1 patch made it never fire because by char 2 wasBlank was already false. Manual typing is intentional — commit each keystroke directly. The first-activation confirmation is reserved for auto-filled values from the Recommend / Detect buttons below, which the user didn't type. SteamService phantom dismiss - Filter probed pending ops by machineName before auto-dismissing. Only entries from our machineName (or "localhost") are treated as phantoms; any cross-device entry blocks the auto-dismiss path so legitimate cloud conflicts surface to the SYNC_CONFLICT dialog instead of getting silently wiped by ignorePendingOperations=true. SteamService beginLaunchApp offline gate - Move the isOffline/!isConnected early-return below the GSE→userdata migrate, inside the existing try block. Local prep should run even offline (one-shot file moves, not cloud-dependent). The cloud RPCs below the gate continue to short-circuit when offline. PluviaMain SDK-cloud-bridge prompt - Don't fire the prompt for non-game launches: bootToContainer (Open Container), useTemporaryOverride, or skipCloudSync flows. The post- prompt `relaunch` lambda doesn't carry those flags forward, so an Open-Container that triggered the prompt would silently turn into a game launch on dismiss. Easier to gate the prompt out than thread every flag through the relaunch. SteamUtils verifyReplacedState / verifyRestoredState - Treat a missing pipe-asset hash as a verification FAILURE rather than a silent skip. The previous `?: return@forEach` would skip the file and leave the function returning true — meaning a future build that drops a pipe DLL asset would silently let the marker check pass and suppress DLL repair. Fail closed instead. LudusaviRegistry.ensureLoaded - Wrap the fetch + disk-write + memoryCache-populate path in a kotlinx.coroutines Mutex with a double-check on entry. Without it, concurrent primeCache() + lookup() callers could both pass the null check and both fetch the 5 MB manifest. Now the second waiter sees the populated cache after the first finishes. Findings flagged but not changed: - SteamUtils SDK cloud mirror nested directories (third time): mirror is by design for Dead Cells flat saves; recursive expansion remains scope creep.
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.
Description
Recording
Checklist
#code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.CONTRIBUTING.md.