protonscr

Ninja Reflex: Steamworks Edition

protonopen appid 13000Game compatibility - Unofficial
ValveSoftware/Proton#8979 · opened 2025-08-16 by Fighter19 · updated 2025-08-20 · 3 comments · github · game page · search this game
FFighter19 2025-08-16 github

Compatibility Report

  • Name of the game with compatibility issues: Ninja Reflex: Steamworks Edition
  • Steam AppID of the game: 13000

System Information

I confirm:

  • [x] that I haven't found an existing compatibility report for this game.
  • [x] that I have checked whether there are updates for my system available.

steam-13000.log

Symptoms

Starting up the game instantly crashes

Reproduction

Press play

Analysis

The game uses a custom steam_api.dll using probably an obsolete version of ISteamUserStats.
(strings suggest STEAMUSERSTATS_INTERFACE_VERSION002).

The calls for example to presumably GetAchievement (vtable+0x24) always pass app id and zero as the first two parameters.

Publically available documentation implies that passing these values is unexpected.

Code within the provided function by SteamClient crashes the game, whilst dereferencing the app id, as if it was a pointer.

My gut feeling is, that the wrong steam_api.dll gets loaded.

System info should be unnecessary, but is provided as pro forma.

FFighter19 2025-08-16 github

Adding a steam_api override to "Native, Builtin" has been tested and also did nothing.

EDIT:
See this file for reference as to what the game's using:

https://github.com/ValveSoftware/Proton/blob/1e52f95633c5145aaf54bc27476021d9e1baade2/lsteamclient/steamworks_sdk_099y/isteamuserstats.h

The wrong version somehow gets loaded.

FFighter19 2025-08-20 github

The problem can be reproduced with the native steamclient.
For this it's required to take the 100 version of the SDK,
and replace isteamuserstats.h with the one from 99y.

Example invocation:

g++ -g -I/home/patrick/Git/proton-build/src-lsteamclient/steamworks_sdk_special -m32 -Wall steamclient_test.cpp /home/patrick/steamclient.so

Log with WINEDEBUG=steamclient

#include <stdio.h>
#include "isteamclient.h"
#include "isteamuserstats.h"

extern "C"
{
    void *CreateInterface(const char *name, int *return_code);
}

int main(int argc, char *argv[])
{
    int return_code = 0;
    ISteamClient *pSteamClient = (ISteamClient *)CreateInterface("SteamClient007", &return_code);
    HSteamPipe hSteamPipe = pSteamClient->CreateSteamPipe();
    HSteamUser hSteamUser = pSteamClient->ConnectToGlobalUser(hSteamPipe);
    if (pSteamClient == nullptr)
    {
        return 1;
    }
    printf("pSteamClient: %p\n", pSteamClient);
    ISteamUserStats *pUserStats = (ISteamUserStats *)pSteamClient->GetISteamUserStats(hSteamUser, hSteamPipe, "STEAMUSERSTATS_INTERFACE_VERSION002");
    if (pUserStats == nullptr)
    {
        printf("Failed to receive user stats\n");
        return 1;
    }
    printf("pUserStats: %p\n", pUserStats);
    CGameID id(13000);
    bool bSuccess = pUserStats->RequestCurrentStats(id);
    if (!bSuccess)
    {
        printf("Failed to receive current stats\n");
        return 1;
    }

    printf("Everything OK\n");
    return 0;
}

The resulting binary crashes at the same spot.

FFighter19 2025-08-20 github

Passing a reference (pointer) to CGameID instead of CGameID appears to work. There seems to be an issue with CGameID being dereferenced in the code by steamclient.so.

Probably needs to be fixed in Steam(?)