Added ISteamHTTP

This commit is contained in:
acidicoala
2025-08-27 20:42:08 +05:00
parent 9f51349517
commit dfbd7d00d9
32 changed files with 737 additions and 783 deletions

View File

@@ -4,7 +4,7 @@ on: push
jobs:
ci:
name: CI
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@a053502132e51e936820f27b7c99316fdb62b3e4
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@50dba8cafc7ea9523f73be038c80f1eacd1b4f8c
permissions:
contents: write
with:

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.24)
project(SmokeAPI VERSION 3.0.0)
project(SmokeAPI VERSION 3.1.0)
include(KoalaBox/cmake/KoalaBox.cmake)
@@ -16,6 +16,8 @@ configure_build_config(extra_build_config)
set(SMOKE_API_STATIC_SOURCES
static/smoke_api/interfaces/steam_apps.hpp
static/smoke_api/interfaces/steam_apps.cpp
static/smoke_api/interfaces/steam_http.hpp
static/smoke_api/interfaces/steam_http.cpp
static/smoke_api/interfaces/steam_inventory.hpp
static/smoke_api/interfaces/steam_inventory.cpp
static/smoke_api/interfaces/steam_user.hpp
@@ -35,12 +37,11 @@ set(SMOKE_API_SOURCES
${SMOKE_API_STATIC_SOURCES}
src/steam_api/exports/steam_api.cpp
src/steam_api/exports/steam_api.hpp
src/steam_api/exports/steam_api_flat.cpp
src/steam_api/exports/steam_api_internal.cpp
src/steam_api/exports/steam_api_unversioned.cpp
src/steam_api/virtuals/isteamapps.cpp
src/steam_api/virtuals/isteamclient.cpp
src/steam_api/virtuals/isteamgameserver.cpp
src/steam_api/virtuals/isteamhttp.cpp
src/steam_api/virtuals/isteaminventory.cpp
src/steam_api/virtuals/isteamuser.cpp
src/steam_api/virtuals/steam_api_virtuals.hpp
@@ -48,7 +49,7 @@ set(SMOKE_API_SOURCES
src/steam_api/steam_client.cpp
src/steam_api/steam_interface.cpp
src/steam_api/steam_interface.hpp
src/steamclient.cpp
src/steamclient/steamclient.cpp
src/main.cpp
src/smoke_api.cpp
src/smoke_api.hpp
@@ -81,7 +82,8 @@ configure_version_resource(
)
target_include_directories(SmokeAPI PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_BINARY_DIR}")
"${CMAKE_CURRENT_BINARY_DIR}"
)
## https://github.com/batterycenter/embed
CPMAddPackage(

View File

@@ -114,6 +114,7 @@ To use it, simply place it next to the SmokeAPI DLL.
It will be read upon each launch of the game.
In the absence of the config file, default values specified below will be used.
The configuration file is expected to conform to the JSON standard.
All options within the config file are optional.
`logging`:: Toggles generation of a `SmokeAPI.log.log` file.
+
@@ -121,6 +122,12 @@ The configuration file is expected to conform to the JSON standard.
Type::: Boolean
Default::: `false`
`log_steam_http`:: Toggles logging of _SteamHTTP_ traffic.
+
[horizontal]
Type::: Boolean
Default::: `false`
`default_app_status`:: This option sets the default DLC unlocking behaviour.
+
[horizontal]
@@ -184,8 +191,9 @@ Default::: `{}`
[source,json]
----
{
"$version": 3,
"$version": 4,
"logging": true,
"log_steam_http": true,
"default_app_status": "unlocked",
"override_app_status": {
"1234": "original",
@@ -223,7 +231,7 @@ Some games that have a large number of DLCs begin ownership verification by quer
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 DLCs 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.
Unfortunately, even the web API does not solve all of our problems, because it will return only 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 `extra_dlcs` config option comes into play.
You can specify those missing DLC IDs there, and SmokeAPI will make them available to the game.

View File

@@ -1,7 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.0.0/res/SmokeAPI.schema.json",
"$version": 3,
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.0/res/SmokeAPI.schema.json",
"$version": 4,
"logging": true,
"log_steam_http": true,
"default_app_status": "unlocked",
"override_app_status": {},
"override_dlc_status": {},

View File

@@ -12,7 +12,7 @@
"$version": {
"type": "integer",
"minimum": 0,
"default": 3,
"default": 4,
"description": "A technical field reserved for tools like GUI config editors. Do not modify this value."
},
"logging": {
@@ -20,6 +20,11 @@
"default": false,
"description": "Toggles generation of a SmokeAPI.log.log file."
},
"log_steam_http": {
"type": "boolean",
"default": false,
"description": "Toggles logging of SteamHTTP traffic"
},
"default_app_status": {
"description": "Sets the default DLC unlocking behaviour.",
"default": "unlocked",
@@ -111,9 +116,10 @@
},
"examples": [
{
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/heads/master/res/SmokeAPI.schema.json",
"$version": 3,
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.0.0/res/SmokeAPI.schema.json",
"$version": 4,
"logging": true,
"log_steam_http": true,
"default_app_status": "unlocked",
"override_app_status": {
"1234": "original",

View File

@@ -56,6 +56,9 @@ namespace {
} else if(kb::str::eq(library_name, STEAMAPI_DLL)) {
KB_HOOK_DETOUR_MODULE(SteamAPI_RestartAppIfNecessary, module_handle);
KB_HOOK_DETOUR_MODULE(SteamAPI_Shutdown, module_handle);
// Note: It is not necessary to hook flat functions or interface accessors
// since the underlying interfaces will be hooked through steamclient.
}
}
);

View File

@@ -4,6 +4,7 @@
constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
constexpr auto STEAM_CLIENT = "SteamClient";
constexpr auto STEAM_HTTP = "STEAMHTTP_INTERFACE_VERSION";
constexpr auto STEAM_USER = "SteamUser";
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
constexpr auto STEAM_GAME_SERVER = "SteamGameServer";

View File

@@ -1,321 +0,0 @@
#include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_apps.hpp"
#include "smoke_api/interfaces/steam_inventory.hpp"
#include "smoke_api/interfaces/steam_user.hpp"
#include "steam_api/steam_client.hpp"
#include "steam_api/steam_interface.hpp"
// ISteamApps
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void* self, const AppId_t dlcID) {
try {
return smoke_api::steam_apps::IsDlcUnlocked(
__func__,
steam_interface::get_app_id(),
dlcID,
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_BIsSubscribedApp, self, dlcID)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(void* self, const AppId_t dlcID) {
try {
return smoke_api::steam_apps::IsDlcUnlocked(
__func__,
steam_interface::get_app_id(),
dlcID,
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_BIsDlcInstalled, self, dlcID)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(void* self) {
try {
return smoke_api::steam_apps::GetDLCCount(
__func__,
steam_interface::get_app_id(),
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_GetDLCCount, self)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return 0;
}
}
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
void* self,
const int iDLC,
AppId_t* pDlcID,
bool* pbAvailable,
char* pchName,
const int cchNameBufferSize
) {
try {
return smoke_api::steam_apps::GetDLCDataByIndex(
__func__,
steam_interface::get_app_id(),
iDLC,
pDlcID,
pbAvailable,
pchName,
cchNameBufferSize,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamApps_BGetDLCDataByIndex,
self,
iDLC,
pDlcID,
pbAvailable,
pchName,
cchNameBufferSize
),
[&](const AppId_t dlc_id) {
return SteamAPI_ISteamApps_BIsDlcInstalled(self, dlc_id);
}
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}
// ISteamClient
DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(
void* self,
const HSteamUser hSteamUser,
const HSteamPipe hSteamPipe,
const char* pchVersion
) {
try {
return steam_client::GetGenericInterface(
__func__,
pchVersion,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamClient_GetISteamGenericInterface,
self,
hSteamUser,
hSteamPipe,
pchVersion
)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return nullptr;
}
}
// ISteamInventory
DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(
void* self,
const SteamInventoryResult_t resultHandle
) {
return smoke_api::steam_inventory::GetResultStatus(
__func__,
resultHandle,
MODULE_CALL_CLOSURE(SteamAPI_ISteamInventory_GetResultStatus, self, resultHandle)
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
void* self,
SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize
) {
return smoke_api::steam_inventory::GetItemDefinitionIDs(
__func__,
pItemDefIDs,
punItemDefIDsArraySize,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamInventory_GetItemDefinitionIDs,
self,
pItemDefIDs,
punItemDefIDsArraySize
)
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
void* self,
const SteamInventoryResult_t resultHandle,
SteamItemDetails_t* pOutItemsArray,
uint32_t* punOutItemsArraySize
) {
return smoke_api::steam_inventory::GetResultItems(
__func__,
resultHandle,
pOutItemsArray,
punOutItemsArraySize,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamInventory_GetResultItems,
self,
resultHandle,
pOutItemsArray,
punOutItemsArraySize
),
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
MODULE_CALL(
SteamAPI_ISteamInventory_GetItemDefinitionIDs,
self,
pItemDefIDs,
punItemDefIDsArraySize
);
}
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
void* self,
const SteamInventoryResult_t resultHandle,
const uint32_t unItemIndex,
const char* pchPropertyName,
char* pchValueBuffer,
uint32_t* punValueBufferSizeOut
) {
return smoke_api::steam_inventory::GetResultItemProperty(
__func__,
resultHandle,
unItemIndex,
pchPropertyName,
pchValueBuffer,
punValueBufferSizeOut,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamInventory_GetResultItemProperty,
self,
resultHandle,
unItemIndex,
pchPropertyName,
pchValueBuffer,
punValueBufferSizeOut
)
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
void* self,
const SteamInventoryResult_t resultHandle,
const CSteamID steamIDExpected
) {
return smoke_api::steam_inventory::CheckResultSteamID(
__func__,
resultHandle,
steamIDExpected,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamInventory_CheckResultSteamID,
self,
resultHandle,
steamIDExpected
)
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(
void* self,
SteamInventoryResult_t* pResultHandle
) {
return smoke_api::steam_inventory::GetAllItems(
__func__,
pResultHandle,
MODULE_CALL_CLOSURE(SteamAPI_ISteamInventory_GetAllItems, self, pResultHandle)
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
void* self,
SteamInventoryResult_t* pResultHandle,
const SteamItemInstanceID_t* pInstanceIDs,
const uint32_t unCountInstanceIDs
) {
return smoke_api::steam_inventory::GetItemsByID(
__func__,
pResultHandle,
pInstanceIDs,
unCountInstanceIDs,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamInventory_GetItemsByID,
self,
pResultHandle,
pInstanceIDs,
unCountInstanceIDs
)
);
}
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
void* self,
const SteamInventoryResult_t resultHandle,
void* pOutBuffer,
uint32_t* punOutBufferSize
) {
return smoke_api::steam_inventory::SerializeResult(
__func__,
resultHandle,
pOutBuffer,
punOutBufferSize,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamInventory_SerializeResult,
self,
resultHandle,
pOutBuffer,
punOutBufferSize
)
);
}
// ISteamUser
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp(
void* self,
const CSteamID steamID,
const AppId_t dlcID
) {
try {
return smoke_api::steam_user::UserHasLicenseForApp(
__func__,
steam_interface::get_app_id(),
dlcID,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamUser_UserHasLicenseForApp,
self,
steamID,
dlcID
)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return k_EUserHasLicenseResultDoesNotHaveLicense;
}
}
// ISteamGameServer
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamGameServer_UserHasLicenseForApp(
void* self,
const CSteamID steamID,
const AppId_t dlcID
) {
try {
return smoke_api::steam_user::UserHasLicenseForApp(
__func__,
steam_interface::get_app_id(),
dlcID,
MODULE_CALL_CLOSURE(
SteamAPI_ISteamGameServer_UserHasLicenseForApp,
self,
steamID,
dlcID
)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return k_EUserHasLicenseResultDoesNotHaveLicense;
}
}

View File

@@ -1,22 +0,0 @@
#include "smoke_api.hpp"
#include "smoke_api/types.hpp"
#include "steam_api/steam_client.hpp"
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(
const HSteamUser hSteamUser,
const char* version
) {
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamInternal_FindOrCreateUserInterface, hSteamUser, version)
);
}
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char* version) {
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamInternal_CreateInterface, version)
);
}

View File

@@ -22,10 +22,14 @@ namespace {
if(not version_map.contains(version_prefix)) {
try {
const std::string rdata = kb::win::get_pe_section_data_or_throw(
const auto section = kb::win::get_pe_section_or_throw(
smoke_api::steamapi_module,
".rdata"
);
const auto rdata = std::string(
reinterpret_cast<const char*>(section.start_address),
section.size
);
const std::regex regex(version_prefix + "\\d{3}");
if(std::smatch match; std::regex_search(rdata, match, regex)) {
@@ -50,15 +54,7 @@ namespace {
}
}
DLL_EXPORT(void*) SteamClient() {
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamClient)
);
}
// TODO: Do we really need to proxy them?
DLL_EXPORT(void*) SteamApps() {
static auto version = get_versioned_interface(STEAM_APPS, "002");
@@ -70,13 +66,23 @@ DLL_EXPORT(void*) SteamApps() {
);
}
DLL_EXPORT(void*) SteamUser() {
static auto version = get_versioned_interface(STEAM_USER, "012");
DLL_EXPORT(void*) SteamClient() {
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamUser)
MODULE_CALL_CLOSURE(SteamClient)
);
}
DLL_EXPORT(void*) SteamHTTP() {
static auto version = get_versioned_interface(STEAM_HTTP, "003");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamHTTP)
);
}
@@ -89,3 +95,13 @@ DLL_EXPORT(void*) SteamInventory() {
MODULE_CALL_CLOSURE(SteamInventory)
);
}
DLL_EXPORT(void*) SteamUser() {
static auto version = get_versioned_interface(STEAM_USER, "012");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamUser)
);
}

