diff --git a/CMakeLists.txt b/CMakeLists.txt index f73ecc7..25b10b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,10 +45,13 @@ set( src/steam_api_virtuals/isteaminventory.cpp src/steam_api_virtuals/isteamuser.cpp src/steam_impl/steam_apps.cpp + src/steam_impl/steam_apps.hpp src/steam_impl/steam_client.cpp - src/steam_impl/steam_impl.hpp + src/steam_impl/steam_client.hpp src/steam_impl/steam_inventory.cpp + src/steam_impl/steam_inventory.hpp src/steam_impl/steam_user.cpp + src/steam_impl/steam_user.hpp src/steam_functions/steam_functions.cpp src/steam_functions/steam_functions.hpp src/steam_types/steam_types.hpp diff --git a/README.md b/README.md index 758175f..8ffbbe5 100644 --- a/README.md +++ b/README.md @@ -84,16 +84,22 @@ SmokeAPI does not require any manual configuration. By default, it uses the most ¹ DLC/Item IDs can be obtained from https://steamdb.info. You need to be logged in with your steam account in order to see accurate inventory item IDs. [SmokeAPI.json]: res/SmokeAPI.json + [manually maintained list of DLC IDs]: https://github.com/acidicoala/public-entitlements/blob/main/steam/v1/dlc.json ## ℹ Extra info ### How SmokeAPI works in games with large number of DLCs -Some games that have a lot of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs. Once the game receives the list, it will go over each item and check the ownership. The issue arises from the fact that response from Steamworks SDK may max out at 64, depending on how much unowned DLC the user has. To alleviate this issue, SmokeAPI will make a web request to Steam API for a full list of DLCs, which works well most of the time. Unfortunately, even the web API does not solve all of our problems, because it will only return DLCs that are available in Steam store. This means that DLCs without a dedicated store offer, such as pre-order DLCs will be left out. That's where the `dlc_ids` config option comes into play. You can specify those missing DLC IDs there, and SmokeAPI will make them available to the game. However, this introduces the need for manual configuration, which goes against the ideals of this project. To remedy this issue SmokeAPI will also fetch [this document] stored in a GitHub repository. It contains all the DLC IDs missing from Steam store. The document is hand-crafted using data from https://steamdb.com. This enables SmokeAPI to unlock all DLCs without any config file at all. Feel free to report games that have more than 64 DLCs, *and* have DLCs without a dedicated store page. They will be added to the list of missing DLC IDs to facilitate configless operation. +Some games that have a lot of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs. Once the game receives the list, it will go over each item and check the ownership. The issue arises from the fact that response from Steamworks SDK may max out at 64, depending on how much unowned DLC the user has. To alleviate this issue, SmokeAPI will make a web request to Steam API for a full list of DLCs, which works well most of the time. Unfortunately, even the web API does not solve all of our problems, because it will only return DLCs that are available in Steam store. This means that DLCs without a dedicated store offer, such as pre-order DLCs will be left out. That's where the `dlc_ids` config option comes into play. You can specify those missing DLC IDs there, and SmokeAPI will make them available to the game. However, this introduces the need for manual configuration, which goes against the ideals of this project. To remedy this issue SmokeAPI will also fetch [this document] stored in a GitHub repository. It contains all the DLC IDs missing from Steam store. The document is hand-crafted using data from https://steamdb.com. This enables SmokeAPI to unlock all DLCs without any config file at all. Feel free to report games that have more than 64 DLCs, +*and* have DLCs without a dedicated store page. They will be added to the list of missing DLC IDs to facilitate configless operation. [this document]: https://github.com/acidicoala/public-entitlements/blob/main/steam/v1/dlc.json +## ✒️ TODO +- Describe how Koalageddon mode works and its config parameters +- Describe the organisation of the project + ## 👋 Acknowledgements SmokeAPI makes use of the following open source projects: diff --git a/src/smoke_api/smoke_api.cpp b/src/smoke_api/smoke_api.cpp index 22ba16a..9e918dd 100644 --- a/src/smoke_api/smoke_api.cpp +++ b/src/smoke_api/smoke_api.cpp @@ -57,7 +57,7 @@ namespace smoke_api { logger->info("Loaded Koalageddon config from the {}", kg_config_source); dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& library, const String& name) { - original_library = library; // TODO: Is this necessary? + original_library = library; if (name == VSTDLIB_DLL) { // Family Sharing functions diff --git a/src/steam_api_exports/steam_api_flat.cpp b/src/steam_api_exports/steam_api_flat.cpp index 7ed2af0..3f96c15 100644 --- a/src/steam_api_exports/steam_api_flat.cpp +++ b/src/steam_api_exports/steam_api_flat.cpp @@ -1,5 +1,8 @@ #include -#include +#include +#include +#include +#include using namespace smoke_api; diff --git a/src/steam_api_exports/steam_api_internal.cpp b/src/steam_api_exports/steam_api_internal.cpp index 63b3f62..6cafbf8 100644 --- a/src/steam_api_exports/steam_api_internal.cpp +++ b/src/steam_api_exports/steam_api_internal.cpp @@ -1,6 +1,5 @@ #include -#include -#include +#include using namespace smoke_api; diff --git a/src/steam_api_exports/steam_api_unversioned.cpp b/src/steam_api_exports/steam_api_unversioned.cpp index 80290ae..006b6ab 100644 --- a/src/steam_api_exports/steam_api_unversioned.cpp +++ b/src/steam_api_exports/steam_api_unversioned.cpp @@ -1,6 +1,5 @@ #include -#include -#include +#include #include @@ -18,9 +17,9 @@ String get_versioned_interface(const String& version_prefix, const String& fallb if (not version_map.contains(version_prefix)) { try { - String rdata = win_util::get_pe_section_data_or_throw(original_library, ".rdata"); + const String rdata = win_util::get_pe_section_data_or_throw(original_library, ".rdata"); - std::regex regex(version_prefix + "\\d{3}"); + const std::regex regex(version_prefix + "\\d{3}"); std::smatch match; if (std::regex_search(rdata, match, regex)) { version_map[version_prefix] = match[0]; diff --git a/src/steam_api_virtuals/isteamapps.cpp b/src/steam_api_virtuals/isteamapps.cpp index fbe50bf..a875a79 100644 --- a/src/steam_api_virtuals/isteamapps.cpp +++ b/src/steam_api_virtuals/isteamapps.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace smoke_api; diff --git a/src/steam_api_virtuals/isteamclient.cpp b/src/steam_api_virtuals/isteamclient.cpp index 349793a..f43f35f 100644 --- a/src/steam_api_virtuals/isteamclient.cpp +++ b/src/steam_api_virtuals/isteamclient.cpp @@ -1,6 +1,5 @@ #include -#include -#include +#include using namespace smoke_api; diff --git a/src/steam_api_virtuals/isteaminventory.cpp b/src/steam_api_virtuals/isteaminventory.cpp index b96314a..496a998 100644 --- a/src/steam_api_virtuals/isteaminventory.cpp +++ b/src/steam_api_virtuals/isteaminventory.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace smoke_api; diff --git a/src/steam_api_virtuals/isteamuser.cpp b/src/steam_api_virtuals/isteamuser.cpp index a7617a9..1a557d9 100644 --- a/src/steam_api_virtuals/isteamuser.cpp +++ b/src/steam_api_virtuals/isteamuser.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace smoke_api; diff --git a/src/steam_functions/steam_functions.hpp b/src/steam_functions/steam_functions.hpp index 1e452d4..5617e10 100644 --- a/src/steam_functions/steam_functions.hpp +++ b/src/steam_functions/steam_functions.hpp @@ -55,6 +55,8 @@ typedef uint64_t CSteamID; typedef uint32_t HCoroutine; +// TODO: Refactor into multiple headers + // ISteamClient VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*)); VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*)); diff --git a/src/steam_impl/steam_apps.cpp b/src/steam_impl/steam_apps.cpp index b9dce54..254c572 100644 --- a/src/steam_impl/steam_apps.cpp +++ b/src/steam_impl/steam_apps.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -163,8 +163,6 @@ namespace steam_apps { logger->debug("{} -> App ID: {}", function_name, app_id); } - // Compute count only once - // FIXME: This doesn't work in Koalageddon mode original_dlc_count = original_function(); logger->debug("{} -> Original DLC count: {}", function_name, original_dlc_count); diff --git a/src/steam_impl/steam_apps.hpp b/src/steam_impl/steam_apps.hpp new file mode 100644 index 0000000..796acfe --- /dev/null +++ b/src/steam_impl/steam_apps.hpp @@ -0,0 +1,22 @@ +#include + +using namespace smoke_api; + +namespace steam_apps { + + bool IsDlcUnlocked(const String& function_name, AppId_t app_id, AppId_t dlc_id); + + int GetDLCCount(const String& function_name, AppId_t app_id, const std::function& original_function); + + bool GetDLCDataByIndex( + const String& function_name, + AppId_t app_id, + int iDLC, + AppId_t* pDlcId, + bool* pbAvailable, + char* pchName, + int cchNameBufferSize, + const std::function& original_function + ); + +} diff --git a/src/steam_impl/steam_client.cpp b/src/steam_impl/steam_client.cpp index 07a8a05..b5b447d 100644 --- a/src/steam_impl/steam_client.cpp +++ b/src/steam_impl/steam_client.cpp @@ -1,6 +1,9 @@ -#include +#include +#include -namespace steam_client{ +using namespace smoke_api; + +namespace steam_client { void* GetGenericInterface( const String& function_name, diff --git a/src/steam_impl/steam_client.hpp b/src/steam_impl/steam_client.hpp new file mode 100644 index 0000000..df7a977 --- /dev/null +++ b/src/steam_impl/steam_client.hpp @@ -0,0 +1,14 @@ +#include +#include + +using namespace smoke_api; + +namespace steam_client { + + void* GetGenericInterface( + const String& function_name, + const String& interface_version, + const std::function& original_function + ); + +} diff --git a/src/steam_impl/steam_inventory.cpp b/src/steam_impl/steam_inventory.cpp index 63da524..824ec6a 100644 --- a/src/steam_impl/steam_inventory.cpp +++ b/src/steam_impl/steam_inventory.cpp @@ -1,5 +1,5 @@ -#include #include +#include // TODO: Figure out why it doesn't work in koalageddon mode namespace steam_inventory { @@ -25,7 +25,7 @@ namespace steam_inventory { const std::function& get_item_definition_ids ) { static std::mutex section; - std::lock_guard guard(section); + const std::lock_guard guard(section); const auto success = original_function(); @@ -120,7 +120,7 @@ namespace steam_inventory { uint32_t unItemIndex, const char* pchPropertyName, char* pchValueBuffer, - uint32_t* punValueBufferSizeOut, + const uint32_t* punValueBufferSizeOut, const std::function& original_function ) { const auto common_info = fmt::format( diff --git a/src/steam_impl/steam_impl.hpp b/src/steam_impl/steam_inventory.hpp similarity index 66% rename from src/steam_impl/steam_impl.hpp rename to src/steam_impl/steam_inventory.hpp index 5b2f800..82e2613 100644 --- a/src/steam_impl/steam_impl.hpp +++ b/src/steam_impl/steam_inventory.hpp @@ -1,45 +1,7 @@ +#include #include -using namespace koalabox; - -namespace steam_apps { - - bool IsDlcUnlocked(const String& function_name, AppId_t app_id, AppId_t dlc_id); - - int GetDLCCount(const String& function_name, AppId_t app_id, const std::function& original_function); - - bool GetDLCDataByIndex( - const String& function_name, - AppId_t app_id, - int iDLC, - AppId_t* pDlcId, - bool* pbAvailable, - char* pchName, - int cchNameBufferSize, - const std::function& original_function - ); - -} - -namespace steam_user { - - EUserHasLicenseForAppResult UserHasLicenseForApp( - const String& function_name, - AppId_t appID, - const std::function& original_function - ); - -} - -namespace steam_client { - - void* GetGenericInterface( - const String& function_name, - const String& interface_version, - const std::function& original_function - ); - -} +using namespace smoke_api; namespace steam_inventory { @@ -64,7 +26,7 @@ namespace steam_inventory { uint32_t unItemIndex, const char* pchPropertyName, char* pchValueBuffer, - uint32_t* punValueBufferSizeOut, + const uint32_t* punValueBufferSizeOut, const std::function& original_function ); diff --git a/src/steam_impl/steam_user.cpp b/src/steam_impl/steam_user.cpp index 36a81c1..2c8e8f5 100644 --- a/src/steam_impl/steam_user.cpp +++ b/src/steam_impl/steam_user.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace steam_user { diff --git a/src/steam_impl/steam_user.hpp b/src/steam_impl/steam_user.hpp new file mode 100644 index 0000000..f027fb1 --- /dev/null +++ b/src/steam_impl/steam_user.hpp @@ -0,0 +1,14 @@ +#include +#include + +using namespace smoke_api; + +namespace steam_user { + + EUserHasLicenseForAppResult UserHasLicenseForApp( + const String& function_name, + AppId_t appID, + const std::function& original_function + ); + +} diff --git a/src/steamclient_exports/steamclient.cpp b/src/steamclient_exports/steamclient.cpp index ebcc710..e6bfe3a 100644 --- a/src/steamclient_exports/steamclient.cpp +++ b/src/steamclient_exports/steamclient.cpp @@ -1,6 +1,5 @@ #include -#include -#include +#include using namespace smoke_api; diff --git a/src/steamclient_virtuals/client_app_manager.cpp b/src/steamclient_virtuals/client_app_manager.cpp index 770f9d5..cb265f2 100644 --- a/src/steamclient_virtuals/client_app_manager.cpp +++ b/src/steamclient_virtuals/client_app_manager.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace smoke_api; @@ -10,4 +10,4 @@ VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled( ) ) { return steam_apps::IsDlcUnlocked(__func__, app_id, dlc_id); -} \ No newline at end of file +} diff --git a/src/steamclient_virtuals/client_apps.cpp b/src/steamclient_virtuals/client_apps.cpp index 73257a2..c9e6f8a 100644 --- a/src/steamclient_virtuals/client_apps.cpp +++ b/src/steamclient_virtuals/client_apps.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace smoke_api; diff --git a/src/steamclient_virtuals/client_inventory.cpp b/src/steamclient_virtuals/client_inventory.cpp index f00e007..1a20304 100644 --- a/src/steamclient_virtuals/client_inventory.cpp +++ b/src/steamclient_virtuals/client_inventory.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace smoke_api; @@ -132,4 +132,4 @@ VIRTUAL(bool) IClientInventory_GetItemDefinitionIDs( *p_array_size = item_count; return IClientInventory_GetItemDefinitionIDs_o(ARGS(pItemDefIDs, item_count, p_array_size)); }); -} \ No newline at end of file +} diff --git a/src/steamclient_virtuals/client_user.cpp b/src/steamclient_virtuals/client_user.cpp index 8a7f2a2..6ff1d42 100644 --- a/src/steamclient_virtuals/client_user.cpp +++ b/src/steamclient_virtuals/client_user.cpp @@ -1,9 +1,9 @@ #include -#include +#include using namespace smoke_api; -// TODO: Implement? +// TODO: Hook? VIRTUAL(bool) IClientUser_IsSubscribedApp(PARAMS(AppId_t app_id)) { // NOLINT(misc-unused-parameters) return steam_apps::IsDlcUnlocked(__func__, 0, app_id); }