From f4ab249f369dac944f150f5757dfdca541297bfc Mon Sep 17 00:00:00 2001 From: Mr_Goldberg Date: Sat, 3 Aug 2019 18:55:08 -0400 Subject: [PATCH 1/3] Add a way to configure which leaderboards are seen by the game. --- Readme_release.txt | 9 ++++ dll/settings.cpp | 10 +++++ dll/settings.h | 13 ++++++ dll/steam_client.cpp | 41 +++++++++++++++++++ dll/steam_user_stats.h | 25 +++++++---- .../leaderboards.EXAMPLE.txt | 3 ++ 6 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 files_example/steam_settings.EXAMPLE/leaderboards.EXAMPLE.txt diff --git a/Readme_release.txt b/Readme_release.txt index 296d844..0685e60 100644 --- a/Readme_release.txt +++ b/Readme_release.txt @@ -72,6 +72,15 @@ The items.json syntax is simple, you SHOULD validate your .json file before tryi You can use https://steamdb.info/ to list items and attributes they have and put them into your .json. Keep in mind that some item are not valid to have in your inventory. For example, in PayDay2 all items below item_id 50000 will make your game crash. +Leaderboards: +By default the emulator assumes all leaderboards queried by the game (FindLeaderboard()) exist and creates them with the most common options (sort method descending, display type numeric) +In some games this default behavior doesn't work and so you may need to tweak which leaderboards the game sees. +To do that, you can put a leaderboards.txt file in the steam_settings folder. +An empty leaderboards.txt makes the emu behave as if any leaderboard queried by the game using FindLeaderboard does not exist. +The format is: LEADERBOARD_NAME=sort method=display type +For the sort methods: 0 = none, 1 = ascending, 2 = descending +For the display type: 0 = none, 1 = numeric, 2 = time seconds, 3 = milliseconds +An example can be found in steam_settings.EXAMPLE Support for CPY steam_api(64).dll cracks: See the build in the experimental folder. diff --git a/dll/settings.cpp b/dll/settings.cpp index affa95f..46771a4 100644 --- a/dll/settings.cpp +++ b/dll/settings.cpp @@ -53,6 +53,7 @@ Settings::Settings(CSteamID steam_id, CGameID game_id, std::string name, std::st this->unlockAllDLCs = true; this->offline = offline; + this->create_unknown_leaderboards = true; } CSteamID Settings::get_local_steam_id() @@ -193,3 +194,12 @@ std::string Settings::getAppInstallPath(AppId_t appID) { return app_paths[appID]; } + +void Settings::setLeaderboard(std::string leaderboard, enum ELeaderboardSortMethod sort_method, enum ELeaderboardDisplayType display_type) +{ + Leaderboard_config leader; + leader.sort_method = sort_method; + leader.display_type = display_type; + + leaderboards[leaderboard] = leader; +} \ No newline at end of file diff --git a/dll/settings.h b/dll/settings.h index 001b7ef..940f121 100644 --- a/dll/settings.h +++ b/dll/settings.h @@ -33,6 +33,11 @@ struct Mod_entry { std::string path; }; +struct Leaderboard_config { + enum ELeaderboardSortMethod sort_method; + enum ELeaderboardDisplayType display_type; +}; + class Settings { CSteamID steam_id; CGameID game_id; @@ -44,6 +49,8 @@ class Settings { std::vector DLCs; std::vector mods; std::map app_paths; + std::map leaderboards; + bool create_unknown_leaderboards; public: #ifdef LOBBY_CONNECT @@ -78,6 +85,12 @@ public: Mod_entry getMod(PublishedFileId_t id); bool isModInstalled(PublishedFileId_t id); std::set modSet(); + + //leaderboards + void setLeaderboard(std::string leaderboard, enum ELeaderboardSortMethod sort_method, enum ELeaderboardDisplayType display_type); + std::map getLeaderboards() { return leaderboards; } + void setCreateUnknownLeaderboards(bool enable) {create_unknown_leaderboards = enable;} + bool createUnknownLeaderboards() { return create_unknown_leaderboards; } }; #endif diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp index 09b6bca..38fbd8c 100644 --- a/dll/steam_client.cpp +++ b/dll/steam_client.cpp @@ -278,6 +278,47 @@ Steam_Client::Steam_Client() } } + { + std::string dlc_config_path = Local_Storage::get_game_settings_path() + "leaderboards.txt"; + std::ifstream input( dlc_config_path ); + if (input.is_open()) { + settings_client->setCreateUnknownLeaderboards(false); + settings_server->setCreateUnknownLeaderboards(false); + + for( std::string line; getline( input, line ); ) { + if (!line.empty() && line[line.length()-1] == '\n') { + line.erase(line.length()-1); + } + + if (!line.empty() && line[line.length()-1] == '\r') { + line.erase(line.length()-1); + } + + std::string leaderboard; + unsigned int sort_method = 0; + unsigned int display_type = 0; + + std::size_t deliminator = line.find("="); + if (deliminator != 0 && deliminator != std::string::npos && deliminator != line.size()) { + leaderboard = line.substr(0, deliminator); + std::size_t deliminator2 = line.find("=", deliminator + 1); + if (deliminator2 != std::string::npos && deliminator2 != line.size()) { + sort_method = stol(line.substr(deliminator + 1, deliminator2)); + display_type = stol(line.substr(deliminator2 + 1)); + } + } + + if (leaderboard.size() && sort_method <= k_ELeaderboardSortMethodDescending && display_type <= k_ELeaderboardDisplayTypeTimeMilliSeconds) { + PRINT_DEBUG("Adding leaderboard: %s|%u|%u\n", leaderboard.c_str(), sort_method, display_type); + settings_client->setLeaderboard(leaderboard, (ELeaderboardSortMethod)sort_method, (ELeaderboardDisplayType)display_type); + settings_server->setLeaderboard(leaderboard, (ELeaderboardSortMethod)sort_method, (ELeaderboardDisplayType)display_type); + } else { + PRINT_DEBUG("Error adding leaderboard for: %s, are sort method %u or display type %u valid?\n", leaderboard.c_str(), sort_method, display_type); + } + } + } + } + { std::string mod_path = Local_Storage::get_game_settings_path() + "mods"; std::vector paths = Local_Storage::get_filenames_path(mod_path); diff --git a/dll/steam_user_stats.h b/dll/steam_user_stats.h index fca085b..d889579 100644 --- a/dll/steam_user_stats.h +++ b/dll/steam_user_stats.h @@ -109,6 +109,7 @@ bool GetStat( const char *pchName, float *pData ) bool SetStat( const char *pchName, int32 nData ) { PRINT_DEBUG("SetStat int32 %s\n", pchName); + if (!pchName) return false; std::lock_guard lock(global_mutex); return local_storage->store_data(STATS_STORAGE_FOLDER, pchName, (char* )&nData, sizeof(nData)) == sizeof(nData); @@ -117,6 +118,7 @@ bool SetStat( const char *pchName, int32 nData ) bool SetStat( const char *pchName, float fData ) { PRINT_DEBUG("SetStat float %s\n", pchName); + if (!pchName) return false; std::lock_guard lock(global_mutex); return local_storage->store_data(STATS_STORAGE_FOLDER, pchName, (char* )&fData, sizeof(fData)) == sizeof(fData); @@ -368,14 +370,19 @@ SteamAPICall_t FindLeaderboard( const char *pchLeaderboardName ) { PRINT_DEBUG("FindLeaderboard %s\n", pchLeaderboardName); std::lock_guard lock(global_mutex); - //TODO: figure out a way to get real leaderboard info - /* - LeaderboardFindResult_t data; - data.m_hSteamLeaderboard = find_leaderboard(pchLeaderboardName);; - data.m_bLeaderboardFound = !!data.m_hSteamLeaderboard; - return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); - */ - return FindOrCreateLeaderboard(pchLeaderboardName, k_ELeaderboardSortMethodDescending, k_ELeaderboardDisplayTypeNumeric); + + auto settings_Leaderboards = settings->getLeaderboards(); + if (settings_Leaderboards.count(pchLeaderboardName)) { + auto config = settings_Leaderboards[pchLeaderboardName]; + return FindOrCreateLeaderboard(pchLeaderboardName, config.sort_method, config.display_type); + } else if (settings->createUnknownLeaderboards()) { + return FindOrCreateLeaderboard(pchLeaderboardName, k_ELeaderboardSortMethodDescending, k_ELeaderboardDisplayTypeNumeric); + } else { + LeaderboardFindResult_t data; + data.m_hSteamLeaderboard = find_leaderboard(pchLeaderboardName);; + data.m_bLeaderboardFound = !!data.m_hSteamLeaderboard; + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); + } } @@ -446,7 +453,7 @@ STEAM_METHOD_DESC(Downloads leaderboard entries for an arbitrary set of users - SteamAPICall_t DownloadLeaderboardEntriesForUsers( SteamLeaderboard_t hSteamLeaderboard, STEAM_ARRAY_COUNT_D(cUsers, Array of users to retrieve) CSteamID *prgUsers, int cUsers ) { - PRINT_DEBUG("DownloadLeaderboardEntriesForUsers\n"); + PRINT_DEBUG("DownloadLeaderboardEntriesForUsers %i %llu\n", cUsers, cUsers > 0 ? prgUsers[0].ConvertToUint64() : 0); std::lock_guard lock(global_mutex); LeaderboardScoresDownloaded_t data; data.m_hSteamLeaderboard = hSteamLeaderboard; diff --git a/files_example/steam_settings.EXAMPLE/leaderboards.EXAMPLE.txt b/files_example/steam_settings.EXAMPLE/leaderboards.EXAMPLE.txt new file mode 100644 index 0000000..392e08c --- /dev/null +++ b/files_example/steam_settings.EXAMPLE/leaderboards.EXAMPLE.txt @@ -0,0 +1,3 @@ +LEADERBOARD1=0=0 +LEADERBOARDX=1=1 +LEADERBOARDTEST=0=0 From bf4847452e0ca751cfd278aec739f9f0310d85e8 Mon Sep 17 00:00:00 2001 From: Mr_Goldberg Date: Sat, 3 Aug 2019 18:58:23 -0400 Subject: [PATCH 2/3] SteamAPI_Shutdown actually does something now. --- dll/dll.cpp | 2 ++ dll/steam_client.cpp | 5 +++++ dll/steam_client.h | 1 + 3 files changed, 8 insertions(+) diff --git a/dll/dll.cpp b/dll/dll.cpp index 22a256e..ec7d209 100644 --- a/dll/dll.cpp +++ b/dll/dll.cpp @@ -135,6 +135,7 @@ Steam_Client *get_steam_clientserver_old() S_API void * S_CALLTYPE SteamInternal_CreateInterface( const char *ver ) { PRINT_DEBUG("SteamInternal_CreateInterface %s\n", ver); + if (!get_steam_client()->user_logged_in) return NULL; if (strstr(ver, "SteamClient") == ver) { void *steam_client; @@ -217,6 +218,7 @@ S_API bool S_CALLTYPE SteamAPI_InitAnonymousUser() S_API void S_CALLTYPE SteamAPI_Shutdown() { PRINT_DEBUG("SteamAPI_Shutdown\n"); + get_steam_client()->clientShutdown(); } // SteamAPI_RestartAppIfNecessary ensures that your executable was launched through Steam. diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp index 38fbd8c..48e69ac 100644 --- a/dll/steam_client.cpp +++ b/dll/steam_client.cpp @@ -421,6 +421,11 @@ void Steam_Client::serverShutdown() server_init = false; } +void Steam_Client::clientShutdown() +{ + user_logged_in = false; +} + void Steam_Client::setAppID(uint32 appid) { std::lock_guard lock(global_mutex); diff --git a/dll/steam_client.h b/dll/steam_client.h index 7e6bc75..36f40a0 100644 --- a/dll/steam_client.h +++ b/dll/steam_client.h @@ -274,6 +274,7 @@ public: void userLogIn(); void serverInit(); void serverShutdown(); + void clientShutdown(); bool IsServerInit(); bool IsUserLogIn(); }; From 35c59044fd5da9daf0aeb27d9bc3e0a732073c79 Mon Sep 17 00:00:00 2001 From: Mr_Goldberg Date: Sat, 3 Aug 2019 19:00:31 -0400 Subject: [PATCH 3/3] SteamGameServerClient should return NULL if the gameserver is not initialized. --- dll/dll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dll/dll.cpp b/dll/dll.cpp index ec7d209..19f9c70 100644 --- a/dll/dll.cpp +++ b/dll/dll.cpp @@ -588,7 +588,7 @@ S_API uint64 SteamGameServer_GetSteamID() S_API ISteamClient *SteamGameServerClient() { PRINT_DEBUG("SteamGameServerClient()\n"); load_old_interface_versions(); - get_steam_clientserver_old(); + if (!get_steam_clientserver_old()->IsServerInit()) return NULL; return (ISteamClient *)SteamInternal_CreateInterface(old_client); }