Split static & shared lib

This commit is contained in:
acidicoala
2025-08-23 13:44:17 +05:00
parent b828ecc58a
commit dc086e40e0
48 changed files with 1048 additions and 1318 deletions

View File

@@ -0,0 +1,23 @@
#include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "smoke_api/config.hpp"
// TODO: Support in hook mode
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(const uint32_t unOwnAppID) {
if(smoke_api::config::instance.override_app_id != 0) {
LOG_DEBUG("{} -> {}. Preventing app restart", unOwnAppID, __func__);
return false;
}
// Note: Assumes proxy mode only
MODULE_CALL(SteamAPI_RestartAppIfNecessary, unOwnAppID);
}
// TODO: Support in hook mode
DLL_EXPORT(void) SteamAPI_Shutdown() {
LOG_INFO("{} -> Game requested shutdown", __func__);
// Note: Assumes proxy mode only
MODULE_CALL(SteamAPI_Shutdown);
}

View File

@@ -0,0 +1,296 @@
#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, 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, 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;
}
}

View File

@@ -0,0 +1,22 @@
#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

@@ -0,0 +1,92 @@
#include <regex>
#include <map>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <koalabox/win_util.hpp>
#include "smoke_api.hpp"
#include "steam_api/steam_client.hpp"
namespace {
namespace kb = koalabox;
/**
* Searches the `.rdata` section of the original dll for the full interface version string
* Results are cached for performance.
*/
std::string get_versioned_interface(
const std::string& version_prefix,
const std::string& fallback
) {
static std::map<std::string, std::string> version_map;
if(not version_map.contains(version_prefix)) {
try {
const std::string rdata = kb::win_util::get_pe_section_data_or_throw(
smoke_api::steamapi_module,
".rdata"
);
const std::regex regex(version_prefix + "\\d{3}");
if(std::smatch match; std::regex_search(rdata, match, regex)) {
version_map[version_prefix] = match[0];
return version_map[version_prefix];
}
throw kb::util::exception("No match found for '{}'", version_prefix);
} catch(const std::exception& ex) {
LOG_ERROR(
"Failed to get versioned interface: {}."
"Falling back to version {}",
ex.what(),
fallback
);
version_map[version_prefix] = version_prefix + fallback;
}
}
return version_map[version_prefix];
}
}
DLL_EXPORT(void*) SteamClient() {
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamClient)
);
}
DLL_EXPORT(void*) SteamApps() {
static auto version = get_versioned_interface(STEAM_APPS, "002");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamApps)
);
}
DLL_EXPORT(void*) SteamUser() {
static auto version = get_versioned_interface(STEAM_USER, "012");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamUser)
);
}
DLL_EXPORT(void*) SteamInventory() {
static auto version = get_versioned_interface(STEAM_INVENTORY, "001");
return steam_client::GetGenericInterface(
__func__,
version,
MODULE_CALL_CLOSURE(SteamInventory)
);
}

View File