View File

@@ -7,13 +7,18 @@ namespace steam_client {
const std::string& function_name,
const std::string& interface_version,
const std::function<void*()>& original_function
) {
auto* const interface = original_function();
) noexcept {
try {
auto* const interface = original_function();
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
steam_interface::hook_virtuals(interface, interface_version);
steam_interface::hook_virtuals(interface, interface_version);
return interface;
return interface;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: '{}' @ {}", function_name, interface_version, e.what());
return nullptr;
}
}
}

View File

@@ -7,5 +7,5 @@ namespace steam_client {
const std::string& function_name,
const std::string& interface_version,
const std::function<void*()>& original_function
);
) noexcept;
}

View File

@@ -25,11 +25,11 @@ namespace {
std::map<std::string, interface_data> get_virtual_hook_map() {
#define ENTRY(INTERFACE, FUNC) \
{ \
#FUNC, { \
#INTERFACE "_" #FUNC, reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
} \
}
{ \
#FUNC, { \
#INTERFACE "_" #FUNC, reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
} \
}
return {
{
@@ -56,6 +56,17 @@ namespace {
}
}
},
{
STEAM_HTTP,
interface_data{
.fallback_version = "STEAMHTTP_INTERFACE_VERSION003",
.entry_map = {
ENTRY(ISteamHTTP, GetHTTPResponseBodyData),
ENTRY(ISteamHTTP, GetHTTPStreamingResponseBodyData),
ENTRY(ISteamHTTP, SetHTTPRequestRawPostBody),
}
}
},
{
STEAM_USER,
interface_data{
@@ -129,7 +140,11 @@ namespace steam_interface {
static std::set<void*> processed_interfaces;
if(processed_interfaces.contains(interface)) {
LOG_DEBUG("Interface {} at {} has already been processed.", version_string, interface);
LOG_DEBUG(
"Interface '{}' at {} has already been processed.",
version_string,
interface
);
return;
}

View File

@@ -4,45 +4,30 @@
#include "steam_api/steam_interface.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp"
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(const AppId_t dlc_id)) {
try {
return smoke_api::steam_apps::IsDlcUnlocked(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamApps_BIsSubscribedApp, ARGS(dlc_id))
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(const AppId_t dlc_id)) noexcept {
return smoke_api::steam_apps::IsDlcUnlocked(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamApps_BIsSubscribedApp, ARGS(dlc_id))
);
}
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(const AppId_t dlc_id)) {
try {
return smoke_api::steam_apps::IsDlcUnlocked(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamApps_BIsDlcInstalled, ARGS(dlc_id))
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(const AppId_t dlc_id)) noexcept {
return smoke_api::steam_apps::IsDlcUnlocked(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamApps_BIsDlcInstalled, ARGS(dlc_id))
);
}
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) {
try {
return smoke_api::steam_apps::GetDLCCount(
__func__,
steam_interface::get_app_id(),
HOOKED_CALL_CLOSURE(ISteamApps_GetDLCCount, ARGS())
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return 0;
}
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) noexcept {
return smoke_api::steam_apps::GetDLCCount(
__func__,
steam_interface::get_app_id(),
HOOKED_CALL_CLOSURE(ISteamApps_GetDLCCount, ARGS())
);
}
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
@@ -53,26 +38,22 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
char* pchName,
const int cchNameBufferSize
)
) {
try {
return smoke_api::steam_apps::GetDLCDataByIndex(
__func__,
steam_interface::get_app_id(),
iDLC,
p_dlc_id,
pbAvailable,
pchName,
cchNameBufferSize,
HOOKED_CALL_CLOSURE(
ISteamApps_BGetDLCDataByIndex,
ARGS(iDLC, p_dlc_id, pbAvailable, pchName, cchNameBufferSize)
),
[&](const AppId_t dlc_id) {
return ISteamApps_BIsDlcInstalled(ARGS(dlc_id));
}
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
) noexcept {
return smoke_api::steam_apps::GetDLCDataByIndex(
__func__,
steam_interface::get_app_id(),
iDLC,
p_dlc_id,
pbAvailable,
pchName,
cchNameBufferSize,
HOOKED_CALL_CLOSURE(
ISteamApps_BGetDLCDataByIndex,
ARGS(iDLC, p_dlc_id, pbAvailable, pchName, cchNameBufferSize)
),
HOOKED_CALL_CLOSURE(
ISteamApps_BIsSubscribedApp,
ARGS(*p_dlc_id)
)
);
}

View File

@@ -9,17 +9,12 @@ VIRTUAL(void*) ISteamClient_GetISteamApps(
const HSteamPipe hSteamPipe,
const char* version
)
) {
try {
return steam_client::GetGenericInterface(
__func__,
version,
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamApps, ARGS(hSteamUser, hSteamPipe, version))
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return nullptr;
}
) noexcept {
return steam_client::GetGenericInterface(
__func__,
version,
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamApps, ARGS(hSteamUser, hSteamPipe, version))
);
}
VIRTUAL(void*) ISteamClient_GetISteamUser(
@@ -28,17 +23,12 @@ VIRTUAL(void*) ISteamClient_GetISteamUser(
const HSteamPipe hSteamPipe,
const char* version
)
) {
try {
return steam_client::GetGenericInterface(
__func__,
version,
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamUser, ARGS(hSteamUser, hSteamPipe, version))
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return nullptr;
}
) noexcept {
return steam_client::GetGenericInterface(
__func__,
version,
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamUser, ARGS(hSteamUser, hSteamPipe, version))
);
}
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
@@ -47,20 +37,15 @@ VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
HSteamPipe hSteamPipe,
const char* pchVersion
)
) {
try {
return steam_client::GetGenericInterface(
__func__,
pchVersion,
HOOKED_CALL_CLOSURE(
ISteamClient_GetISteamGenericInterface,
ARGS(hSteamUser, hSteamPipe, pchVersion)
)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return nullptr;
}
) noexcept {
return steam_client::GetGenericInterface(
__func__,
pchVersion,
HOOKED_CALL_CLOSURE(
ISteamClient_GetISteamGenericInterface,
ARGS(hSteamUser, hSteamPipe, pchVersion)
)
);
}
VIRTUAL(void*) ISteamClient_GetISteamInventory(
@@ -69,18 +54,13 @@ VIRTUAL(void*) ISteamClient_GetISteamInventory(
const HSteamPipe hSteamPipe,
const char* pchVersion
)
) {
try {
return steam_client::GetGenericInterface(
__func__,
pchVersion,
HOOKED_CALL_CLOSURE(
ISteamClient_GetISteamInventory,
ARGS(hSteamUser, hSteamPipe, pchVersion)
)
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return nullptr;
}
) noexcept {
return steam_client::GetGenericInterface(
__func__,
pchVersion,
HOOKED_CALL_CLOSURE(
ISteamClient_GetISteamInventory,
ARGS(hSteamUser, hSteamPipe, pchVersion)
)
);
}

View File

@@ -6,16 +6,11 @@
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
) {
try {
return smoke_api::steam_user::UserHasLicenseForApp(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamGameServer_UserHasLicenseForApp, ARGS(steamID, dlc_id))
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return k_EUserHasLicenseResultDoesNotHaveLicense;
}
) noexcept {
return smoke_api::steam_user::UserHasLicenseForApp(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamGameServer_UserHasLicenseForApp, ARGS(steamID, dlc_id))
);
}

