mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2026-01-25 05:52:51 -05:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53d28ee65d | ||
|
|
5b76d155a8 | ||
|
|
be9fa39508 | ||
|
|
5d1abc6498 | ||
|
|
5afdd59044 | ||
|
|
179be28097 | ||
|
|
08290d3559 | ||
|
|
1c9270676d |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -4,7 +4,7 @@ on: push
|
|||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
name: CI
|
name: CI
|
||||||
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@1f09cc8e2efa189573acb6958e6419598340797a
|
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@d9b0d1a00beb065a9a931a60ef615ce8d1fc7164
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
with:
|
with:
|
||||||
|
|||||||
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -3,3 +3,4 @@
|
|||||||
/workspace.xml
|
/workspace.xml
|
||||||
# Editor-based HTTP Client requests
|
# Editor-based HTTP Client requests
|
||||||
/httpRequests/
|
/httpRequests/
|
||||||
|
vcs.xml
|
||||||
|
|||||||
22
.idea/cmake.xml
generated
22
.idea/cmake.xml
generated
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CMakeSharedSettings">
|
|
||||||
<configurations>
|
|
||||||
<configuration PROFILE_NAME="Debug [32]" ENABLED="true" GENERATION_DIR="build/32" CONFIG_NAME="Debug" TOOLCHAIN_NAME="Visual Studio 2022 [x86]" GENERATION_OPTIONS="-G "Visual Studio 17 2022" -A Win32">
|
|
||||||
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
|
||||||
<envs>
|
|
||||||
<env name="VERSION_SUFFIX" value="-debug" />
|
|
||||||
</envs>
|
|
||||||
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
|
||||||
</configuration>
|
|
||||||
<configuration PROFILE_NAME="Debug [64]" ENABLED="true" GENERATION_DIR="build/64" CONFIG_NAME="Debug" TOOLCHAIN_NAME="Visual Studio 2022 [amd64]" GENERATION_OPTIONS="-G "Visual Studio 17 2022" -A x64">
|
|
||||||
<ADDITIONAL_GENERATION_ENVIRONMENT>
|
|
||||||
<envs>
|
|
||||||
<env name="VERSION_SUFFIX" value="-debug" />
|
|
||||||
</envs>
|
|
||||||
</ADDITIONAL_GENERATION_ENVIRONMENT>
|
|
||||||
</configuration>
|
|
||||||
<configuration PROFILE_NAME="Relase [64]" ENABLED="true" GENERATION_DIR="build/64/release" CONFIG_NAME="Release" TOOLCHAIN_NAME="Visual Studio 2022 [amd64]" GENERATION_OPTIONS="-G "Visual Studio 17 2022" -A x64" />
|
|
||||||
</configurations>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
7
.idea/vcs.xml
generated
7
.idea/vcs.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$/KoalaBox" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
project(SmokeAPI VERSION 1.0.0)
|
project(SmokeAPI VERSION 1.0.2)
|
||||||
|
|
||||||
include(KoalaBox/cmake/KoalaBox.cmake)
|
include(KoalaBox/cmake/KoalaBox.cmake)
|
||||||
|
|
||||||
@@ -53,11 +53,23 @@ set(
|
|||||||
src/steam_functions/steam_functions.hpp
|
src/steam_functions/steam_functions.hpp
|
||||||
src/steam_types/steam_types.hpp
|
src/steam_types/steam_types.hpp
|
||||||
src/steamclient_exports/steamclient.cpp
|
src/steamclient_exports/steamclient.cpp
|
||||||
src/vstdlib/vstdlib.cpp
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
${GENERATED_LINKER_EXPORTS}
|
${GENERATED_LINKER_EXPORTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
|
set(
|
||||||
|
SMOKE_API_SOURCES ${SMOKE_API_SOURCES}
|
||||||
|
src/koalageddon/vstdlib.cpp
|
||||||
|
src/koalageddon/steamclient.cpp
|
||||||
|
src/steamclient_virtuals/client_app_manager.cpp
|
||||||
|
src/steamclient_virtuals/client_apps.cpp
|
||||||
|
src/steamclient_virtuals/client_inventory.cpp
|
||||||
|
src/steamclient_virtuals/client_user.cpp
|
||||||
|
src/steamclient_virtuals/client_utils.cpp
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_library(SmokeAPI SHARED ${SMOKE_API_SOURCES} ${VERSION_RESOURCE})
|
add_library(SmokeAPI SHARED ${SMOKE_API_SOURCES} ${VERSION_RESOURCE})
|
||||||
|
|
||||||
configure_output_name(${ORIGINAL_DLL})
|
configure_output_name(${ORIGINAL_DLL})
|
||||||
@@ -65,3 +77,4 @@ configure_output_name(${ORIGINAL_DLL})
|
|||||||
configure_include_directories()
|
configure_include_directories()
|
||||||
|
|
||||||
target_link_libraries(SmokeAPI PRIVATE KoalaBox)
|
target_link_libraries(SmokeAPI PRIVATE KoalaBox)
|
||||||
|
|
||||||
|
|||||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: 1f09cc8e2e...d9b0d1a00b
10
README.md
10
README.md
@@ -12,7 +12,7 @@ ___
|
|||||||
|
|
||||||
📥 [Download the latest release](https://github.com/acidicoala/SmokeAPI/releases/latest)
|
📥 [Download the latest release](https://github.com/acidicoala/SmokeAPI/releases/latest)
|
||||||
|
|
||||||
💬 [Official forum topic]()
|
💬 [Official forum topic](https://cs.rin.ru/forum/viewtopic.php?p=2597932#p2597932)
|
||||||
|
|
||||||
## ℹ Introduction
|
## ℹ Introduction
|
||||||
|
|
||||||
@@ -87,6 +87,14 @@ SmokeAPI does not require any manual configuration. By default, it uses the most
|
|||||||
[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
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
[this document]: https://github.com/acidicoala/public-entitlements/blob/main/steam/v1/dlc.json
|
||||||
|
|
||||||
## 👋 Acknowledgements
|
## 👋 Acknowledgements
|
||||||
|
|
||||||
SmokeAPI makes use of the following open source projects:
|
SmokeAPI makes use of the following open source projects:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
58
src/koalageddon/steamclient.cpp
Normal file
58
src/koalageddon/steamclient.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include <smoke_api/smoke_api.hpp>
|
||||||
|
#include <steam_functions/steam_functions.hpp>
|
||||||
|
|
||||||
|
#include <koalabox/hook.hpp>
|
||||||
|
|
||||||
|
using namespace smoke_api;
|
||||||
|
|
||||||
|
|
||||||
|
DLL_EXPORT(void) Log_Interface(const char* interface_name, const char* function_name) {
|
||||||
|
try {
|
||||||
|
void**** parent_ebp;
|
||||||
|
|
||||||
|
__asm mov parent_ebp, ebp
|
||||||
|
|
||||||
|
auto* interface_address = (*parent_ebp)[2];
|
||||||
|
|
||||||
|
static Set<String> hooked_functions;
|
||||||
|
|
||||||
|
auto hook_function = [&](const auto hook_function, const String& name, const int ordinal) {
|
||||||
|
if (hooked_functions.contains(name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook::swap_virtual_func_or_throw(interface_address, name, ordinal, (FunctionAddress) (hook_function));
|
||||||
|
|
||||||
|
hooked_functions.insert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto compound_name = interface_name + String("::") + function_name;
|
||||||
|
|
||||||
|
#define HOOK(FUNC, ORDINAL) hook_function(FUNC, #FUNC, ORDINAL);
|
||||||
|
|
||||||
|
if (compound_name == "IClientAppManager::IsAppDlcInstalled") {
|
||||||
|
HOOK(IClientAppManager_IsAppDlcInstalled, 8)
|
||||||
|
} else if (compound_name == "IClientApps::GetDLCCount") {
|
||||||
|
HOOK(IClientApps_GetDLCCount, 8)
|
||||||
|
} else if (compound_name == "IClientApps::BGetDLCDataByIndex") {
|
||||||
|
HOOK(IClientApps_BGetDLCDataByIndex, 9)
|
||||||
|
} else if (compound_name == "IClientUser::IsSubscribedApp") {
|
||||||
|
HOOK(IClientUser_IsSubscribedApp, 0xB5)
|
||||||
|
} else if (util::strings_are_equal(interface_name, "IClientInventory")) {
|
||||||
|
if (util::strings_are_equal(function_name, "GetResultItems")) {
|
||||||
|
auto* function_address = interface_address[0x2]; // TODO: Un-hardcode
|
||||||
|
logger->debug("{} -> {}::{} @ {}", __func__, interface_name, function_name, function_address);
|
||||||
|
}
|
||||||
|
} else if (util::strings_are_equal(interface_name, "IClientUtils")) {
|
||||||
|
if (util::strings_are_equal(function_name, "GetAppID")) {
|
||||||
|
auto* function_address = interface_address[0x12]; // TODO: Un-hardcode
|
||||||
|
logger->debug("{} -> {}::{} @ {}", __func__, interface_name, function_name, function_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_ORIGINAL_FUNCTION(Log_Interface)
|
||||||
|
Log_Interface_o(interface_name, function_name);
|
||||||
|
} catch (const Exception& ex) {
|
||||||
|
logger->error("{} -> Error: {}", __func__, ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,15 +19,15 @@ VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) { // NOLINT(misc-unuse
|
|||||||
|
|
||||||
struct CallbackData {
|
struct CallbackData {
|
||||||
[[maybe_unused]] void* pad1[1];
|
[[maybe_unused]] void* pad1[1];
|
||||||
void* set_callback_name_address;
|
void* set_callback_name_address; // to_do: fetch online
|
||||||
[[maybe_unused]] void* pad15[15];
|
[[maybe_unused]] void* pad19[17];
|
||||||
void* callback_address;
|
void* callback_address; // to_do: fetch online
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CoroutineData {
|
struct CoroutineData {
|
||||||
CallbackData* callback_data;
|
CallbackData* callback_data; // to_do: fetch online
|
||||||
[[maybe_unused]] uint32_t pad3[3];
|
[[maybe_unused]] uint32_t pad4[3];
|
||||||
const char* callback_name;
|
const char* callback_name; // to_do: fetch online
|
||||||
};
|
};
|
||||||
|
|
||||||
VIRTUAL(void) set_callback_name(PARAMS(const char** p_name)) {
|
VIRTUAL(void) set_callback_name(PARAMS(const char** p_name)) {
|
||||||
@@ -2,13 +2,17 @@
|
|||||||
#include <steam_functions/steam_functions.hpp>
|
#include <steam_functions/steam_functions.hpp>
|
||||||
#include <build_config.h>
|
#include <build_config.h>
|
||||||
|
|
||||||
#include <koalabox/loader.hpp>
|
|
||||||
#include <koalabox/config_parser.hpp>
|
#include <koalabox/config_parser.hpp>
|
||||||
#include <koalabox/file_logger.hpp>
|
|
||||||
#include <koalabox/win_util.hpp>
|
|
||||||
#include <koalabox/hook.hpp>
|
|
||||||
#include <koalabox/dll_monitor.hpp>
|
#include <koalabox/dll_monitor.hpp>
|
||||||
|
#include <koalabox/file_logger.hpp>
|
||||||
|
#include <koalabox/hook.hpp>
|
||||||
|
#include <koalabox/loader.hpp>
|
||||||
|
#include <koalabox/win_util.hpp>
|
||||||
|
#ifndef _WIN64
|
||||||
|
#include <koalabox/patcher.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DETOUR_EX(FUNC, ADDRESS) hook::detour_or_warn(ADDRESS, #FUNC, reinterpret_cast<FunctionAddress>(FUNC));
|
||||||
#define DETOUR(FUNC) hook::detour_or_warn(original_library, #FUNC, reinterpret_cast<FunctionAddress>(FUNC));
|
#define DETOUR(FUNC) hook::detour_or_warn(original_library, #FUNC, reinterpret_cast<FunctionAddress>(FUNC));
|
||||||
|
|
||||||
namespace smoke_api {
|
namespace smoke_api {
|
||||||
@@ -47,14 +51,29 @@ namespace smoke_api {
|
|||||||
if (is_hook_mode) {
|
if (is_hook_mode) {
|
||||||
hook::init(true);
|
hook::init(true);
|
||||||
|
|
||||||
if (util::strings_are_equal(exe_name, "steam.exe")) { // target vstdlib_s.dll
|
if (util::strings_are_equal(exe_name, "steam.exe")) {
|
||||||
|
#ifndef _WIN64
|
||||||
logger->info("🐨 Detected Koalageddon mode 💥");
|
logger->info("🐨 Detected Koalageddon mode 💥");
|
||||||
|
|
||||||
dll_monitor::init(VSTDLIB_DLL, [](const HMODULE& library) {
|
dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& library, const String& name) {
|
||||||
original_library = library;
|
original_library = library; // TODO: Is this necessary?
|
||||||
|
|
||||||
DETOUR(Coroutine_Create)
|
if (name == VSTDLIB_DLL) {
|
||||||
|
// Family Sharing functions
|
||||||
|
DETOUR(Coroutine_Create)
|
||||||
|
} else if (name == STEAMCLIENT_DLL) {
|
||||||
|
// Unlocking functions
|
||||||
|
// TODO: Un-hardcode the pattern
|
||||||
|
const String pattern("55 8B EC 8B ?? ?? ?? ?? ?? 81 EC ?? ?? ?? ?? 53 FF 15");
|
||||||
|
auto Log_Interface_address = (FunctionAddress) patcher::find_pattern_address(
|
||||||
|
win_util::get_module_info(library), "Log_Interface", pattern
|
||||||
|
);
|
||||||
|
if (Log_Interface_address) {
|
||||||
|
DETOUR_EX(Log_Interface, Log_Interface_address)
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
} else if (config.hook_steamclient) { // target steamclient(64).dll
|
} else if (config.hook_steamclient) { // target steamclient(64).dll
|
||||||
logger->info("🪝 Detected hook mode for SteamClient");
|
logger->info("🪝 Detected hook mode for SteamClient");
|
||||||
|
|
||||||
@@ -116,8 +135,8 @@ namespace smoke_api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool should_unlock(uint32_t appId) {
|
bool should_unlock(uint32_t app_id) {
|
||||||
return config.unlock_all != config.override.contains(appId);
|
return config.unlock_all != config.override.contains(app_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,6 @@ namespace smoke_api {
|
|||||||
|
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
bool should_unlock(uint32_t appId);
|
bool should_unlock(uint32_t app_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ using namespace smoke_api;
|
|||||||
// ISteamApps
|
// ISteamApps
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps*, AppId_t appID) {
|
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps*, AppId_t appID) {
|
||||||
return steam_apps::IsSubscribedApp(__func__, appID);
|
return steam_apps::IsDlcUnlocked(__func__, 0, appID);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps*, AppId_t appID) {
|
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps*, AppId_t appID) {
|
||||||
return steam_apps::IsDlcInstalled(__func__, appID);
|
return steam_apps::IsDlcUnlocked(__func__, 0, appID);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps* self) {
|
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps* self) {
|
||||||
return steam_apps::GetDLCCount(__func__, [&]() {
|
return steam_apps::GetDLCCount(__func__, 0, [&]() {
|
||||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_GetDLCCount)
|
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_GetDLCCount)
|
||||||
|
|
||||||
return SteamAPI_ISteamApps_GetDLCCount_o(self);
|
return SteamAPI_ISteamApps_GetDLCCount_o(self);
|
||||||
@@ -29,7 +29,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
|
|||||||
char* pchName,
|
char* pchName,
|
||||||
int cchNameBufferSize
|
int cchNameBufferSize
|
||||||
) {
|
) {
|
||||||
return steam_apps::GetDLCDataByIndex(__func__, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
|
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
|
||||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_BGetDLCDataByIndex)
|
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_BGetDLCDataByIndex)
|
||||||
|
|
||||||
return SteamAPI_ISteamApps_BGetDLCDataByIndex_o(
|
return SteamAPI_ISteamApps_BGetDLCDataByIndex_o(
|
||||||
@@ -111,7 +111,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
|
|||||||
) {
|
) {
|
||||||
return steam_inventory::GetResultItemProperty(
|
return steam_inventory::GetResultItemProperty(
|
||||||
__func__, resultHandle, unItemIndex, pchPropertyName, pchValueBuffer, punValueBufferSizeOut, [&]() {
|
__func__, resultHandle, unItemIndex, pchPropertyName, pchValueBuffer, punValueBufferSizeOut, [&]() {
|
||||||
GET_ORIGINAL_VIRTUAL_FUNCTION(SteamAPI_ISteamInventory_GetResultItemProperty)
|
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetResultItemProperty)
|
||||||
|
|
||||||
return SteamAPI_ISteamInventory_GetResultItemProperty_o(
|
return SteamAPI_ISteamInventory_GetResultItemProperty_o(
|
||||||
self, resultHandle, unItemIndex, pchPropertyName, pchValueBuffer, punValueBufferSizeOut
|
self, resultHandle, unItemIndex, pchPropertyName, pchValueBuffer, punValueBufferSizeOut
|
||||||
@@ -126,7 +126,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
|
|||||||
CSteamID steamIDExpected
|
CSteamID steamIDExpected
|
||||||
) {
|
) {
|
||||||
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() {
|
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() {
|
||||||
GET_ORIGINAL_VIRTUAL_FUNCTION(SteamAPI_ISteamInventory_CheckResultSteamID)
|
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_CheckResultSteamID)
|
||||||
|
|
||||||
return SteamAPI_ISteamInventory_CheckResultSteamID_o(self, resultHandle, steamIDExpected);
|
return SteamAPI_ISteamInventory_CheckResultSteamID_o(self, resultHandle, steamIDExpected);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
using namespace smoke_api;
|
using namespace smoke_api;
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
|
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
|
||||||
return steam_apps::IsSubscribedApp(__func__, appID);
|
return steam_apps::IsDlcUnlocked(__func__, 0, appID);
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
|
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
|
||||||
return steam_apps::IsDlcInstalled(__func__, appID);
|
return steam_apps::IsDlcUnlocked(__func__, 0, appID);
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) {
|
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) {
|
||||||
return steam_apps::GetDLCCount(__func__, [&]() {
|
return steam_apps::GetDLCCount(__func__, 0, [&]() {
|
||||||
GET_ORIGINAL_VIRTUAL_FUNCTION(ISteamApps_GetDLCCount)
|
GET_ORIGINAL_VIRTUAL_FUNCTION(ISteamApps_GetDLCCount)
|
||||||
|
|
||||||
return ISteamApps_GetDLCCount_o(ARGS());
|
return ISteamApps_GetDLCCount_o(ARGS());
|
||||||
@@ -28,7 +28,7 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
|
|||||||
int cchNameBufferSize
|
int cchNameBufferSize
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return steam_apps::GetDLCDataByIndex(__func__, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
|
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
|
||||||
GET_ORIGINAL_VIRTUAL_FUNCTION(ISteamApps_BGetDLCDataByIndex)
|
GET_ORIGINAL_VIRTUAL_FUNCTION(ISteamApps_BGetDLCDataByIndex)
|
||||||
|
|
||||||
return ISteamApps_BGetDLCDataByIndex_o(
|
return ISteamApps_BGetDLCDataByIndex_o(
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace steam_functions {
|
|||||||
const auto version_number = stoi(version_string.substr(prefix.length()));
|
const auto version_number = stoi(version_string.substr(prefix.length()));
|
||||||
|
|
||||||
if (version_number < min_version) {
|
if (version_number < min_version) {
|
||||||
util::panic("Unsupported old version of {}: {}", version_string, version_number);
|
logger->warn("Legacy version of {}: {}", version_string, version_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_number > max_version) {
|
if (version_number > max_version) {
|
||||||
|
|||||||
@@ -118,9 +118,20 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionProperty(
|
|||||||
ISteamInventory*, SteamItemDef_t, const char*, char*, uint32_t*
|
ISteamInventory*, SteamItemDef_t, const char*, char*, uint32_t*
|
||||||
);
|
);
|
||||||
|
|
||||||
// vstdlib
|
// koalageddon
|
||||||
|
|
||||||
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data);
|
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data);
|
||||||
|
DLL_EXPORT(void) Log_Interface(const char* interface_name, const char* function_name);
|
||||||
|
|
||||||
|
// IClientApps
|
||||||
|
VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t));
|
||||||
|
VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(PARAMS(AppId_t, int, AppId_t*, bool*, char*, int));
|
||||||
|
|
||||||
|
// IClientAppManager
|
||||||
|
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t, AppId_t));
|
||||||
|
|
||||||
|
// IClientUser
|
||||||
|
VIRTUAL(bool) IClientUser_IsSubscribedApp(PARAMS(AppId_t));
|
||||||
|
|
||||||
namespace steam_functions {
|
namespace steam_functions {
|
||||||
using namespace koalabox;
|
using namespace koalabox;
|
||||||
|
|||||||
@@ -51,14 +51,15 @@ void save_to_cache(const String& app_id_str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetch_and_cache_dlcs() {
|
void fetch_and_cache_dlcs(AppId_t app_id) {
|
||||||
uint32_t app_id;
|
if (not app_id) {
|
||||||
try {
|
try {
|
||||||
app_id = steam_functions::get_app_id_or_throw();
|
app_id = steam_functions::get_app_id_or_throw();
|
||||||
logger->info("Detected App ID: {}", app_id);
|
logger->info("Detected App ID: {}", app_id);
|
||||||
} catch (const Exception& ex) {
|
} catch (const Exception& ex) {
|
||||||
logger->error("Failed to get app ID: {}", ex.what());
|
logger->error("Failed to get app ID: {}", ex.what());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto app_id_str = std::to_string(app_id);
|
const auto app_id_str = std::to_string(app_id);
|
||||||
@@ -131,29 +132,31 @@ void fetch_and_cache_dlcs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get_app_id_log(const AppId_t app_id) {
|
||||||
|
return app_id ? fmt::format("App ID: {}, ", app_id) : "";
|
||||||
|
}
|
||||||
|
|
||||||
namespace steam_apps{
|
namespace steam_apps {
|
||||||
|
|
||||||
bool IsSubscribedApp(const String& function_name, AppId_t appID) {
|
bool IsDlcUnlocked(const String& function_name, AppId_t app_id, AppId_t dlc_id) {
|
||||||
const auto subscribed = should_unlock(appID);
|
const auto app_id_unlocked = not app_id or should_unlock(app_id); // true if app_id == 0
|
||||||
|
const auto dlc_id_unlocked = should_unlock(dlc_id);
|
||||||
|
|
||||||
logger->info("{} -> App ID: {}, Subscribed: {}", function_name, appID, subscribed);
|
const auto installed = app_id_unlocked and dlc_id_unlocked;
|
||||||
|
|
||||||
return subscribed;
|
logger->info("{} -> {}DLC ID: {}, Unlocked: {}", function_name, get_app_id_log(app_id), dlc_id, installed);
|
||||||
}
|
|
||||||
|
|
||||||
bool IsDlcInstalled(const String& function_name, AppId_t appID) {
|
|
||||||
const auto installed = should_unlock(appID);
|
|
||||||
|
|
||||||
logger->info("{} -> App ID: {}, Installed: {}", function_name, appID, installed);
|
|
||||||
|
|
||||||
return installed;
|
return installed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetDLCCount(const String& function_name, const std::function<int()>& original_function) {
|
int GetDLCCount(const String& function_name, const AppId_t app_id, const std::function<int()>& original_function) {
|
||||||
static std::mutex section;
|
static std::mutex section;
|
||||||
std::lock_guard<std::mutex> guard(section);
|
std::lock_guard<std::mutex> guard(section);
|
||||||
|
|
||||||
|
if (app_id) {
|
||||||
|
logger->debug("{} -> App ID: {}", function_name, app_id);
|
||||||
|
}
|
||||||
|
|
||||||
// Compute count only once
|
// Compute count only once
|
||||||
static int total_count = [&]() {
|
static int total_count = [&]() {
|
||||||
original_dlc_count = original_function();
|
original_dlc_count = original_function();
|
||||||
@@ -171,7 +174,7 @@ namespace steam_apps{
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger->debug("Game has {} or more DLCs. Fetching DLCs from a web API.", max_dlc);
|
logger->debug("Game has {} or more DLCs. Fetching DLCs from a web API.", max_dlc);
|
||||||
fetch_and_cache_dlcs();
|
fetch_and_cache_dlcs(app_id);
|
||||||
|
|
||||||
const auto fetched_count = static_cast<int>(cached_dlcs.size());
|
const auto fetched_count = static_cast<int>(cached_dlcs.size());
|
||||||
logger->debug("{} -> Fetched/cached DLC count: {}", function_name, fetched_count);
|
logger->debug("{} -> Fetched/cached DLC count: {}", function_name, fetched_count);
|
||||||
@@ -186,8 +189,9 @@ namespace steam_apps{
|
|||||||
|
|
||||||
bool GetDLCDataByIndex(
|
bool GetDLCDataByIndex(
|
||||||
const String& function_name,
|
const String& function_name,
|
||||||
|
AppId_t app_id,
|
||||||
int iDLC,
|
int iDLC,
|
||||||
AppId_t* pAppID,
|
AppId_t* pDlcId,
|
||||||
bool* pbAvailable,
|
bool* pbAvailable,
|
||||||
char* pchName,
|
char* pchName,
|
||||||
int cchNameBufferSize,
|
int cchNameBufferSize,
|
||||||
@@ -195,13 +199,13 @@ namespace steam_apps{
|
|||||||
) {
|
) {
|
||||||
const auto print_dlc_info = [&](const String& tag) {
|
const auto print_dlc_info = [&](const String& tag) {
|
||||||
logger->info(
|
logger->info(
|
||||||
"{} -> [{}] index: {}, App ID: {}, available: {}, name: '{}'",
|
"{} -> [{}] {}index: {}, DLC ID: {}, available: {}, name: '{}'",
|
||||||
function_name, tag, iDLC, *pAppID, *pbAvailable, pchName
|
function_name, tag, get_app_id_log(app_id), iDLC, *pDlcId, *pbAvailable, pchName
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto fill_dlc_info = [&](const AppId_t id) {
|
const auto fill_dlc_info = [&](const AppId_t id) {
|
||||||
*pAppID = id;
|
*pDlcId = id;
|
||||||
*pbAvailable = should_unlock(id);
|
*pbAvailable = should_unlock(id);
|
||||||
|
|
||||||
auto name = fmt::format("DLC #{} with ID: {} ", iDLC, id);
|
auto name = fmt::format("DLC #{} with ID: {} ", iDLC, id);
|
||||||
@@ -216,8 +220,8 @@ namespace steam_apps{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto app_id = config.dlc_ids[index];
|
const auto dlc_id = config.dlc_ids[index];
|
||||||
fill_dlc_info(app_id);
|
fill_dlc_info(dlc_id);
|
||||||
print_dlc_info("injected");
|
print_dlc_info("injected");
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -229,7 +233,7 @@ namespace steam_apps{
|
|||||||
const auto success = original_function();
|
const auto success = original_function();
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
*pbAvailable = should_unlock(*pAppID);
|
*pbAvailable = should_unlock(*pDlcId);
|
||||||
print_dlc_info("original");
|
print_dlc_info("original");
|
||||||
} else {
|
} else {
|
||||||
logger->warn("{} -> original function failed for index: {}", function_name, iDLC);
|
logger->warn("{} -> original function failed for index: {}", function_name, iDLC);
|
||||||
@@ -254,8 +258,8 @@ namespace steam_apps{
|
|||||||
|
|
||||||
// Cached index
|
// Cached index
|
||||||
if (iDLC < cached_dlcs.size()) {
|
if (iDLC < cached_dlcs.size()) {
|
||||||
const auto app_id = cached_dlcs[iDLC];
|
const auto dlc_id = cached_dlcs[iDLC];
|
||||||
fill_dlc_info(app_id);
|
fill_dlc_info(dlc_id);
|
||||||
print_dlc_info("cached");
|
print_dlc_info("cached");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,15 @@ using namespace koalabox;
|
|||||||
|
|
||||||
namespace steam_apps {
|
namespace steam_apps {
|
||||||
|
|
||||||
bool IsSubscribedApp(const String& function_name, AppId_t appID);
|
bool IsDlcUnlocked(const String& function_name, AppId_t app_id, AppId_t dlc_id);
|
||||||
|
|
||||||
bool IsDlcInstalled(const String& function_name, AppId_t appID);
|
int GetDLCCount(const String& function_name, AppId_t app_id, const std::function<int()>& original_function);
|
||||||
|
|
||||||
int GetDLCCount(const String& function_name, const std::function<int()>& original_function);
|
|
||||||
|
|
||||||
bool GetDLCDataByIndex(
|
bool GetDLCDataByIndex(
|
||||||
const String& function_name,
|
const String& function_name,
|
||||||
|
AppId_t app_id,
|
||||||
int iDLC,
|
int iDLC,
|
||||||
AppId_t* pAppID,
|
AppId_t* pDlcId,
|
||||||
bool* pbAvailable,
|
bool* pbAvailable,
|
||||||
char* pchName,
|
char* pchName,
|
||||||
int cchNameBufferSize,
|
int cchNameBufferSize,
|
||||||
|
|||||||
13
src/steamclient_virtuals/client_app_manager.cpp
Normal file
13
src/steamclient_virtuals/client_app_manager.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include <smoke_api/smoke_api.hpp>
|
||||||
|
#include <steam_impl/steam_impl.hpp>
|
||||||
|
|
||||||
|
using namespace smoke_api;
|
||||||
|
|
||||||
|
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(
|
||||||
|
PARAMS( // NOLINT(misc-unused-parameters)
|
||||||
|
AppId_t app_id,
|
||||||
|
AppId_t dlc_id
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return steam_apps::IsDlcUnlocked(__func__, app_id, dlc_id);
|
||||||
|
}
|
||||||
31
src/steamclient_virtuals/client_apps.cpp
Normal file
31
src/steamclient_virtuals/client_apps.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <smoke_api/smoke_api.hpp>
|
||||||
|
#include <steam_impl/steam_impl.hpp>
|
||||||
|
|
||||||
|
using namespace smoke_api;
|
||||||
|
|
||||||
|
VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) {
|
||||||
|
return steam_apps::GetDLCCount(__func__, appId, [&]() {
|
||||||
|
GET_ORIGINAL_VIRTUAL_FUNCTION(IClientApps_GetDLCCount)
|
||||||
|
|
||||||
|
return IClientApps_GetDLCCount_o(ARGS(appId));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
|
||||||
|
PARAMS(
|
||||||
|
AppId_t appID,
|
||||||
|
int iDLC,
|
||||||
|
AppId_t* pDlcID,
|
||||||
|
bool* pbAvailable,
|
||||||
|
char* pchName,
|
||||||
|
int cchNameBufferSize
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return steam_apps::GetDLCDataByIndex(__func__, appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize, [&]() {
|
||||||
|
GET_ORIGINAL_VIRTUAL_FUNCTION(IClientApps_BGetDLCDataByIndex)
|
||||||
|
|
||||||
|
return IClientApps_BGetDLCDataByIndex_o(
|
||||||
|
ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
0
src/steamclient_virtuals/client_inventory.cpp
Normal file
0
src/steamclient_virtuals/client_inventory.cpp
Normal file
8
src/steamclient_virtuals/client_user.cpp
Normal file
8
src/steamclient_virtuals/client_user.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <smoke_api/smoke_api.hpp>
|
||||||
|
#include <steam_impl/steam_impl.hpp>
|
||||||
|
|
||||||
|
using namespace smoke_api;
|
||||||
|
|
||||||
|
VIRTUAL(bool) IClientUser_IsSubscribedApp(PARAMS(AppId_t app_id)) { // NOLINT(misc-unused-parameters)
|
||||||
|
return steam_apps::IsDlcUnlocked(__func__, 0, app_id);
|
||||||
|
}
|
||||||
0
src/steamclient_virtuals/client_utils.cpp
Normal file
0
src/steamclient_virtuals/client_utils.cpp
Normal file
Reference in New Issue
Block a user