Skip to content

[WIP] Fix onlinefix achievements and SteamNetworkingSockets#54

Open
JanitorialMess wants to merge 4 commits into
OpenSteam001:mainfrom
JanitorialMess:fix/onlinefix-achievements
Open

[WIP] Fix onlinefix achievements and SteamNetworkingSockets#54
JanitorialMess wants to merge 4 commits into
OpenSteam001:mainfrom
JanitorialMess:fix/onlinefix-achievements

Conversation

@JanitorialMess
Copy link
Copy Markdown
Contributor

@JanitorialMess JanitorialMess commented May 25, 2026

This PR is a Work in Progress and attempts to fix achievements for -onlinefix apps. I am also whitelisting build 1779486452 signatures so this change is testable while you decide on the best approach going forward.

-onlinefix launches the game through app 480, but achievements belong to the configured game app. Steamclient resolves the app used for user stats and achievement icon precaching from the current game pipe, so achievement calls were being processed against app 480.

Hooks_IPC now scopes calls forwarded for IClientUserStats, and Hooks_Misc returns the configured game app from GetAppIDForCurrentPipe only within that scope. Other Steam traffic still uses app 480, so the existing multiplayer path is unchanged.

I noticed though that games relying on SteamNetworkingSockets do not work with the -onlinefix and I am testing a fix for that.

Please do not merge this yet until we get more testing done.

Testing

  • Achievement Clicker unlocks achievements under -onlinefix.
  • Stick Fight receives its ordinary stats-initialization callback and then handles achievements.
  • YAPYAP and RV There Yet? connect through SteamNetworkingSockets.
  • RV There Yet? can still read and update its game achievements and stats while its public identity remains 480.

Related issues

Known issues

  • Game language specification through Steam Properties not taking effect. Defaults to "English" (see comment below)

@Parzival0025
Copy link
Copy Markdown

I tried a solution for this, but yours is definitely better. Regarding playtime, we could create another pipe with the Real AppID idling after (Spacewar - 480) is launched, similar to how Gibbed’s SAM or SamRewritten handles it when we want to manage achievements.

@JanitorialMess
Copy link
Copy Markdown
Contributor Author

JanitorialMess commented May 25, 2026

I tried a solution for this, but yours is definitely better. Regarding playtime, we could create another pipe with the Real AppID idling after (Spacewar - 480) is launched, similar to how Gibbed’s SAM or SamRewritten handles it when we want to manage achievements.

Before I look into playtime, I think this needs to be tested a lot more. My fix is insufficient and does not work for some games which may emit requests for DeprecatedPublic_RequestCurrentStats.

I am not familiar with either project enough but I will definitely take a look!

@JanitorialMess JanitorialMess changed the title Fix OnlineFix achievements and whitelist build 1779486452 [WIP] Fix OnlineFix achievements and whitelist build 1779486452 May 25, 2026
@JanitorialMess JanitorialMess changed the title [WIP] Fix OnlineFix achievements and whitelist build 1779486452 [WIP] Fix onlinefix achievements and SteamNetworkingSockets May 25, 2026
@JanitorialMess
Copy link
Copy Markdown
Contributor Author

JanitorialMess commented May 25, 2026

This has grown to cover a bit more than I initially intended and the code isn't the best it can be yet.

Here is a breakdown of what is happening at different layers and why user stats are so tricky. Different games follow different paths and trigger different calls.