View File

@@ -0,0 +1,66 @@
#include <koalabox/logger.hpp>
#include "smoke_api/interfaces/steam_http.hpp"
#include "steam_api/steam_interface.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp"
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(
PARAMS(
const HTTPRequestHandle hRequest,
const uint8_t* pBodyDataBuffer,
const uint32_t unBufferSize
)
) noexcept {
return smoke_api::steam_http::GetHTTPResponseBodyData(
__func__,
hRequest,
pBodyDataBuffer,
unBufferSize,
HOOKED_CALL_CLOSURE(
ISteamHTTP_GetHTTPResponseBodyData,
ARGS(hRequest, pBodyDataBuffer, unBufferSize)
)
);
}
VIRTUAL(bool) ISteamHTTP_GetHTTPStreamingResponseBodyData(
PARAMS(
const HTTPRequestHandle hRequest,
const uint32_t cOffset,
const uint8_t* pBodyDataBuffer,
const uint32_t unBufferSize
)
) noexcept {
return smoke_api::steam_http::GetHTTPStreamingResponseBodyData(
__func__,
hRequest,
cOffset,
pBodyDataBuffer,
unBufferSize,
HOOKED_CALL_CLOSURE(
ISteamHTTP_GetHTTPStreamingResponseBodyData,
ARGS(hRequest, cOffset, pBodyDataBuffer, unBufferSize)
)
);
}
VIRTUAL(bool) ISteamHTTP_SetHTTPRequestRawPostBody(
PARAMS(
const HTTPRequestHandle hRequest,
const char* pchContentType,
const uint8_t* pubBody,
const uint32_t unBodyLen
)
) noexcept {
return smoke_api::steam_http::SetHTTPRequestRawPostBody(
__func__,
hRequest,
pchContentType,
pubBody,
unBodyLen,
HOOKED_CALL_CLOSURE(
ISteamHTTP_SetHTTPRequestRawPostBody,
ARGS(hRequest, pchContentType, pubBody, unBodyLen)
)
);
}

