Skip to content

Fix/steam offline - #738

Merged
maxjivi05 merged 4 commits into
WinNative-Emu:mainfrom
maxjivi05:fix/steam-offline
Sep 11, 2026
Merged

Fix/steam offline#738
maxjivi05 merged 4 commits into
WinNative-Emu:mainfrom
maxjivi05:fix/steam-offline

Conversation

@maxjivi05

Copy link
Copy Markdown
Contributor

No description provided.

The Offline Steam options shipped in WinNative-Emu#732 never produced a signed-in
session: the in-prefix agent asked steamclient to log on offline with an
empty cached SteamID, and the prefix state that offline sign-in depends on
was deleted before every launch.

Agent (wn-steam-launcher):

- Call IClientUser slot 50 SetAccountNameForCachedCredentialLogin before
  slot 215 LogOnOffline. It is the only non-network call that resolves the
  cached SteamID CUser::LogOnOffline requires; without it the call returned
  EResult 19 InvalidSteamID every time.
- Pass true to LogOnOffline. The bool is written verbatim into the
  engine-wide offline-mode flag at CSteamEngine+0x180A, so the previous
  false cancelled the offline mode it had just entered.
- Seed config/config.vdf with Accounts\<name>\SteamID, repairing a blank
  file and injecting the entry into an existing one rather than only
  writing when the file is absent.
- Report ValidateOfflineLogonTicket, CanLogonOffline and GetLogonState, and
  on the online path log whether the licence cache, the Valve-signed
  ParentalSettings pair and the offline ticket are present.
- Skip the appinfo refresh, the ownership sync and the encrypted-app-ticket
  prewarm when there is no CM to answer them, and re-check the live logon
  state before giving up on MissingConfig.
- Bound the sign-in wait when the device reports no validated network, and
  break out as soon as a connect failure arrives, instead of burning 60s.
- Arm the clean shutdown even when the sign-in did not complete, so the
  next launch is not blocked by a stale running-app registration.

Prefix state:

- ensureRealSteamDir now restores config/**, root ssfn* files,
  userdata/<account>/config/** and appcache/appinfo.vdf before the client
  starts. It used to recreate the Steam directory empty, destroying the
  licence cache, the parental-settings blob and the offline logon ticket
  that only a successful online sign-in can mint.

App:

- Publish WN_STEAM_NET_DOWN/WN_STEAM_OFFLINE from a live connectivity
  check, and stop the unbounded Steam session bring-ups that stalled an
  offline launch.
- Stop mutating the shared KeyValue.INVALID sentinel when the restored
  localconfig.vdf has no entry for the app, which silently dropped
  LaunchOptions and the AutoCloud disable.
- Keep the shortcut-level Steam Offline Mode toggle when the container
  changes, and honour the container default when reading it.

Offline sign-in still requires one prior successful online sign-in in that
container: the parental-settings blob and the offline logon ticket are both
signed by Valve and cannot be synthesized locally.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@maxjivi05
maxjivi05 merged commit 98aae56 into WinNative-Emu:main Sep 11, 2026
4 checks passed
@maxjivi05
maxjivi05 deleted the fix/steam-offline branch September 11, 2026 22:10
maxjivi05 added a commit to maxjivi05/WinNative that referenced this pull request Sep 12, 2026
The SessionKeepAliveService/NotificationHelper/LogManager refactor (WinNative-Emu#609)
dropped `import com.winlator.cmod.app.service.NetworkMonitor` from
SteamService.kt while the `NetworkMonitor.isOffline(this)` guard that WinNative-Emu#738
added to getEncryptedAppTicket stayed. Kotlin compilation of every flavor
fails with "Unresolved reference 'NetworkMonitor'", so main and every open
PR built against it are red.
maxjivi05 added a commit that referenced this pull request Sep 12, 2026
* Fix duplicate library entries and add a per-game store switch

A game owned on two stores showed up twice once the stores shared one
download folder. Every store writes the same .download_complete marker
into the install directory and resolves that directory from the game's
name, so after installing from one store the others found a completed
install of their own and claimed it — Steam's startup metadata repair
made this reappear on every launch.

Installs now record which store owns them. Each store's disk detection
skips directories owned by another store, install-directory deletes
refuse to touch a foreign install, and the library collapses rows that
resolve to the same directory, preferring the recorded owner, then a
launcher shortcut's source, then a fixed order.

The source tag at the top right of a game lists every store the game is
owned on when there is more than one, tagged with the current store.
Choosing another store moves the install record over to it, so the tag
label, check for update, verify, workshop and the branch list all follow
the new store. Stores that already have their own separate install of
the game are not offered, since they have their own library row.

* Put the store list behind a Change Store entry

The stores sat inline at the top of the source tag menu, which pushed
Verify Files and Check for Update down and mixed a choice in with the
actions. The menu now offers a single Change Store entry, and picking it
opens the list of stores the game is owned on with the current one
ticked.

* Restore the NetworkMonitor import in SteamService

The SessionKeepAliveService/NotificationHelper/LogManager refactor (#609)
dropped `import com.winlator.cmod.app.service.NetworkMonitor` from
SteamService.kt while the `NetworkMonitor.isOffline(this)` guard that #738
added to getEncryptedAppTicket stayed. Kotlin compilation of every flavor
fails with "Unresolved reference 'NetworkMonitor'", so main and every open
PR built against it are red.

* Always offer Change Store, including for custom games

The switcher only appeared when a game resolved to two or more stores, so
a game you own on one store had no entry at all and a manually added custom
game could never be adopted by the store that actually owns it.

- computeLibraryStoreLinks returns the store options it resolved instead of
  discarding lists of one, and seeds an installed row with its own store so
  the current store is always listed even when the store library has no
  matching entry.
- Custom rows already match owned titles, so a custom game now offers every
  store whose library carries that title; picking one runs the existing
  transfer, which claims the folder, writes the download-complete marker and
  marks the game installed at that path for the target store.
- A custom row whose folder is stamped for a store that also has an install
  there is hidden, so adopting a custom game replaces its row instead of
  leaving a duplicate beside the store row.
- The source tag is always tappable and always carries Change Store; with no
  matching library the picker says so rather than opening empty.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant