diff --git a/dll/client_known_interfaces.cpp b/dll/client_known_interfaces.cpp new file mode 100644 index 00000000..6fa05e11 --- /dev/null +++ b/dll/client_known_interfaces.cpp @@ -0,0 +1,228 @@ +#include "dll/client_known_interfaces.h" + +/* +the client function Steam_IsKnownInterface() accesses a structure which has this layout: + +typedef struct struct_known_interfaces { + void *unknown_function_ptr; + const char *name; // ex: "STEAMAPPLIST_INTERFACE_VERSION001" + const char *family; // ex: "AppList" + struct_known_interfaces *previous_node; +}; + +this is a dump of the `name` field when running this function from a debugger +*/ + +extern const std::unordered_set client_known_interfaces = { + "SteamAppDisableUpdate001", + "STEAMAPPLIST_INTERFACE_VERSION001", + "SteamApps001", + "STEAMAPPS_INTERFACE_VERSION001", + "STEAMAPPS_INTERFACE_VERSION002", + "STEAMAPPS_INTERFACE_VERSION003", + "STEAMAPPS_INTERFACE_VERSION004", + "STEAMAPPS_INTERFACE_VERSION005", + "STEAMAPPS_INTERFACE_VERSION006", + "STEAMAPPS_INTERFACE_VERSION007", + "STEAMAPPS_INTERFACE_VERSION008", + "STEAMAPPTICKET_INTERFACE_VERSION001", + "SteamBilling002", + "STEAMCHAT_INTERFACE_VERSION003", + "SteamController003", + "SteamController004", + "SteamController005", + "SteamController006", + "SteamController007", + "SteamController008", + "STEAMCONTROLLER_INTERFACE_VERSION", + "SteamFriends001", + "SteamFriends002", + "SteamFriends003", + "SteamFriends004", + "SteamFriends005", + "SteamFriends006", + "SteamFriends007", + "SteamFriends008", + "SteamFriends009", + "SteamFriends010", + "SteamFriends011", + "SteamFriends012", + "SteamFriends013", + "SteamFriends014", + "SteamFriends015", + "SteamFriends016", + "SteamFriends017", + "SteamGameCoordinator001", + "SteamGameServer002", + "SteamGameServer003", + "SteamGameServer004", + "SteamGameServer005", + "SteamGameServer006", + "SteamGameServer007", + "SteamGameServer008", + "SteamGameServer009", + "SteamGameServer010", + "SteamGameServer011", + "SteamGameServer012", + "SteamGameServer013", + "SteamGameServer014", + "SteamGameServer015", + "SteamGameServerStats001", + "SteamGameStats001", + "STEAMHTMLSURFACE_INTERFACE_VERSION_001", + "STEAMHTMLSURFACE_INTERFACE_VERSION_002", + "STEAMHTMLSURFACE_INTERFACE_VERSION_003", + "STEAMHTMLSURFACE_INTERFACE_VERSION_004", + "STEAMHTMLSURFACE_INTERFACE_VERSION_005", + "STEAMHTTP_INTERFACE_VERSION001", + "STEAMHTTP_INTERFACE_VERSION002", + "STEAMHTTP_INTERFACE_VERSION003", + "SteamInput001", + "SteamInput002", + "SteamInput003", + "SteamInput004", + "SteamInput005", + "SteamInput006", + "STEAMINVENTORY_INTERFACE_V001", + "STEAMINVENTORY_INTERFACE_V002", + "STEAMINVENTORY_INTERFACE_V003", + "SteamMasterServerUpdater001", + "SteamMatchGameSearch001", + "SteamMatchMaking001", + "SteamMatchMaking002", + "SteamMatchMaking003", + "SteamMatchMaking004", + "SteamMatchMaking005", + "SteamMatchMaking006", + "SteamMatchMaking007", + "SteamMatchMaking008", + "SteamMatchMaking009", + "SteamMatchMakingServers001", + "SteamMatchMakingServers002", + "STEAMMUSIC_INTERFACE_VERSION001", + "STEAMMUSICREMOTE_INTERFACE_VERSION001", + "SteamNetworking001", + "SteamNetworking002", + "SteamNetworking003", + "SteamNetworking004", + "SteamNetworking005", + "SteamNetworking006", + "SteamNetworkingMessages002", + "SteamNetworkingSockets002", + "SteamNetworkingSockets003", + "SteamNetworkingSockets004", + "SteamNetworkingSockets005", + "SteamNetworkingSockets006", + "SteamNetworkingSockets008", + "SteamNetworkingSockets009", + "SteamNetworkingSockets010", + "SteamNetworkingSockets011", + "SteamNetworkingSockets012", + "SteamNetworkingSocketsSerialized001", + "SteamNetworkingSocketsSerialized002", + "SteamNetworkingSocketsSerialized003", + "SteamNetworkingSocketsSerialized004", + "SteamNetworkingSocketsSerialized005", + "SteamNetworkingUtils001", + "SteamNetworkingUtils002", + "SteamNetworkingUtils003", + "SteamNetworkingUtils004", + "STEAMPARENTALSETTINGS_INTERFACE_VERSION001", + "SteamParties001", + "SteamParties002", + "STEAMREMOTEPLAY_INTERFACE_VERSION001", + "STEAMREMOTEPLAY_INTERFACE_VERSION002", + "STEAMREMOTESTORAGE_INTERFACE_VERSION001", + "STEAMREMOTESTORAGE_INTERFACE_VERSION002", + "STEAMREMOTESTORAGE_INTERFACE_VERSION003", + "STEAMREMOTESTORAGE_INTERFACE_VERSION004", + "STEAMREMOTESTORAGE_INTERFACE_VERSION005", + "STEAMREMOTESTORAGE_INTERFACE_VERSION006", + "STEAMREMOTESTORAGE_INTERFACE_VERSION007", + "STEAMREMOTESTORAGE_INTERFACE_VERSION008", + "STEAMREMOTESTORAGE_INTERFACE_VERSION009", + "STEAMREMOTESTORAGE_INTERFACE_VERSION010", + "STEAMREMOTESTORAGE_INTERFACE_VERSION011", + "STEAMREMOTESTORAGE_INTERFACE_VERSION012", + "STEAMREMOTESTORAGE_INTERFACE_VERSION013", + "STEAMREMOTESTORAGE_INTERFACE_VERSION014", + "STEAMREMOTESTORAGE_INTERFACE_VERSION015", + "STEAMREMOTESTORAGE_INTERFACE_VERSION016", + "STEAMSCREENSHOTS_INTERFACE_VERSION001", + "STEAMSCREENSHOTS_INTERFACE_VERSION002", + "STEAMSCREENSHOTS_INTERFACE_VERSION003", + "SteamStreamLauncher001", + "STEAMTIMELINE_INTERFACE_V001", + "STEAMTV_INTERFACE_V001", + "STEAMTV_INTERFACE_V002", + "STEAMUGC_INTERFACE_VERSION001", + "STEAMUGC_INTERFACE_VERSION002", + "STEAMUGC_INTERFACE_VERSION003", + "STEAMUGC_INTERFACE_VERSION004", + "STEAMUGC_INTERFACE_VERSION005", + "STEAMUGC_INTERFACE_VERSION006", + "STEAMUGC_INTERFACE_VERSION007", + "STEAMUGC_INTERFACE_VERSION008", + "STEAMUGC_INTERFACE_VERSION009", + "STEAMUGC_INTERFACE_VERSION010", + "STEAMUGC_INTERFACE_VERSION011", + "STEAMUGC_INTERFACE_VERSION012", + "STEAMUGC_INTERFACE_VERSION013", + "STEAMUGC_INTERFACE_VERSION014", + "STEAMUGC_INTERFACE_VERSION015", + "STEAMUGC_INTERFACE_VERSION016", + "STEAMUGC_INTERFACE_VERSION017", + "STEAMUGC_INTERFACE_VERSION018", + "STEAMUGC_INTERFACE_VERSION019", + "STEAMUGC_INTERFACE_VERSION020", + "STEAMUNIFIEDMESSAGES_INTERFACE_VERSION001", + "SteamUser004", + "SteamUser005", + "SteamUser006", + "SteamUser007", + "SteamUser008", + "SteamUser009", + "SteamUser010", + "SteamUser011", + "SteamUser012", + "SteamUser013", + "SteamUser014", + "SteamUser015", + "SteamUser016", + "SteamUser017", + "SteamUser018", + "SteamUser019", + "SteamUser020", + "SteamUser021", + "SteamUser022", + "SteamUser023", + "STEAMUSERSTATS_INTERFACE_VERSION001", + "STEAMUSERSTATS_INTERFACE_VERSION002", + "STEAMUSERSTATS_INTERFACE_VERSION003", + "STEAMUSERSTATS_INTERFACE_VERSION004", + "STEAMUSERSTATS_INTERFACE_VERSION005", + "STEAMUSERSTATS_INTERFACE_VERSION006", + "STEAMUSERSTATS_INTERFACE_VERSION007", + "STEAMUSERSTATS_INTERFACE_VERSION008", + "STEAMUSERSTATS_INTERFACE_VERSION009", + "STEAMUSERSTATS_INTERFACE_VERSION010", + "STEAMUSERSTATS_INTERFACE_VERSION011", + "STEAMUSERSTATS_INTERFACE_VERSION012", + "SteamUtils001", + "SteamUtils002", + "SteamUtils003", + "SteamUtils004", + "SteamUtils005", + "SteamUtils006", + "SteamUtils007", + "SteamUtils008", + "SteamUtils009", + "SteamUtils010", + "STEAMVIDEO_INTERFACE_V001", + "STEAMVIDEO_INTERFACE_V002", + "STEAMVIDEO_INTERFACE_V003", + "STEAMVIDEO_INTERFACE_V004", + "STEAMVIDEO_INTERFACE_V005", + "STEAMVIDEO_INTERFACE_V006", + "STEAMVIDEO_INTERFACE_V007", +}; diff --git a/dll/dll.cpp b/dll/dll.cpp index 18c210ec..424716e3 100644 --- a/dll/dll.cpp +++ b/dll/dll.cpp @@ -18,6 +18,7 @@ #define STEAM_API_FUNCTIONS_IMPL #include "dll/dll.h" #include "dll/settings_parser.h" +#include "dll/client_known_interfaces.h" static char old_client[128] = STEAMCLIENT_INTERFACE_VERSION; //"SteamClient017"; @@ -1320,7 +1321,7 @@ STEAMCLIENT_API steam_bool Steam_BGetCallback( HSteamPipe hSteamPipe, CallbackMs STEAMCLIENT_API void Steam_FreeLastCallback( HSteamPipe hSteamPipe ) { - PRINT_DEBUG("Steam_FreeLastCallback %i", hSteamPipe); + PRINT_DEBUG("%i", hSteamPipe); SteamAPI_ManualDispatch_FreeLastCallback( hSteamPipe ); } @@ -1330,7 +1331,7 @@ STEAMCLIENT_API steam_bool Steam_GetAPICallResult( HSteamPipe hSteamPipe, SteamA return SteamAPI_ManualDispatch_GetAPICallResult(hSteamPipe, hSteamAPICall, pCallback, cubCallback, iCallbackExpected, pbFailed); } -STEAMCLIENT_API void *CreateInterface( const char *pName, int *pReturnCode ) +STEAMCLIENT_API void* CreateInterface( const char *pName, int *pReturnCode ) { PRINT_DEBUG("%s %p", pName, pReturnCode); auto ptr = create_client_interface(pName); @@ -1347,6 +1348,11 @@ STEAMCLIENT_API void Breakpad_SteamMiniDumpInit( uint32 a, const char *b, const PRINT_DEBUG_TODO(); } +STEAMCLIENT_API void Breakpad_SteamSendMiniDump( void *a, uint32 b ) +{ + PRINT_DEBUG_TODO(); +} + STEAMCLIENT_API void Breakpad_SteamSetAppID( uint32 unAppID ) { PRINT_DEBUG_TODO(); @@ -1369,19 +1375,19 @@ STEAMCLIENT_API void Breakpad_SteamWriteMiniDumpUsingExceptionInfoWithBuildId( i PRINT_DEBUG(" app is writing a crash dump! [XXXXXXXXXXXXXXXXXXXXXXXXXXX]"); } -STEAMCLIENT_API bool Steam_BConnected( HSteamUser hUser, HSteamPipe hSteamPipe ) +STEAMCLIENT_API steam_bool Steam_BConnected( HSteamUser hUser, HSteamPipe hSteamPipe ) { PRINT_DEBUG_ENTRY(); return true; } -STEAMCLIENT_API bool Steam_BLoggedOn( HSteamUser hUser, HSteamPipe hSteamPipe ) +STEAMCLIENT_API steam_bool Steam_BLoggedOn( HSteamUser hUser, HSteamPipe hSteamPipe ) { PRINT_DEBUG_ENTRY(); return true; } -STEAMCLIENT_API bool Steam_BReleaseSteamPipe( HSteamPipe hSteamPipe ) +STEAMCLIENT_API steam_bool Steam_BReleaseSteamPipe( HSteamPipe hSteamPipe ) { PRINT_DEBUG_TODO(); return false; @@ -1411,19 +1417,19 @@ STEAMCLIENT_API HSteamPipe Steam_CreateSteamPipe() return 0; } -STEAMCLIENT_API bool Steam_GSBLoggedOn( void *phSteamHandle ) +STEAMCLIENT_API steam_bool Steam_GSBLoggedOn( void *phSteamHandle ) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSBSecure( void *phSteamHandle) +STEAMCLIENT_API steam_bool Steam_GSBSecure( void *phSteamHandle) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSGetSteam2GetEncryptionKeyToSendToNewClient( void *phSteamHandle, void *pvEncryptionKey, uint32 *pcbEncryptionKey, uint32 cbMaxEncryptionKey ) +STEAMCLIENT_API steam_bool Steam_GSGetSteam2GetEncryptionKeyToSendToNewClient( void *phSteamHandle, void *pvEncryptionKey, uint32 *pcbEncryptionKey, uint32 cbMaxEncryptionKey ) { PRINT_DEBUG_TODO(); return false; @@ -1445,37 +1451,37 @@ STEAMCLIENT_API void Steam_GSLogOn( void *phSteamHandle ) PRINT_DEBUG_TODO(); } -STEAMCLIENT_API bool Steam_GSRemoveUserConnect( void *phSteamHandle, uint32 unUserID ) +STEAMCLIENT_API steam_bool Steam_GSRemoveUserConnect( void *phSteamHandle, uint32 unUserID ) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSSendSteam2UserConnect( void *phSteamHandle, uint32 unUserID, const void *pvRawKey, uint32 unKeyLen, uint32 unIPPublic, uint16 usPort, const void *pvCookie, uint32 cubCookie ) +STEAMCLIENT_API steam_bool Steam_GSSendSteam2UserConnect( void *phSteamHandle, uint32 unUserID, const void *pvRawKey, uint32 unKeyLen, uint32 unIPPublic, uint16 usPort, const void *pvCookie, uint32 cubCookie ) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSSendSteam3UserConnect( void *phSteamHandle, uint64 steamID, uint32 unIPPublic, const void *pvCookie, uint32 cubCookie ) +STEAMCLIENT_API steam_bool Steam_GSSendSteam3UserConnect( void *phSteamHandle, uint64 steamID, uint32 unIPPublic, const void *pvCookie, uint32 cubCookie ) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSSendUserDisconnect( void *phSteamHandle, uint64 ulSteamID, uint32 unUserID ) +STEAMCLIENT_API steam_bool Steam_GSSendUserDisconnect( void *phSteamHandle, uint64 ulSteamID, uint32 unUserID ) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSSendUserStatusResponse( void *phSteamHandle, uint64 ulSteamID, int nSecondsConnected, int nSecondsSinceLast ) +STEAMCLIENT_API steam_bool Steam_GSSendUserStatusResponse( void *phSteamHandle, uint64 ulSteamID, int nSecondsConnected, int nSecondsSinceLast ) { PRINT_DEBUG_TODO(); return false; } -STEAMCLIENT_API bool Steam_GSSetServerType( void *phSteamHandle, int32 nAppIdServed, uint32 unServerFlags, uint32 unGameIP, uint32 unGamePort, const char *pchGameDir, const char *pchVersion ) +STEAMCLIENT_API steam_bool Steam_GSSetServerType( void *phSteamHandle, int32 nAppIdServed, uint32 unServerFlags, uint32 unGameIP, uint32 unGamePort, const char *pchGameDir, const char *pchVersion ) { PRINT_DEBUG_TODO(); return false; @@ -1486,7 +1492,7 @@ STEAMCLIENT_API void Steam_GSSetSpawnCount( void *phSteamHandle, uint32 ucSpawn PRINT_DEBUG_TODO(); } -STEAMCLIENT_API bool Steam_GSUpdateStatus( void *phSteamHandle, int cPlayers, int cPlayersMax, int cBotPlayers, const char *pchServerName, const char *pchMapName ) +STEAMCLIENT_API steam_bool Steam_GSUpdateStatus( void *phSteamHandle, int cPlayers, int cPlayersMax, int cBotPlayers, const char *pchServerName, const char *pchMapName ) { PRINT_DEBUG_TODO(); return false; @@ -1495,7 +1501,7 @@ STEAMCLIENT_API bool Steam_GSUpdateStatus( void *phSteamHandle, int cPlayers, in STEAMCLIENT_API void* Steam_GetGSHandle( HSteamUser hUser, HSteamPipe hSteamPipe ) { PRINT_DEBUG_TODO(); - return NULL; + return nullptr; } STEAMCLIENT_API int Steam_InitiateGameConnection( HSteamUser hUser, HSteamPipe hSteamPipe, void *pBlob, int cbMaxBlob, uint64 steamID, int nGameAppID, uint32 unIPServer, uint16 usPortServer, bool bSecure ) @@ -1504,6 +1510,24 @@ STEAMCLIENT_API int Steam_InitiateGameConnection( HSteamUser hUser, HSteamPipe h return 0; } +// https://github.com/ValveSoftware/Proton/blob/962bbc4e74dde0643a6edab7c845bc628601f23f/lsteamclient/steamclient_main.c#L579-L586 +STEAMCLIENT_API steam_bool Steam_IsKnownInterface( const char *pchVersion ) +{ + PRINT_DEBUG("'%s'", pchVersion); + + // real client doesn't validate if the arg was null + if (!pchVersion) return false; + + bool found = client_known_interfaces.count(pchVersion); + + PRINT_DEBUG(" result=%i", (int)found); + if (!found) { + get_steam_client()->report_missing_impl(pchVersion, EMU_FUNC_NAME); + } + + return found; +} + STEAMCLIENT_API void Steam_LogOff( HSteamUser hUser, HSteamPipe hSteamPipe ) { PRINT_DEBUG_TODO(); @@ -1514,6 +1538,13 @@ STEAMCLIENT_API void Steam_LogOn( HSteamUser hUser, HSteamPipe hSteamPipe, uint6 PRINT_DEBUG_TODO(); } +// https://github.com/ValveSoftware/Proton/blob/962bbc4e74dde0643a6edab7c845bc628601f23f/lsteamclient/steamclient_main.c#L588-L594 +STEAMCLIENT_API void Steam_NotifyMissingInterface(HSteamPipe hSteamPipe, const char *pchVersion ) +{ + PRINT_DEBUG("XXXXXXXXXXXXX '%s' %i", pchVersion, hSteamPipe); + get_steam_client()->report_missing_impl(pchVersion, EMU_FUNC_NAME); +} + STEAMCLIENT_API void Steam_ReleaseThreadLocalMemory(bool thread_exit) { PRINT_DEBUG_TODO(); diff --git a/dll/dll/client_known_interfaces.h b/dll/dll/client_known_interfaces.h new file mode 100644 index 00000000..61605a73 --- /dev/null +++ b/dll/dll/client_known_interfaces.h @@ -0,0 +1,9 @@ +#ifndef _CLIENT_KNOWN_INTERFACES_H_ +#define _CLIENT_KNOWN_INTERFACES_H_ + +#include +#include + +extern const std::unordered_set client_known_interfaces; + +#endif // _CLIENT_KNOWN_INTERFACES_H_ diff --git a/dll/dll/steam_client.h b/dll/dll/steam_client.h index 5446a92a..1e2f37cd 100644 --- a/dll/dll/steam_client.h +++ b/dll/dll/steam_client.h @@ -338,6 +338,7 @@ public: void DestroyAllInterfaces(); + void report_missing_impl(std::string_view itf, std::string_view caller); [[noreturn]] void report_missing_impl_and_exit(std::string_view itf, std::string_view caller); }; diff --git a/dll/steam_app_ids.cpp b/dll/steam_app_ids.cpp index c02673a0..06c6bbf6 100644 --- a/dll/steam_app_ids.cpp +++ b/dll/steam_app_ids.cpp @@ -3,7 +3,7 @@ // https://developer.valvesoftware.com/wiki/Steam_Application_IDs // https://developer.valvesoftware.com/wiki/Dedicated_Servers_List // they're not really accurate -const std::map steam_preowned_app_ids = { +extern const std::map steam_preowned_app_ids = { // { 0, "Base Goldsource Shared Binaries" }, // { 1, "Base Goldsource Shared Content" }, diff --git a/dll/steam_client_interface_getter.cpp b/dll/steam_client_interface_getter.cpp index 2bed5292..e0736ee9 100644 --- a/dll/steam_client_interface_getter.cpp +++ b/dll/steam_client_interface_getter.cpp @@ -938,7 +938,7 @@ ISteamAppTicket *Steam_Client::GetAppTicket( HSteamUser hSteamUser, HSteamPipe h report_missing_impl_and_exit(pchVersion, EMU_FUNC_NAME); } -void Steam_Client::report_missing_impl_and_exit(std::string_view itf, std::string_view caller) +void Steam_Client::report_missing_impl(std::string_view itf, std::string_view caller) { PRINT_DEBUG("'%s' '%s'", itf.data(), caller.data()); std::lock_guard lck(global_mutex); @@ -947,18 +947,27 @@ void Steam_Client::report_missing_impl_and_exit(std::string_view itf, std::strin try { ss << "INTERFACE=" << itf << "\n"; ss << "CALLER FN=" << caller << "\n"; + } + catch(...) { } + try { if (settings_client) { ss << "APPID=" << settings_client->get_local_game_id().AppID() << "\n"; } + } + catch(...) { } + try { std::string time(common_helpers::get_utc_time()); if (time.size()) { ss << "TIME=" << time << "\n"; } ss << "--------------------\n" << std::endl; + } + catch(...) { } + try { std::ofstream report(std::filesystem::u8path(get_full_program_path() + "EMU_MISSING_INTERFACE.txt"), std::ios::out | std::ios::app); if (report.is_open()) { report << ss.str(); @@ -969,6 +978,10 @@ void Steam_Client::report_missing_impl_and_exit(std::string_view itf, std::strin #if defined(__WINDOWS__) MessageBoxA(nullptr, ss.str().c_str(), "Missing interface", MB_OK); #endif - +} + +void Steam_Client::report_missing_impl_and_exit(std::string_view itf, std::string_view caller) +{ + report_missing_impl(itf, caller); std::exit(0x4155149); // MISSING :) }