@@ -0,0 +1,19 @@
#include <koalabox/logger.hpp>
#include "steam_api/steam_interface.hpp"
namespace steam_client {
void* GetGenericInterface(
const std::string& function_name,
const std::string& interface_version,
const std::function<void*()>& original_function
) {
auto* const interface = original_function();
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
steam_interface::hook_virtuals(interface, interface_version);
return interface;
}
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <functional>
namespace steam_client {
void* GetGenericInterface(
const std::string& function_name,
const std::string& interface_version,
const std::function<void*()>& original_function
);
}

View File

@@ -0,0 +1,168 @@
#include <ranges>
#include <set>
#include <battery/embed.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <koalabox/win_util.hpp>
#include "smoke_api.hpp"
#include "virtuals/steam_api_virtuals.hpp"
namespace {
struct interface_entry {
// function_name must match the function identifier to be able to call original functions
std::string function_name; // e.g. "ISteamClient_GetISteamApps"
uintptr_t function_address; // e.g. ISteamClient_GetISteamApps
};
struct interface_data {
std::string fallback_version; // e.g. "SteamClient021"
std::map<std::string, interface_entry> entry_map;
// e.g. {ENTRY(ISteamClient, GetISteamApps), ...}
};
std::map<std::string, interface_data> get_virtual_hook_map() {
#define ENTRY(INTERFACE, FUNC) \
{ \
#FUNC, { \
#INTERFACE "_" #FUNC, reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
} \
}
return {
{
STEAM_CLIENT,
interface_data{
.fallback_version = "SteamClient021",
.entry_map = {
ENTRY(ISteamClient, GetISteamApps),
ENTRY(ISteamClient, GetISteamUser),
ENTRY(ISteamClient, GetISteamGenericInterface),
ENTRY(ISteamClient, GetISteamInventory),
}
}
},
{
STEAM_APPS,
interface_data{
.fallback_version = "STEAMAPPS_INTERFACE_VERSION008",
.entry_map = {
ENTRY(ISteamApps, BIsSubscribedApp),
ENTRY(ISteamApps, BIsDlcInstalled),
ENTRY(ISteamApps, GetDLCCount),
ENTRY(ISteamApps, BGetDLCDataByIndex),
}
}
},
{
STEAM_USER,
interface_data{
.fallback_version = "SteamUser023",
.entry_map = {
ENTRY(ISteamUser, UserHasLicenseForApp),
}
}
},
{
STEAM_INVENTORY,
interface_data{
.fallback_version = "STEAMINVENTORY_INTERFACE_V003",
.entry_map = {
ENTRY(ISteamInventory, GetResultStatus),
ENTRY(ISteamInventory, GetResultItems),
ENTRY(ISteamInventory, CheckResultSteamID),
ENTRY(ISteamInventory, GetAllItems),
ENTRY(ISteamInventory, GetItemsByID),
ENTRY(ISteamInventory, SerializeResult),
ENTRY(ISteamInventory, GetItemDefinitionIDs),
}
}
},
};
}
nlohmann::json read_interface_lookup() {
const auto lookup_str = b::embed<"res/interface_lookup.json">().str();
return nlohmann::json::parse(lookup_str);
}
const nlohmann::json& find_lookup(
const std::string& interface_version,
const std::string& fallback_version
) {
static const auto lookup = read_interface_lookup();
if(lookup.contains(interface_version)) {
return lookup[interface_version];
}
LOG_WARN(
"Interface version '{}' not found in lookup map. Using fallback: '{}'",
interface_version,
fallback_version
);
return lookup[fallback_version];
}
}
namespace steam_interface {
namespace kb = koalabox;
AppId_t get_app_id_or_throw() {
const auto app_id_str = kb::win_util::get_env_var("SteamAppId");
return std::stoi(app_id_str);
}
AppId_t get_app_id() {
try {
static const auto app_id = get_app_id_or_throw();
return app_id;
} catch(const std::exception& e) {
LOG_ERROR("Failed to get app id: {}", e.what());
return 0;
}
}
void hook_virtuals(void* interface, const std::string& version_string) {
if(interface == nullptr) {
// Game has tried to use an interface before initializing steam api
return;
}
static std::set<void*> processed_interfaces;
if(processed_interfaces.contains(interface)) {
LOG_DEBUG("Interface {} at {} has already been processed.", version_string, interface);
return;
}
static std::mutex section;
const std::lock_guard guard(section);
static const auto virtual_hook_map = get_virtual_hook_map();
for(const auto& [prefix, data] : virtual_hook_map) {
if(version_string.starts_with(prefix)) {
const auto& lookup = find_lookup(version_string, data.fallback_version);
for(const auto& [function, entry] : data.entry_map) {
if(lookup.contains(function)) {
kb::hook::swap_virtual_func(
interface,
entry.function_name,
lookup[function],
entry.function_address
);
}
}
break;
}
}
processed_interfaces.insert(interface);
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "smoke_api/types.hpp"
namespace steam_interface {
AppId_t get_app_id_or_throw();
AppId_t get_app_id();
void hook_virtuals(void* interface, const std::string& version_string);
}

View File

@@ -0,0 +1,79 @@
#include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_apps.hpp"
#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_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(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(bool) ISteamApps_BGetDLCDataByIndex(
PARAMS(
const int iDLC,
AppId_t* p_dlc_id,
bool* pbAvailable,
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;
}
}

View File

@@ -0,0 +1,87 @@
#include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "steam_api/steam_client.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp"
VIRTUAL(void*) ISteamClient_GetISteamApps(
PARAMS(
const HSteamUser hSteamUser,
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;
}
}
VIRTUAL(void*) ISteamClient_GetISteamUser(
PARAMS(
const HSteamUser hSteamUser,
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;
}
}
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
PARAMS(
HSteamUser hSteamUser,
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;
}
}
VIRTUAL(void*) ISteamClient_GetISteamInventory(
PARAMS(
const HSteamUser hSteamUser,
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;
}
}

View File

