This commit is contained in:
acidicoala
2022-12-30 02:50:27 +03:00
parent 636f9186a3
commit d6828e3bfb
24 changed files with 97 additions and 74 deletions

View File

@@ -45,10 +45,13 @@ set(
src/steam_api_virtuals/isteaminventory.cpp src/steam_api_virtuals/isteaminventory.cpp
src/steam_api_virtuals/isteamuser.cpp src/steam_api_virtuals/isteamuser.cpp
src/steam_impl/steam_apps.cpp src/steam_impl/steam_apps.cpp
src/steam_impl/steam_apps.hpp
src/steam_impl/steam_client.cpp 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.cpp
src/steam_impl/steam_inventory.hpp
src/steam_impl/steam_user.cpp src/steam_impl/steam_user.cpp
src/steam_impl/steam_user.hpp
src/steam_functions/steam_functions.cpp src/steam_functions/steam_functions.cpp
src/steam_functions/steam_functions.hpp src/steam_functions/steam_functions.hpp
src/steam_types/steam_types.hpp src/steam_types/steam_types.hpp

View File

@@ -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. ¹ 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 [SmokeAPI.json]: res/SmokeAPI.json
[manually maintained list of DLC IDs]: https://github.com/acidicoala/public-entitlements/blob/main/steam/v1/dlc.json [manually maintained list of DLC IDs]: https://github.com/acidicoala/public-entitlements/blob/main/steam/v1/dlc.json
## Extra info ## Extra info
### How SmokeAPI works in games with large number of DLCs ### 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 [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 ## 👋 Acknowledgements
SmokeAPI makes use of the following open source projects: SmokeAPI makes use of the following open source projects:

View File

@@ -57,7 +57,7 @@ namespace smoke_api {
logger->info("Loaded Koalageddon config from the {}", kg_config_source); logger->info("Loaded Koalageddon config from the {}", kg_config_source);
dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& library, const String& name) { 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) { if (name == VSTDLIB_DLL) {
// Family Sharing functions // Family Sharing functions

View File

@@ -1,5 +1,8 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_apps.hpp>
#include <steam_impl/steam_client.hpp>
#include <steam_impl/steam_inventory.hpp>
#include <steam_impl/steam_user.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,6 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_client.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,6 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_client.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/win_util.hpp> #include <koalabox/win_util.hpp>
@@ -18,9 +17,9 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
if (not version_map.contains(version_prefix)) { if (not version_map.contains(version_prefix)) {
try { 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; std::smatch match;
if (std::regex_search(rdata, match, regex)) { if (std::regex_search(rdata, match, regex)) {
version_map[version_prefix] = match[0]; version_map[version_prefix] = match[0];

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,6 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_client.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_inventory.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_user.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -55,6 +55,8 @@ typedef uint64_t CSteamID;
typedef uint32_t HCoroutine; typedef uint32_t HCoroutine;
// TODO: Refactor into multiple headers
// ISteamClient // ISteamClient
VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*)); VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*));
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*)); VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*));

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_apps.hpp>
#include <koalabox/io.hpp> #include <koalabox/io.hpp>
@@ -163,8 +163,6 @@ namespace steam_apps {
logger->debug("{} -> App ID: {}", function_name, app_id); 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(); original_dlc_count = original_function();
logger->debug("{} -> Original DLC count: {}", function_name, original_dlc_count); logger->debug("{} -> Original DLC count: {}", function_name, original_dlc_count);

View File

@@ -0,0 +1,22 @@
#include <steam_functions/steam_functions.hpp>
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<int()>& 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<bool()>& original_function
);
}

View File