View File

@@ -3,7 +3,7 @@
VIRTUAL(EResult) ISteamInventory_GetResultStatus(
PARAMS(const SteamInventoryResult_t resultHandle)
) {
) noexcept {
return smoke_api::steam_inventory::GetResultStatus(
__func__,
resultHandle,
@@ -17,7 +17,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItems(
SteamItemDetails_t* pOutItemsArray,
uint32_t* punOutItemsArraySize
)
) {
) noexcept {
return smoke_api::steam_inventory::GetResultItems(
__func__,
resultHandle,
@@ -44,7 +44,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
char* pchValueBuffer,
uint32_t* punValueBufferSizeOut
)
) {
) noexcept {
return smoke_api::steam_inventory::GetResultItemProperty(
__func__,
resultHandle,
@@ -65,7 +65,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
);
}
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) {
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) noexcept {
return smoke_api::steam_inventory::GetAllItems(
__func__,
pResultHandle,
@@ -79,7 +79,7 @@ VIRTUAL(bool) ISteamInventory_GetItemsByID(
const SteamItemInstanceID_t* pInstanceIDs,
const uint32_t unCountInstanceIDs
)
) {
) noexcept {
return smoke_api::steam_inventory::GetItemsByID(
__func__,
pResultHandle,
@@ -98,7 +98,7 @@ VIRTUAL(bool) ISteamInventory_SerializeResult(
void* pOutBuffer,
uint32_t* punOutBufferSize
)
) {
) noexcept {
return smoke_api::steam_inventory::SerializeResult(
__func__,
resultHandle,
@@ -116,7 +116,7 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
SteamItemDef_t*pItemDefIDs,
uint32_t* punItemDefIDsArraySize
)
) {
) noexcept {
return smoke_api::steam_inventory::GetItemDefinitionIDs(
__func__,
pItemDefIDs,
@@ -130,14 +130,11 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
PARAMS(const SteamInventoryResult_t resultHandle, CSteamID steamIDExpected)
) {
) noexcept {
return smoke_api::steam_inventory::CheckResultSteamID(
__func__,
resultHandle,
steamIDExpected,
HOOKED_CALL_CLOSURE(
ISteamInventory_CheckResultSteamID,
ARGS(resultHandle, steamIDExpected)
)
HOOKED_CALL_CLOSURE(ISteamInventory_CheckResultSteamID, ARGS(resultHandle, steamIDExpected))
);
}

View File

@@ -6,17 +6,11 @@
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
) {
try {
static const auto app_id = steam_interface::get_app_id();
return smoke_api::steam_user::UserHasLicenseForApp(
__func__,
app_id,
dlc_id,
HOOKED_CALL_CLOSURE(ISteamUser_UserHasLicenseForApp, ARGS(steamID, dlc_id))
);
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return k_EUserHasLicenseResultDoesNotHaveLicense;
}
) noexcept {
return smoke_api::steam_user::UserHasLicenseForApp(
__func__,
steam_interface::get_app_id(),
dlc_id,
HOOKED_CALL_CLOSURE(ISteamUser_UserHasLicenseForApp, ARGS(steamID, dlc_id))
);
}

View File

@@ -3,38 +3,60 @@
#include "smoke_api/types.hpp"
// ISteamApps
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t));
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t));
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS());
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*, int));
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t)) noexcept;
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t)) noexcept;
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) noexcept;
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*, int)) noexcept;
// ISteamClient
VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*));
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*));
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(PARAMS(HSteamUser, HSteamPipe, const char*));
VIRTUAL(void*) ISteamClient_GetISteamInventory(PARAMS(HSteamUser, HSteamPipe, const char*));
VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
PARAMS(HSteamUser, HSteamPipe, const char*)
) noexcept;
VIRTUAL(void*) ISteamClient_GetISteamInventory(
PARAMS(HSteamUser, HSteamPipe, const char*)
) noexcept;
// ISteamHTTP
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(
PARAMS(HTTPRequestHandle, const uint8_t*, uint32_t)
) noexcept;
VIRTUAL(bool) ISteamHTTP_GetHTTPStreamingResponseBodyData(
PARAMS(HTTPRequestHandle, uint32_t, const uint8_t*, uint32_t)
) noexcept;
VIRTUAL(bool) ISteamHTTP_SetHTTPRequestRawPostBody(
PARAMS(HTTPRequestHandle, const char*, const uint8_t*, uint32_t)
) noexcept;
// ISteamInventory
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t)) noexcept;
VIRTUAL(bool) ISteamInventory_GetResultItems(
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*) // @formatter:off
); // @formatter:on
) noexcept; // @formatter:on
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*) // @formatter:off
); // @formatter:on
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t*));
) noexcept; // @formatter:on
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t*)) noexcept;
VIRTUAL(bool) ISteamInventory_GetItemsByID(
PARAMS(SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t)
);
VIRTUAL(bool) ISteamInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t*));
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t*));
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID));
) noexcept;
VIRTUAL(bool) ISteamInventory_SerializeResult(
PARAMS(SteamInventoryResult_t, void*, uint32_t*)
) noexcept;
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t*)) noexcept;
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID)) noexcept;
// ISteamUser
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(
PARAMS(CSteamID, AppId_t)
) noexcept;
// ISteamGameServer
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
PARAMS(CSteamID, AppId_t)
);
) noexcept;