Identity handling changes

  • Achievement/stat operations - IClientUserStats
    OST processed an -onlinefix game's user-stats work from its Spacewar launch context. I scoped GetAppIDForCurrentPipe() during IClientUserStats processing so reads, writes, and achievement operations execute for the original game AppID. This is the change that fixes the original achievement issue.

  • Public/network identity - IClientUtils::GetAppID
    OST also rewrote the completed GetAppID response from 480 back to the original game AppID. That was not required for the achievement fix: achievements passed while it was still present. It does conflict with SteamNetworkingSockets games because the local game identity becomes the original AppID while Steam authorizes the OnlineFix network session for 480. In YAPYAP (3834090), the failure was:

    IClientUtils::GetAppID response rewritten: 480 -> 3834090
      -> SteamNetworkingSockets socket-local AppID = 3834090
      -> GetCertAsync obtains certificate authorized for AppID 480
      -> CheckCertAppID(3834090, certificate[480])
      -> "Cert is not authorized for appid 3834090, only 480"
    

    I removed that response rewrite:

    IClientUtils::GetAppID response retained: 480
      -> SteamNetworkingSockets socket-local AppID = 480
      -> CheckCertAppID(480, certificate[480]) passes
    

    YAPYAP and RV There Yet? can connect through SteamNetworkingSockets with this change.

  • Ordinary stats completion - UserStatsReceived_t /
    DispatchCallbackByAppId

    Removing the public GetAppID rewrite creates a split: the game callback pipe is associated with 480, but IClientUserStats now produces a successful result for the original game AppID. For Stick Fight, that is:

    IClientUserStats operation (AppID 674940)
      -> UserStatsReceived_t(m_nGameID = 674940)
      -> DispatchCallbackByAppId(674940, UserStatsReceived_t)
      -> no delivery to Stick Fight's game pipe (AppID 480)
    

    The added bridge is:

    DispatchCallbackByAppId(674940, UserStatsReceived_t)
      -> keep the normal AppID 674940 delivery
      -> dispatch a copy through AppID 480
      -> SendCallbackToPipe(480 pipe): m_nGameID 674940 -> 480
      -> Stick Fight receives stats initialization
    
  • Asynchronous stats completion - IClientUtils::GetAPICallResult
    RV There Yet? also consumes asynchronous user-stats results. Those result payloads carry an AppID, so I rewrite the result to 480 on RV There Yet?'s game pipe while its actual stats work still runs against the original game AppID.

    RV RequestUserStats(original game AppID)
      -> GetAPICallResult(UserStatsReceived_t(original game AppID))
      -> rewrite result m_nGameID to 480 on the RV game pipe
    

@Parzival0025
Copy link
Copy Markdown

Hello again, I did some testing with your PR and identified two issues.

The first one is that the language for every game keeps defaulting to English, which is probably related to the following issue.

The second problem is that save files from some games are being stored under AppID 480 (including cloud saves — I had to use a third-party tool to remove them).

Captura de tela 2026-05-25 063616

Save from Dying Light in Spacewar:
Captura de tela 2026-05-25 063916

@JanitorialMess
Copy link
Copy Markdown
Contributor Author

The first one is that the language for every game keeps defaulting to English, which is probably related to the following issue.

Did this happen before or after the last commits I made?

The second problem is that save files from some games are being stored under AppID 480 (including cloud saves — I had to use a third-party tool to remove them).

Is this happening only on unlocked games?

@Parzival0025
Copy link
Copy Markdown

Parzival0025 commented May 25, 2026

Did this happen before or after the last commits I made?

Sorry, but I only tested with the most recent commits. To make sure, I even compiled it together with the latest commit, and the same issues still occur.

Is this happening only on unlocked games?

Dying Light — Saves are stored under AppID 480 and the language stays only in English.
Dying Light: The Beast — Saves are stored under AppID 480 and the language stays only in English.
Resident Evil 5 and 6 (LEGIT) — Both save correctly under their respective AppIDs and cloud storage, and the language is also correct.

Yes, apparently this only happens with unlocked games.

If necessary, I can run more tests with other games.

EDIT: I also forgot to mention: achievements are not unlocking either in unlocked games. I’m not sure if that’s because I’m using Steamless to bypass Steam DRM — could you confirm that for me, please?

@OpenSteam001
Copy link
Copy Markdown
Owner

Thanks for the PR and for the detailed investigation. I appreciate the amount of testing across different games here.

This makes me reconsider the current direction a bit.

For lobby matchmaking support, I originally saw two possible approaches:

  1. Handle it at the NetPacket layer.
  2. Change the AppID registered in Steam's pipe to 480 when launching the game.

I chose the second approach because the NetPacket route involves many MMS messages, with more than twenty related message types:
https://github.com/OpenSteam001/steam-monitor/blob/protobuf/steamclient/steammessages_clientserver_mms.proto