@@ -0,0 +1,144 @@
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_inventory.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp"
VIRTUAL(EResult) ISteamInventory_GetResultStatus(
PARAMS(const SteamInventoryResult_t resultHandle)
) {
return smoke_api::steam_inventory::GetResultStatus(
__func__,
resultHandle,
HOOKED_CALL_CLOSURE(ISteamInventory_GetResultStatus, ARGS(resultHandle))
);
}
VIRTUAL(bool) ISteamInventory_GetResultItems(
PARAMS(
const SteamInventoryResult_t resultHandle,
SteamItemDetails_t* pOutItemsArray,
uint32_t* punOutItemsArraySize
)
) {
return smoke_api::steam_inventory::GetResultItems(
__func__,
resultHandle,
pOutItemsArray,
punOutItemsArraySize,
HOOKED_CALL_CLOSURE(
ISteamInventory_GetResultItems,
ARGS(resultHandle, pOutItemsArray, punOutItemsArraySize)
),
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
HOOKED_CALL(
ISteamInventory_GetItemDefinitionIDs,
ARGS(pItemDefIDs, punItemDefIDsArraySize)
);
}
);
}
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
PARAMS(
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,
HOOKED_CALL_CLOSURE(
ISteamInventory_GetResultItemProperty,
ARGS(
resultHandle,
unItemIndex,
pchPropertyName,
pchValueBuffer,
punValueBufferSizeOut
)
)
);
}
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) {
return smoke_api::steam_inventory::GetAllItems(
__func__,
pResultHandle,
HOOKED_CALL_CLOSURE(ISteamInventory_GetAllItems, ARGS(pResultHandle))
);
}
VIRTUAL(bool) ISteamInventory_GetItemsByID(
PARAMS(
SteamInventoryResult_t* pResultHandle,
const SteamItemInstanceID_t* pInstanceIDs,
const uint32_t unCountInstanceIDs
)
) {
return smoke_api::steam_inventory::GetItemsByID(
__func__,
pResultHandle,
pInstanceIDs,
unCountInstanceIDs,
HOOKED_CALL_CLOSURE(
ISteamInventory_GetItemsByID,
ARGS(pResultHandle, pInstanceIDs, unCountInstanceIDs)
)
);
}
VIRTUAL(bool) ISteamInventory_SerializeResult(
PARAMS(
const SteamInventoryResult_t resultHandle,
void* pOutBuffer,
uint32_t* punOutBufferSize
)
) {
return smoke_api::steam_inventory::SerializeResult(
__func__,
resultHandle,
pOutBuffer,
punOutBufferSize,
HOOKED_CALL_CLOSURE(
ISteamInventory_SerializeResult,
ARGS(resultHandle, pOutBuffer, punOutBufferSize)
)
);
}
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
PARAMS(
SteamItemDef_t*pItemDefIDs,
uint32_t* punItemDefIDsArraySize
)
) {
return smoke_api::steam_inventory::GetItemDefinitionIDs(
__func__,
pItemDefIDs,
punItemDefIDsArraySize,
HOOKED_CALL_CLOSURE(
ISteamInventory_GetItemDefinitionIDs,
ARGS(pItemDefIDs, punItemDefIDsArraySize)
)
);
}
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
PARAMS(SteamInventoryResult_t resultHandle, CSteamID steamIDExpected)
) {
return smoke_api::steam_inventory::CheckResultSteamID(
__func__,
resultHandle,
steamIDExpected,
HOOKED_CALL_CLOSURE(
ISteamInventory_CheckResultSteamID,
ARGS(resultHandle, steamIDExpected)
)
);
}

View File

@@ -0,0 +1,23 @@
#include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_user.hpp"
#include "steam_api/steam_interface.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp"
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;
}
}

View File

@@ -0,0 +1,70 @@
#pragma once
#include "smoke_api/types.hpp"
/**
* By default, virtual functions are declared with __thiscall
* convention, which is normal since they are class members.
* But it presents an issue for us, since we cannot pass *this
* pointer as a function argument. This is because *this
* pointer is passed via register ECX in __thiscall
* convention. Hence, to resolve this issue we declare our
* hooked functions with __fastcall convention, to trick
* the compiler into reading ECX & EDX registers as 1st
* and 2nd function arguments respectively. Similarly, __fastcall
* makes the compiler push the first argument into the ECX register,
* which mimics the __thiscall calling convention. Register EDX
* is not used anywhere in this case, but we still pass it along
* to conform to the __fastcall convention. This all applies
* to the x86 architecture.
*
* In x86-64 however, there is only one calling convention,
* so __fastcall is simply ignored. However, RDX in this case
* will store the 1st actual argument to the function, so we
* have to omit it from the function signature.
*
* The macros below implement the above-mentioned considerations.
*/
#ifdef _WIN64
#define PARAMS(...) void *RCX, __VA_ARGS__
#define ARGS(...) RCX, __VA_ARGS__
#define THIS RCX
#else
#define PARAMS(...) const void *ECX, const void *EDX, __VA_ARGS__
#define ARGS(...) ECX, EDX, __VA_ARGS__
#define THIS ECX
#endif
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall // NOLINT(*-macro-parentheses)
// 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));
// 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*));
// ISteamInventory
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
VIRTUAL(bool) ISteamInventory_GetResultItems(
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*) // @formatter:off
); // @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*));
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));
// ISteamUser
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));