@@ -1,6 +1,9 @@
#include <steam_impl/steam_impl.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_functions/steam_functions.hpp>
namespace steam_client{ using namespace smoke_api;
namespace steam_client {
void* GetGenericInterface( void* GetGenericInterface(
const String& function_name, const String& function_name,

View File

@@ -0,0 +1,14 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api;
namespace steam_client {
void* GetGenericInterface(
const String& function_name,
const String& interface_version,
const std::function<void*()>& original_function
);
}

View File

@@ -1,5 +1,5 @@
#include <steam_impl/steam_impl.hpp>
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_inventory.hpp>
// TODO: Figure out why it doesn't work in koalageddon mode // TODO: Figure out why it doesn't work in koalageddon mode
namespace steam_inventory { namespace steam_inventory {
@@ -25,7 +25,7 @@ namespace steam_inventory {
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
) { ) {
static std::mutex section; static std::mutex section;
std::lock_guard<std::mutex> guard(section); const std::lock_guard<std::mutex> guard(section);
const auto success = original_function(); const auto success = original_function();
@@ -120,7 +120,7 @@ namespace steam_inventory {
uint32_t unItemIndex, uint32_t unItemIndex,
const char* pchPropertyName, const char* pchPropertyName,
char* pchValueBuffer, char* pchValueBuffer,
uint32_t* punValueBufferSizeOut, const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function const std::function<bool()>& original_function
) { ) {
const auto common_info = fmt::format( const auto common_info = fmt::format(

View File

@@ -1,45 +1,7 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_functions/steam_functions.hpp> #include <steam_functions/steam_functions.hpp>
using namespace koalabox; 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<int()>& 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<bool()>& original_function
);
}
namespace steam_user {
EUserHasLicenseForAppResult UserHasLicenseForApp(
const String& function_name,
AppId_t appID,
const std::function<EUserHasLicenseForAppResult()>& original_function
);
}
namespace steam_client {
void* GetGenericInterface(
const String& function_name,
const String& interface_version,
const std::function<void*()>& original_function
);
}
namespace steam_inventory { namespace steam_inventory {
@@ -64,7 +26,7 @@ namespace steam_inventory {
uint32_t unItemIndex, uint32_t unItemIndex,
const char* pchPropertyName, const char* pchPropertyName,
char* pchValueBuffer, char* pchValueBuffer,
uint32_t* punValueBufferSizeOut, const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function const std::function<bool()>& original_function
); );

View File

@@ -1,4 +1,4 @@
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_user.hpp>
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
namespace steam_user { namespace steam_user {

View File

@@ -0,0 +1,14 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api;
namespace steam_user {
EUserHasLicenseForAppResult UserHasLicenseForApp(
const String& function_name,
AppId_t appID,
const std::function<EUserHasLicenseForAppResult()>& original_function
);
}

View File

@@ -1,6 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_functions/steam_functions.hpp> #include <steam_impl/steam_client.hpp>
#include <steam_impl/steam_impl.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api; using namespace smoke_api;
@@ -10,4 +10,4 @@ VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(
) )
) { ) {
return steam_apps::IsDlcUnlocked(__func__, app_id, dlc_id); return steam_apps::IsDlcUnlocked(__func__, app_id, dlc_id);
} }

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api; using namespace smoke_api;

View File

@@ -1,5 +1,5 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_inventory.hpp>
using namespace smoke_api; using namespace smoke_api;
@@ -132,4 +132,4 @@ VIRTUAL(bool) IClientInventory_GetItemDefinitionIDs(
*p_array_size = item_count; *p_array_size = item_count;
return IClientInventory_GetItemDefinitionIDs_o(ARGS(pItemDefIDs, item_count, p_array_size)); return IClientInventory_GetItemDefinitionIDs_o(ARGS(pItemDefIDs, item_count, p_array_size));
}); });
} }

View File

@@ -1,9 +1,9 @@
#include <smoke_api/smoke_api.hpp> #include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_impl.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api; using namespace smoke_api;
// TODO: Implement? // TODO: Hook?
VIRTUAL(bool) IClientUser_IsSubscribedApp(PARAMS(AppId_t app_id)) { // NOLINT(misc-unused-parameters) VIRTUAL(bool) IClientUser_IsSubscribedApp(PARAMS(AppId_t app_id)) { // NOLINT(misc-unused-parameters)
return steam_apps::IsDlcUnlocked(__func__, 0, app_id); return steam_apps::IsDlcUnlocked(__func__, 0, app_id);
} }