The second approach was simpler initially, but its side effects now look more complicated than expected. Besides achievements, it may also affect Workshop, cloud saves, and other Steam features. Because of that, I am not fully sure whether the second approach is still better than handling this at the NetPacket layer.

Also, pattern rules are now fetched from steam-monitor. If any new function needs to be resolved or hooked, just provide the function name and the RVA from the latest stable Steam version, and I can update the remote rules.

@JanitorialMess
Copy link
Copy Markdown
Contributor Author

JanitorialMess commented May 25, 2026

Dying Light — Saves are stored under AppID 480 and the language stays only in English.
Dying Light: The Beast — Saves are stored under AppID 480 and the language stays only in English.
Resident Evil 5 and 6 (LEGIT) — Both save correctly under their respective AppIDs and cloud storage, and the language is also correct.

Yes, apparently this only happens with unlocked games.

If necessary, I can run more tests with other games.

I appreciate the testing and feedback; I was able to reproduce the language issue on Megabonk (a much smaller game). I will investigate.

For cloud saves, I was not able to reproduce the issue yet. I get the regular cloud save error in steam and no new entries for Spacewar. My DispatchCallbackByAppId hook may be overreaching.

The second approach was simpler initially, but its side effects now look more complicated than expected. Besides achievements, it may also affect Workshop, cloud saves, and other Steam features. Because of that, I am not fully sure whether the second approach is still better than handling this at the NetPacket layer.

I haven't looked into lobbies much yet. I just saw that SteamNetworkingSockets only worked when the GetAppId wasn't rewritten globally and it was blocking me from testing achievements properly so I removed it in favor of what I thought were more targeted fixes.

From the little testing I did, Steam Workshop was working just fine with -onlinefix. (I have not tested with this PR yet, but it was working with the overlay fix that got merged).

Also, pattern rules are now fetched from steam-monitor. If any new function needs to be resolved or hooked, just provide the function name and the RVA from the latest stable Steam version, and I can update the remote rules.

Great work! I will try to resolve this PR's issues and conflicts whenever I have some more time available.

@asg2712
Copy link
Copy Markdown

asg2712 commented May 25, 2026

can you guys analyze the online-fix dll and compare it, even if this is based of unsteam, the unsteam one has its own game save folder which does not clash with corrupt save error with this onlinefix. can you look intot the code of the unsteam and online-fix, i think that would help you move forward tremendously

and i saw you throw shade by saying not put lua at st-plugin, hilarious.

@JanitorialMess
Copy link
Copy Markdown
Contributor Author

can you guys analyze the online-fix dll and compare it, even if this is based of unsteam, the unsteam one has its own game save folder which does not clash with corrupt save error with this onlinefix. can you look intot the code of the unsteam and online-fix, i think that would help you move forward tremendously

This approach operates at a higher level than Unsteam or CreamAPI. It does not touch the Steamworks API (steam_api.dll) directly which is what all of the other solutions do. We do not have the same level of control to only patch specific APIs the games may need, and I am personally not interested in hooking game at runtime because that will create issues with DRMs, anti-cheats, etc.

and i saw you throw shade by saying not put lua at st-plugin, hilarious.

Also, please refrain from making unrelated inappropriate remarks. I am not the original creator of the project and this PR has nothing to do with LUA folder configuration.

The instructions merely say to place lua files in a different directory. This is most likely to avoid any incompatibilities with other tools or drifts in the design of the LUA files. It also makes it easier to revert back to SteamTools if you need to. All you have to do is copy over files or change the TOML configuration to make it work.

@asg2712
Copy link
Copy Markdown

asg2712 commented May 27, 2026

which drms? most of all online-fix on the original steamapi too. and anti cheats are only in online only games. maybe make 2 versions. online multiplayer is a big thing to make your mark. please consider some form of workaround, greenluma and other steamtools already exist. no one has done the multiplayer side of things

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.

[BUG] onlinefix empty lobbies , invite crashes the game { release a debug version to get data } [BUG] Steam is not showing achievements

4 participants