View File

@@ -1,8 +1,8 @@
#include "smoke_api/steamclient/steamclient.hpp"
#include "smoke_api.hpp"
#include "../smoke_api.hpp"
#include "smoke_api/types.hpp"
#include "steam_api/steam_client.hpp"
#include "../steam_api/steam_client.hpp"
/**
* SmokeAPI implementation

View File

@@ -23,8 +23,9 @@ namespace smoke_api::config {
)
struct Config {
uint32_t $version = 3;
uint32_t $version = 4;
bool logging = false;
bool log_steam_http = false;
AppStatus default_app_status = AppStatus::UNLOCKED;
std::map<std::string, AppStatus> override_app_status;
std::map<std::string, AppStatus> override_dlc_status;
@@ -32,7 +33,7 @@ namespace smoke_api::config {
bool auto_inject_inventory = true;
std::vector<uint32_t> extra_inventory_items;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
Config,
$version,
logging,

View File

@@ -85,7 +85,7 @@ namespace smoke_api::steam_apps {
const AppId_t app_id,
const AppId_t dlc_id,
const std::function<bool()>& original_function
) {
) noexcept {
try {
const auto unlocked = config::is_dlc_unlocked(
app_id,
@@ -103,7 +103,7 @@ namespace smoke_api::steam_apps {
return unlocked;
} catch(const std::exception& e) {
LOG_ERROR("Uncaught exception: {}", e.what());
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what());
return false;
}
}
@@ -112,7 +112,7 @@ namespace smoke_api::steam_apps {
const std::string& function_name,
const AppId_t app_id,
const std::function<int()>& original_function
) {
) noexcept {
try {
const auto total_count = [&](int count) {
LOG_INFO("{} -> Responding with DLC count: {}", function_name, count);
@@ -139,7 +139,7 @@ namespace smoke_api::steam_apps {
return total_count(static_cast<int>(app_dlcs[app_id].size()));
} catch(const std::exception& e) {
LOG_ERROR("Uncaught exception: {}", function_name, e.what());
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what());
return 0;
}
}
@@ -153,8 +153,8 @@ namespace smoke_api::steam_apps {
char* pchName,
const int cchNameBufferSize,
const std::function<bool()>& original_function,
const std::function<bool(AppId_t)>& is_originally_unlocked
) {
const std::function<bool()>& is_originally_unlocked
) noexcept {
try {
LOG_DEBUG("{} -> {}index: {:>3}", function_name, get_app_id_log(app_id), iDLC);
@@ -174,13 +174,7 @@ namespace smoke_api::steam_apps {
const auto output_dlc = [&](const DLC& dlc) {
// Fill the output pointers
*pDlcId = dlc.get_id();
*pbAvailable = config::is_dlc_unlocked(
app_id,
*pDlcId,
[&] {
return is_originally_unlocked(*pDlcId);
}
);
*pbAvailable = config::is_dlc_unlocked(app_id, *pDlcId, is_originally_unlocked);
auto name = dlc.get_name();
name = name.substr(0, cchNameBufferSize + 1);

View File

@@ -2,19 +2,21 @@
#include "smoke_api/types.hpp"
// TODO: Make them all noexcept
namespace smoke_api::steam_apps {
bool IsDlcUnlocked(
const std::string& function_name,
AppId_t app_id,
AppId_t dlc_id,
const std::function<bool()>& original_function
);
) noexcept;
int GetDLCCount(
const std::string& function_name,
AppId_t app_id,
const std::function<int()>& original_function
);
) noexcept;
bool GetDLCDataByIndex(
const std::string& function_name,
@@ -25,6 +27,6 @@ namespace smoke_api::steam_apps {
char* pchName,
int cchNameBufferSize,
const std::function<bool()>& original_function,
const std::function<bool(AppId_t)>& is_originally_unlocked
);
const std::function<bool()>& is_originally_unlocked
) noexcept;
}

View File

@@ -0,0 +1,115 @@
#include <koalabox/logger.hpp>
#include "smoke_api/interfaces/steam_http.hpp"
#include "smoke_api/config.hpp"
namespace smoke_api::steam_http {
bool GetHTTPResponseBodyData(
const std::string& function_name,
const HTTPRequestHandle hRequest,
const uint8_t* pBodyDataBuffer,
const uint32_t unBufferSize,
const std::function<bool()>& original_function
) noexcept {
try {
const auto result = original_function();
if(config::instance.log_steam_http) {
const std::string_view buffer =
pBodyDataBuffer && unBufferSize
? std::string_view(
reinterpret_cast<const char*>(pBodyDataBuffer),
unBufferSize
)
: "";
LOG_INFO(
"{} -> handle: {}, size: {}, buffer:\n{}",
function_name,
hRequest,
unBufferSize,
buffer
);
}
return result;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}
bool GetHTTPStreamingResponseBodyData(
const std::string& function_name,
const HTTPRequestHandle hRequest,
const uint32_t cOffset,
const uint8_t* pBodyDataBuffer,
const uint32_t unBufferSize,
const std::function<bool()>& original_function
) noexcept {
try {
const auto result = original_function();
if(config::instance.log_steam_http) {
const std::string_view buffer =
pBodyDataBuffer && unBufferSize
? std::string_view(
reinterpret_cast<const char*>(pBodyDataBuffer),
unBufferSize
)
: "";
LOG_INFO(
"{} -> handle: {}, offset: {}, size: {}, buffer:\n{}",
function_name,
hRequest,
cOffset,
unBufferSize,
buffer
);
}
return result;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}
bool SetHTTPRequestRawPostBody(
const std::string& function_name,
const HTTPRequestHandle hRequest,
const char* pchContentType,
const uint8_t* pubBody,
const uint32_t unBodyLen,
const std::function<bool()>& original_function
) noexcept {
try {
const auto result = original_function();
if(config::instance.log_steam_http) {
const std::string_view content_type =
pchContentType ? pchContentType : "smoke_api::N/A";
const std::string_view buffer =
pubBody && unBodyLen
? std::string_view(reinterpret_cast<const char*>(pubBody), unBodyLen)
: "";
LOG_INFO(
"{} -> handle: {}, content-type: {}, size: {}, buffer:\n{}",
function_name,
hRequest,
content_type,
unBodyLen,
buffer
);
}
return result;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "smoke_api/types.hpp"
namespace smoke_api::steam_http {
bool GetHTTPResponseBodyData(
const std::string& function_name,
HTTPRequestHandle hRequest,
const uint8_t* pBodyDataBuffer,
uint32_t unBufferSize,
const std::function<bool()>& original_function
) noexcept;
bool GetHTTPStreamingResponseBodyData(
const std::string& function_name,
HTTPRequestHandle hRequest,
uint32_t cOffset,
const uint8_t* pBodyDataBuffer,
uint32_t unBufferSize,
const std::function<bool()>& original_function
) noexcept;
bool SetHTTPRequestRawPostBody(
const std::string& function_name,
HTTPRequestHandle hRequest,
const char* pchContentType,
const uint8_t* pubBody,
uint32_t unBodyLen,
const std::function<bool()>& original_function
) noexcept;
}

View File

@@ -8,17 +8,22 @@ namespace smoke_api::steam_inventory {
const std::string& function_name,
const SteamInventoryResult_t resultHandle,
const std::function<EResult()>& original_function
) {
const auto status = original_function();
) noexcept {
try {
const auto status = original_function();
LOG_DEBUG(
"{} -> handle: {}, status: {}",
function_name,
resultHandle,
static_cast<int>(status)
);
LOG_DEBUG(
"{} -> handle: {}, status: {}",
function_name,
resultHandle,
static_cast<int>(status)
);
return status;
return status;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return EResult::k_EResultFail;
}
}
bool GetResultItems(
@@ -28,107 +33,112 @@ namespace smoke_api::steam_inventory {
uint32_t* punOutItemsArraySize,
const std::function<bool()>& original_function,
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
) {
static std::mutex section;
const std::lock_guard guard(section);
) noexcept {
try {
static std::mutex section;
const std::lock_guard guard(section);
const auto success = original_function();
const auto success = original_function();
auto print_item = [](const std::string& tag, const SteamItemDetails_t& item) {
LOG_DEBUG(
" [{}] definitionId: {}, itemId: {}, quantity: {}, flags: {}",
tag,
item.m_iDefinition,
item.m_itemId,
item.m_unQuantity,
item.m_unFlags
);
};
if(not success) {
LOG_DEBUG("{} -> original result is false", function_name);
return success;
}
if(punOutItemsArraySize == nullptr) {
LOG_ERROR("{} -> arraySize pointer is null", function_name);
return success;
}
LOG_DEBUG(
"{} -> handle: {}, pOutItemsArray: {}, arraySize: {}",
function_name,
resultHandle,
reinterpret_cast<void*>(pOutItemsArray),
*punOutItemsArraySize
);
static uint32_t original_count = 0;
const auto injected_count = config::instance.extra_inventory_items.size();
// Automatically get inventory items from steam
static std::vector<SteamItemDef_t> auto_inventory_items;
if(config::instance.auto_inject_inventory) {
static std::once_flag inventory_inject_flag;
std::call_once(
inventory_inject_flag,
[&] {
uint32_t count = 0;
if(get_item_definition_ids(nullptr, &count)) {
auto_inventory_items.resize(count);
get_item_definition_ids(auto_inventory_items.data(), &count);
}
}
);
}
const auto auto_injected_count = auto_inventory_items.size();
if(not pOutItemsArray) {
// If pOutItemsArray is NULL then we must set the array size.
original_count = *punOutItemsArraySize;
*punOutItemsArraySize += auto_injected_count + injected_count;
LOG_DEBUG(
"{} -> Original count: {}, Total count: {}",
function_name,
original_count,
*punOutItemsArraySize
);
} else {
// Otherwise, we modify the array
for(int i = 0; i < original_count; i++) {
print_item("original", pOutItemsArray[i]);
}
static auto new_item = [](SteamItemDef_t id) {
return SteamItemDetails_t{
.m_itemId = id,
.m_iDefinition = id,
.m_unQuantity = 1,
.m_unFlags = 0,
};
auto print_item = [](const std::string& tag, const SteamItemDetails_t& item) {
LOG_DEBUG(
" [{}] definitionId: {}, itemId: {}, quantity: {}, flags: {}",
tag,
item.m_iDefinition,
item.m_itemId,
item.m_unQuantity,
item.m_unFlags
);
};
for(int i = 0; i < auto_injected_count; i++) {
auto& item = pOutItemsArray[original_count + i];
const auto item_def_id = auto_inventory_items[i];
item = new_item(item_def_id);
print_item("auto-injected", item);
if(not success) {
LOG_DEBUG("{} -> original result is false", function_name);
return success;
}
for(int i = 0; i < injected_count; i++) {
auto& item = pOutItemsArray[original_count + auto_injected_count + i];
const auto item_def_id = config::instance.extra_inventory_items[i];
item = new_item(item_def_id);
print_item("injected", item);
if(punOutItemsArraySize == nullptr) {
LOG_ERROR("{} -> arraySize pointer is null", function_name);
return success;
}
LOG_DEBUG(
"{} -> handle: {}, pOutItemsArray: {}, arraySize: {}",
function_name,
resultHandle,
reinterpret_cast<void*>(pOutItemsArray),
*punOutItemsArraySize
);
static uint32_t original_count = 0;
const auto injected_count = config::instance.extra_inventory_items.size();
// Automatically get inventory items from steam
static std::vector<SteamItemDef_t> auto_inventory_items;
if(config::instance.auto_inject_inventory) {
static std::once_flag inventory_inject_flag;
std::call_once(
inventory_inject_flag,
[&] {
uint32_t count = 0;
if(get_item_definition_ids(nullptr, &count)) {
auto_inventory_items.resize(count);
get_item_definition_ids(auto_inventory_items.data(), &count);
}
}
);
}
const auto auto_injected_count = auto_inventory_items.size();
if(not pOutItemsArray) {
// If pOutItemsArray is NULL then we must set the array size.
original_count = *punOutItemsArraySize;
*punOutItemsArraySize += auto_injected_count + injected_count;
LOG_DEBUG(
"{} -> Original count: {}, Total count: {}",
function_name,
original_count,
*punOutItemsArraySize
);
} else {
// Otherwise, we modify the array
for(int i = 0; i < original_count; i++) {
print_item("original", pOutItemsArray[i]);
}
static auto new_item = [](SteamItemDef_t id) {
return SteamItemDetails_t{
.m_itemId = id,
.m_iDefinition = id,
.m_unQuantity = 1,
.m_unFlags = 0,
};
};
for(int i = 0; i < auto_injected_count; i++) {
auto& item = pOutItemsArray[original_count + i];
const auto item_def_id = auto_inventory_items[i];
item = new_item(item_def_id);
print_item("auto-injected", item);
}
for(int i = 0; i < injected_count; i++) {
auto& item = pOutItemsArray[original_count + auto_injected_count + i];
const auto item_def_id = config::instance.extra_inventory_items[i];
item = new_item(item_def_id);
print_item("injected", item);
}
}
return success;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
return success;
}
bool GetResultItemProperty(
@@ -139,47 +149,61 @@ namespace smoke_api::steam_inventory {
const char* pchValueBuffer,
const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function
) {
LOG_DEBUG(
"{} -> Handle: {}, Index: {}, Name: '{}'",
function_name,
resultHandle,
unItemIndex,
// can be empty, in which case steam responds with property list in csv format
pchPropertyName ? pchPropertyName : "nullptr"
);
) noexcept {
try {
LOG_DEBUG(
"{} -> Handle: {}, Index: {}, Name: '{}'",
function_name,
resultHandle,
unItemIndex,
// can be empty, in which case steam responds with property list in csv format
pchPropertyName ? pchPropertyName : "nullptr"
);
const auto success = original_function();
const auto success = original_function();
if(!success) {
LOG_WARN("{} -> Result is false", function_name);
if(!success) {
LOG_WARN("{} -> Result is false", function_name);
return false;
}
if(
pchValueBuffer && *pchValueBuffer &&
punValueBufferSizeOut && *punValueBufferSizeOut > 0
) {
LOG_DEBUG(
R"({} -> Buffer: "{}")",
function_name,
std::string(pchValueBuffer, *punValueBufferSizeOut - 1)
);
}
return success;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
if(
pchValueBuffer && *pchValueBuffer &&
punValueBufferSizeOut && *punValueBufferSizeOut > 0
) {
LOG_DEBUG(
R"({} -> Buffer: "{}")",
function_name,
std::string(pchValueBuffer, *punValueBufferSizeOut - 1)
);
}
return success;
}
bool GetAllItems(
const std::string& function_name,
const SteamInventoryResult_t* pResultHandle,
const std::function<bool()>& original_function
) {
const auto success = original_function();
) noexcept {
try {
const auto success = original_function();
LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle));
LOG_DEBUG(
"{} -> Handle: {}",
function_name,
reinterpret_cast<const void*>(pResultHandle)
);
return success;
return success;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
}
bool GetItemsByID(
@@ -188,18 +212,23 @@ namespace smoke_api::steam_inventory {
const SteamItemInstanceID_t* pInstanceIDs,
const uint32_t unCountInstanceIDs,
const std::function<bool()>& original_function
) {
const auto success = original_function();
) noexcept {
try {
const auto success = original_function();
LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle));
LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle));
if(success && pInstanceIDs != nullptr) {
for(int i = 0; i < unCountInstanceIDs; i++) {
LOG_DEBUG(" Index: {}, ItemId: {}", i, pInstanceIDs[i]);
if(success && pInstanceIDs != nullptr) {
for(int i = 0; i < unCountInstanceIDs; i++) {
LOG_DEBUG(" Index: {}, ItemId: {}", i, pInstanceIDs[i]);
}
}
}
return success;
return success;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
}
bool SerializeResult(
@@ -208,22 +237,27 @@ namespace smoke_api::steam_inventory {
void* pOutBuffer,
uint32_t* punOutBufferSize,
const std::function<bool()>& original_function
) {
const auto success = original_function();
) noexcept {
try {
const auto success = original_function();
if(pOutBuffer != nullptr) {
std::string buffer(static_cast<char*>(pOutBuffer), *punOutBufferSize);
LOG_DEBUG("{} -> Handle: {}, Buffer: '{}'", function_name, resultHandle, buffer);
} else {
LOG_DEBUG(
"{} -> Handle: {}, Size: '{}'",
function_name,
resultHandle,
*punOutBufferSize
);
if(pOutBuffer != nullptr) {
std::string buffer(static_cast<char*>(pOutBuffer), *punOutBufferSize);
LOG_DEBUG("{} -> Handle: {}, Buffer: '{}'", function_name, resultHandle, buffer);
} else {
LOG_DEBUG(
"{} -> Handle: {}, Size: '{}'",
function_name,
resultHandle,
*punOutBufferSize
);
}
return success;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
return success;
}
bool GetItemDefinitionIDs(
@@ -231,28 +265,33 @@ namespace smoke_api::steam_inventory {
const SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize,
const std::function<bool()>& original_function
) {
const auto success = original_function();
) noexcept {
try {
const auto success = original_function();
if(!success) {
LOG_WARN("{} -> Result is false", function_name);
if(!success) {
LOG_WARN("{} -> Result is false", function_name);
return false;
}
if(punItemDefIDsArraySize) {
LOG_DEBUG("{} -> Size: {}", function_name, *punItemDefIDsArraySize);
} else {
return success;
}
if(pItemDefIDs) { // Definitions were copied
for(int i = 0; i < *punItemDefIDsArraySize; i++) {
const auto& def = pItemDefIDs[i];
LOG_DEBUG(" Index: {}, ID: {}", i, def);
}
}
return success;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
if(punItemDefIDsArraySize) {
LOG_DEBUG("{} -> Size: {}", function_name, *punItemDefIDsArraySize);
} else {
return success;
}
if(pItemDefIDs) { // Definitions were copied
for(int i = 0; i < *punItemDefIDsArraySize; i++) {
const auto& def = pItemDefIDs[i];
LOG_DEBUG(" Index: {}, ID: {}", i, def);
}
}
return success;
}
bool CheckResultSteamID(
@@ -260,17 +299,22 @@ namespace smoke_api::steam_inventory {
SteamInventoryResult_t resultHandle,
CSteamID steamIDExpected,
const std::function<bool()>& original_function
) {
const auto result = original_function();
) noexcept {
try {
const auto result = original_function();
LOG_DEBUG(
"{} -> handle: {}, steamID: {}, original result: {}",
function_name,
resultHandle,
steamIDExpected,
result
);
LOG_DEBUG(
"{} -> handle: {}, steamID: {}, original result: {}",
function_name,
resultHandle,
steamIDExpected,
result
);
return true;
return true;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return false;
}
}
}

View File

@@ -7,7 +7,7 @@ namespace smoke_api::steam_inventory {
const std::string& function_name,
SteamInventoryResult_t resultHandle,
const std::function<EResult()>& original_function
);
) noexcept;
bool GetResultItems(
const std::string& function_name,
@@ -16,7 +16,7 @@ namespace smoke_api::steam_inventory {
uint32_t* punOutItemsArraySize,
const std::function<bool()>& original_function,
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
);
) noexcept;
bool GetResultItemProperty(
const std::string& function_name,
@@ -26,13 +26,13 @@ namespace smoke_api::steam_inventory {
const char* pchValueBuffer,
const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function
);
) noexcept;
bool GetAllItems(
const std::string& function_name,
const SteamInventoryResult_t* pResultHandle,
const std::function<bool()>& original_function
);
) noexcept;
bool GetItemsByID(
const std::string& function_name,
@@ -40,7 +40,7 @@ namespace smoke_api::steam_inventory {
const SteamItemInstanceID_t* pInstanceIDs,
uint32_t unCountInstanceIDs,
const std::function<bool()>& original_function
);
) noexcept;
bool SerializeResult(
const std::string& function_name,
@@ -48,19 +48,19 @@ namespace smoke_api::steam_inventory {
void* pOutBuffer,
uint32_t* punOutBufferSize,
const std::function<bool()>& original_function
);
) noexcept;
bool GetItemDefinitionIDs(
const std::string& function_name,
const SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize,
const std::function<bool()>& original_function
);
) noexcept;
bool CheckResultSteamID(
const std::string& function_name,
SteamInventoryResult_t resultHandle,
CSteamID steamIDExpected,
const std::function<bool()>& original_function
);
) noexcept;
}

View File

@@ -9,26 +9,31 @@ namespace smoke_api::steam_user {
const AppId_t appId,
const AppId_t dlcId,
const std::function<EUserHasLicenseForAppResult()>& original_function
) {
const auto result = original_function();
) noexcept {
try {
const auto result = original_function();
if(result == k_EUserHasLicenseResultNoAuth) {
LOG_WARN("{} -> App ID: {:>8}, Result: NoAuth", function_name, dlcId);
return result;
}
const auto has_license = config::is_dlc_unlocked(
appId,
dlcId,
[&] {
return result == k_EUserHasLicenseResultHasLicense;
if(result == k_EUserHasLicenseResultNoAuth) {
LOG_WARN("{} -> App ID: {:>8}, Result: NoAuth", function_name, dlcId);
return result;
}
);
LOG_INFO("{} -> App ID: {:>8}, HasLicense: {}", function_name, dlcId, has_license);
const auto has_license = config::is_dlc_unlocked(
appId,
dlcId,
[&] {
return result == k_EUserHasLicenseResultHasLicense;
}
);
return has_license
? k_EUserHasLicenseResultHasLicense
: k_EUserHasLicenseResultDoesNotHaveLicense;
LOG_INFO("{} -> App ID: {:>8}, HasLicense: {}", function_name, dlcId, has_license);
return has_license
? k_EUserHasLicenseResultHasLicense
: k_EUserHasLicenseResultDoesNotHaveLicense;
} catch(const std::exception& e) {
LOG_ERROR("{} -> Error: {}", function_name, e.what());
return k_EUserHasLicenseResultDoesNotHaveLicense;
}
}
}

View File

@@ -8,5 +8,5 @@ namespace smoke_api::steam_user {
AppId_t appId,
AppId_t dlcId,
const std::function<EUserHasLicenseForAppResult()>& original_function
);
) noexcept;
}

View File

@@ -14,11 +14,15 @@
// These macros are meant to be used for callbacks that should return original result
#define HOOKED_CALL(FUNC, ...) \
static const auto _##FUNC = KB_HOOK_GET_HOOKED_FN(FUNC); \
return _##FUNC(__VA_ARGS__)
static const auto _##FUNC = KB_HOOK_GET_HOOKED_FN(FUNC); \
return _##FUNC(__VA_ARGS__)
#define HOOKED_CALL_CLOSURE(FUNC, ...) \
[&] { HOOKED_CALL(FUNC, __VA_ARGS__); }
[&] { HOOKED_CALL(FUNC, __VA_ARGS__); }
#define HOOKED_CALL_RESULT(FUNC, ...) \
static const auto _##FUNC = KB_HOOK_GET_HOOKED_FN(FUNC); \
const auto result = _##FUNC(__VA_ARGS__)
/**
* By default, virtual functions are declared with __thiscall
@@ -55,12 +59,19 @@ return _##FUNC(__VA_ARGS__)
using AppId_t = uint32_t;
using HSteamPipe = uint32_t;
using EResult = uint32_t;
using HSteamUser = uint32_t;
using SteamInventoryResult_t = uint32_t;
using SteamItemInstanceID_t = uint64_t;
using SteamItemDef_t = uint32_t;
using CSteamID = uint64_t;
using HTTPRequestHandle = uint32_t;
enum class EResult {
k_EResultNone = 0,
k_EResultOK = 1,
k_EResultFail = 2,
// See all at steamclientpublic.h
};
struct SteamItemDetails_t {
SteamItemInstanceID_t m_itemId;
@@ -71,10 +82,12 @@ struct SteamItemDetails_t {
// results from UserHasLicenseForApp
enum EUserHasLicenseForAppResult {
k_EUserHasLicenseResultHasLicense = 0, // User has a license for specified app
k_EUserHasLicenseResultDoesNotHaveLicense = 1,
// User has a license for specified app
k_EUserHasLicenseResultHasLicense = 0,
// User does not have a license for the specified app
k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated
k_EUserHasLicenseResultDoesNotHaveLicense = 1,
// User has not been authenticated
k_EUserHasLicenseResultNoAuth = 2,
};
// These aliases exist solely to increase code readability
@@ -87,7 +100,7 @@ using DlcNameMap = std::map<DlcIdKey, DlcNameValue>;
struct App {
DlcNameMap dlcs;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(App, dlcs) // NOLINT(misc-const-correctness)
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(App, dlcs)
};
using AppDlcNameMap = std::map<AppIdKey, App>;
@@ -98,6 +111,8 @@ class DLC {
std::string name;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(DLC, appid, name)
explicit DLC() = default;
explicit DLC(std::string appid, std::string name) : appid{std::move(appid)},
@@ -115,8 +130,6 @@ public:
return name;
}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(DLC, appid, name)
static std::vector<DLC> get_dlcs_from_apps(const AppDlcNameMap& apps, AppId_t app_id);
static DlcNameMap get_dlc_map_from_vector(const std::vector<DLC>& dlcs);