master
acidicoala 1 year ago
parent 6347e3f148
commit ad1578f556
No known key found for this signature in database
GPG Key ID: D24C6065B49C645B

@ -35,6 +35,8 @@
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="0" />
<option name="BLANK_LINES_AROUND_CLASS" value="0" />
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="SOFT_MARGINS" value="120" />

@ -35,19 +35,21 @@ configure_build_config(extra_build_config)
set(
SMOKE_API_SOURCES
src/core/config.cpp
src/core/config.hpp
src/core/api.cpp
src/core/api.hpp
src/core/globals.cpp
src/core/globals.hpp
src/core/macros.hpp
src/core/paths.cpp
src/core/paths.hpp
src/core/types.cpp
src/core/types.hpp
src/smoke_api/smoke_api.cpp
src/smoke_api/smoke_api.hpp
src/smoke_api/app_cache.cpp
src/smoke_api/app_cache.hpp
src/smoke_api/config.cpp
src/smoke_api/config.hpp
src/smoke_api/smoke_api.cpp
src/smoke_api/smoke_api.hpp
src/steam_api_exports/steam_api_exports.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
@ -55,6 +57,7 @@ set(
src/steam_api_virtuals/isteamclient.cpp
src/steam_api_virtuals/isteaminventory.cpp
src/steam_api_virtuals/isteamuser.cpp
src/steam_api_virtuals/steam_api_virtuals.hpp
src/steam_impl/steam_apps.cpp
src/steam_impl/steam_apps.hpp
src/steam_impl/steam_client.cpp
@ -63,8 +66,8 @@ set(
src/steam_impl/steam_inventory.hpp
src/steam_impl/steam_user.cpp
src/steam_impl/steam_user.hpp
src/steam_functions/steam_functions.cpp
src/steam_functions/steam_functions.hpp
src/steam_impl/steam_impl.cpp
src/steam_impl/steam_impl.hpp
src/steamclient_exports/steamclient.cpp
src/main.cpp
${GENERATED_LINKER_EXPORTS}
@ -74,20 +77,18 @@ set(
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set(
SMOKE_API_SOURCES ${SMOKE_API_SOURCES}
src/koalageddon/cache.hpp
src/koalageddon/cache.cpp
src/koalageddon/kg_cache.hpp
src/koalageddon/kg_cache.cpp
src/koalageddon/koalageddon.hpp
src/koalageddon/koalageddon.cpp
src/koalageddon/steamclient.cpp
src/koalageddon/steamclient.hpp
src/koalageddon/types.hpp
src/koalageddon/vstdlib.cpp
src/koalageddon/vstdlib.hpp
# TODO: Move to koalageddon package
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/koalageddon/steamclient/client_app_manager.cpp
src/koalageddon/steamclient/client_apps.cpp
src/koalageddon/steamclient/client_inventory.cpp
src/koalageddon/steamclient/client_user.cpp
src/koalageddon/steamclient/steamclient.cpp
src/koalageddon/steamclient/steamclient.hpp
)
endif ()

@ -1 +1 @@
Subproject commit 960ad86f2c9327165c103be812af1e94930bd555
Subproject commit 2e6832007f2f2ba7c09141597ee97680febd77a2

@ -14,16 +14,14 @@
"16384": "original"
},
"extra_dlcs": {
"extra_dlcs": {
"1234": {
"dlcs": {
"56789": "Example DLC 1"
}
},
"4321": {
"dlcs": {
"98765": "Example DLC 2"
}
"1234": {
"dlcs": {
"56789": "Example DLC 1"
}
},
"4321": {
"dlcs": {
"98765": "Example DLC 2"
}
}
},

@ -0,0 +1,48 @@
#include <core/api.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/http_client.hpp>
namespace api {
struct SteamResponse {
uint32_t success = 0;
Vector<DLC> dlcs;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(SteamResponse, success, dlcs) // NOLINT(misc-const-correctness)
};
std::optional<Vector<DLC>> fetch_dlcs_from_github(AppId_t app_id) noexcept {
try {
const auto* url =
"https://raw.githubusercontent.com/acidicoala/public-entitlements/main/steam/v2/dlc.json";
const auto json = koalabox::http_client::fetch_json(url);
const auto response = json.get<AppDlcNameMap>();
return DLC::get_dlcs_from_apps(response, app_id);
} catch (const Json::exception& e) {
LOG_ERROR("Failed to fetch dlc list from GitHub: {}", e.what())
return std::nullopt;
}
}
std::optional<Vector<DLC>> fetch_dlcs_from_steam(AppId_t app_id) noexcept {
try {
const auto url = fmt::format("https://store.steampowered.com/dlc/{}/ajaxgetdlclist", app_id);
const auto json = koalabox::http_client::fetch_json(url);
LOG_TRACE("Steam response: \n{}", json.dump(2))
const auto response = json.get<SteamResponse>();
if (response.success != 1) {
throw std::runtime_error("Web API responded with 'success' != 1");
}
return response.dlcs;
} catch (const Exception& e) {
LOG_ERROR("Failed to fetch dlc list from Steam: {}", e.what())
return std::nullopt;
}
}
}

@ -0,0 +1,11 @@
#pragma once
#include <core/types.hpp>
namespace api {
std::optional<Vector<DLC>> fetch_dlcs_from_github(AppId_t app_id) noexcept;
std::optional<Vector<DLC>> fetch_dlcs_from_steam(AppId_t app_id) noexcept;
}

@ -1,58 +0,0 @@
#pragma once
#include <core/globals.hpp>
#include <koalabox/hook.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
// Names beginning with $ designate macros that are not meant to be used directly by the sources consuming this file
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
static const auto FUNC##_o = koalabox::hook::get_original_hooked_function(globals::address_map, #FUNC, FUNC);
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
static const auto FUNC##_o = koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC);
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
koalabox::hook::detour_or_warn(globals::address_map, ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
koalabox::hook::detour_or_warn(globals::address_map, MODULE_HANDLE, NAME, reinterpret_cast<uintptr_t>(FUNC));
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, #FUNC, globals::steamclient_module)
#define DETOUR_VSTDLIB(FUNC) $DETOUR(vstdlib::FUNC, #FUNC, globals::vstdlib_module)

@ -1,7 +1,63 @@
#pragma once
#include <koalabox/core.hpp>
#include <koalabox/hook.hpp>
#include <nlohmann/json.hpp>
#include <core/globals.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
// Names beginning with $ designate macros that are not meant to be used directly by the sources consuming this file
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
static const auto FUNC##_o = koalabox::hook::get_original_hooked_function(globals::address_map, #FUNC, FUNC);
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
static const auto FUNC##_o = koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC);
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
koalabox::hook::detour_or_warn(globals::address_map, ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
koalabox::hook::detour_or_warn(globals::address_map, MODULE_HANDLE, NAME, reinterpret_cast<uintptr_t>(FUNC));
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, #FUNC, globals::steamclient_module)
#define DETOUR_VSTDLIB(FUNC) $DETOUR(vstdlib::FUNC, #FUNC, globals::vstdlib_module)
#ifdef _WIN64
#define COMPILE_KOALAGEDDON 0
@ -9,6 +65,12 @@
#define COMPILE_KOALAGEDDON 1
#endif
constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
constexpr auto STEAM_CLIENT = "SteamClient";
constexpr auto STEAM_USER = "SteamUser";
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
constexpr auto CLIENT_ENGINE = "CLIENTENGINE_INTERFACE_VERSION";
using AppId_t = uint32_t;
using SteamInventoryResult_t = uint32_t;
using SteamItemInstanceID_t = uint64_t;
@ -33,11 +95,8 @@ enum EUserHasLicenseForAppResult {
};
class ISteamClient;
class ISteamApps;
class ISteamUser;
class ISteamInventory;
// These aliases exist solely to increase code readability

@ -1,10 +1,10 @@
#include <koalageddon/cache.hpp>
#include <koalageddon/kg_cache.hpp>
#include <koalabox/cache.hpp>
#include <koalabox/logger.hpp>
constexpr auto KEY_KG_CONFIG = "koalageddon_config";
namespace koalageddon::cache {
namespace koalageddon::kg_cache {
std::optional<KoalageddonConfig> get_koalageddon_config() {
try {

@ -1,8 +1,8 @@
#pragma once
#include <koalageddon/types.hpp>
#include <koalageddon/koalageddon.hpp>
namespace koalageddon::cache {
namespace koalageddon::kg_cache {
std::optional<KoalageddonConfig> get_koalageddon_config();

@ -1,9 +1,9 @@
#include <koalageddon/koalageddon.hpp>
#include <koalageddon/vstdlib.hpp>
#include <koalageddon/cache.hpp>
#include <koalageddon/kg_cache.hpp>
#include <build_config.h>
#include <core/config.hpp>
#include <steam_functions/steam_functions.hpp>
#include <smoke_api/config.hpp>
#include <steam_api_exports/steam_api_exports.hpp>
#include <koalabox/dll_monitor.hpp>
#include <koalabox/http_client.hpp>
#include <koalabox/logger.hpp>
@ -17,10 +17,10 @@ namespace koalageddon {
* @return A string representing the source of the config.
*/
String init_koalageddon_config() {
if (!config::instance.koalageddon_config.is_null()) {
if (!smoke_api::config::instance.koalageddon_config.is_null()) {
try {
// First try to read a local config override
config = config::instance.koalageddon_config.get<decltype(config)>();
config = smoke_api::config::instance.koalageddon_config.get<decltype(config)>();
return "local config override";
} catch (const Exception& ex) {
@ -33,7 +33,7 @@ namespace koalageddon {
const String url = "https://raw.githubusercontent.com/acidicoala/public-entitlements/main/koalageddon/v2/steam.json";
config = koalabox::http_client::fetch_json(url).get<decltype(config)>();
cache::save_koalageddon_config(config);
kg_cache::save_koalageddon_config(config);
return "GitHub repository";
} catch (const Exception& ex) {
@ -43,7 +43,7 @@ namespace koalageddon {
try {
// Then try to get a cached copy of a previously fetched config.
// We expect this unboxing to throw exception if no koalageddon config is present.
config = cache::get_koalageddon_config().value();
config = kg_cache::get_koalageddon_config().value();
return "disk cache";
} catch (const Exception& ex) {
@ -71,7 +71,7 @@ namespace koalageddon {
globals::vstdlib_module = module_handle;
if (config::instance.unlock_family_sharing) {
if (smoke_api::config::instance.unlock_family_sharing) {
DETOUR_VSTDLIB(Coroutine_Create)
}
} else if (name < equals > STEAMCLIENT_DLL) {
@ -87,8 +87,9 @@ namespace koalageddon {
}
} catch (const Exception& ex) {
LOG_ERROR(
"Koalageddon mode dll monitor process_interface_selector error. Module: '{}', Message: {}",
name, ex.what())
"Error listening to DLL load events. Module: '{}', Message: {}",
name, ex.what()
)
}
}
);

@ -1,8 +1,30 @@
#pragma once
#include <koalageddon/types.hpp>
#include <core/types.hpp>
namespace koalageddon {
// Offset values are interpreted according to pointer arithmetic rules, i.e.
// 1 unit offset represents 4 and 8 bytes in 32-bit and 64-bit architectures respectively.
struct KoalageddonConfig {
uint32_t client_engine_steam_client_internal_ordinal = 12;
uint32_t steam_client_internal_interface_selector_ordinal = 18;
uint32_t vstdlib_callback_address_offset = 20;
uint32_t vstdlib_callback_data_offset = 0;
uint32_t vstdlib_callback_interceptor_address_offset = 1;
uint32_t vstdlib_callback_name_offset = 4;
// We do not use *_WITH_DEFAULT macro to ensure that overriding
// the koalageddon config requires definition of all keys
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
KoalageddonConfig, // NOLINT(misc-const-correctness)
client_engine_steam_client_internal_ordinal,
steam_client_internal_interface_selector_ordinal,
vstdlib_callback_address_offset,
vstdlib_callback_data_offset,
vstdlib_callback_interceptor_address_offset,
vstdlib_callback_name_offset
)
};
/// We need this interface in other IClient* functions in order to query original DLC status
extern const void* client_app_manager_interface;

@ -1,7 +0,0 @@
#pragma once
namespace koalageddon::steamclient {
void process_client_engine(uintptr_t interface);
}

@ -1,7 +1,4 @@
#include <steam_impl/steam_apps.hpp>
#include <core/macros.hpp>
#include <core/types.hpp>
#include <steam_functions/steam_functions.hpp>
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) {
return steam_apps::IsDlcUnlocked(

@ -1,8 +1,6 @@
#include <core/macros.hpp>
#include <core/types.hpp>
#include <steam_impl/steam_apps.hpp>
#include <koalageddon/koalageddon.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalageddon/steamclient/steamclient.hpp>
VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) {
return steam_apps::GetDLCCount(

@ -1,7 +1,5 @@
#include <core/macros.hpp>
#include <core/types.hpp>
#include <koalageddon/steamclient/steamclient.hpp>
#include <steam_impl/steam_inventory.hpp>
#include <steam_functions/steam_functions.hpp>
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
return steam_inventory::GetResultStatus(

@ -1,4 +1,4 @@
#include <core/macros.hpp>
#include <koalageddon/steamclient/steamclient.hpp>
#include <steam_impl/steam_apps.hpp>
VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t app_id)) {

@ -1,8 +1,9 @@
#include <koalageddon/steamclient/steamclient.hpp>
#include <koalageddon/koalageddon.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <Zydis/Zydis.h>
#include <Zydis/DecoderTypes.h>
@ -85,9 +86,9 @@ namespace koalageddon::steamclient {
const auto& operand = instruction.operands[0];
return instruction.mnemonic == ZYDIS_MNEMONIC_PUSH &&
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operand.visibility == ZYDIS_OPERAND_VISIBILITY_EXPLICIT &&
operand.encoding == ZYDIS_OPERAND_ENCODING_SIMM16_32_32;
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operand.visibility == ZYDIS_OPERAND_VISIBILITY_EXPLICIT &&
operand.encoding == ZYDIS_OPERAND_ENCODING_SIMM16_32_32;
}
std::optional<String> get_string_argument(const ZydisDecodedInstruction& instruction) {
@ -141,9 +142,9 @@ namespace koalageddon::steamclient {
const auto is_mov_base_esp = [](const ZydisDecodedInstruction& instruction) {
return instruction.mnemonic == ZYDIS_MNEMONIC_MOV &&
instruction.operand_count == 2 &&
instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instruction.operands[1].reg.value == ZYDIS_REGISTER_ESP;
instruction.operand_count == 2 &&
instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instruction.operands[1].reg.value == ZYDIS_REGISTER_ESP;
};
// Initialize with a dummy previous instruction
@ -158,7 +159,7 @@ namespace koalageddon::steamclient {
&instruction
))) {
LOG_TRACE(
"{} visiting {} | {}", __func__,
"{} visiting {} {}", __func__,
(void*) current_address, *get_instruction_string(instruction, current_address)
)
@ -168,8 +169,8 @@ namespace koalageddon::steamclient {
// Save base register
context.base_register = instruction.operands[0].reg.value;
} else if (is_push_immediate(last_instruction) &&
is_push_immediate(instruction) &&
!context.function_name) {
is_push_immediate(instruction) &&
!context.function_name) {
// The very first 2 consecutive pushes indicate interface and function names.
// However, subsequent pushes may contain irrelevant strings.
const auto push_string_1 = get_string_argument(last_instruction);
@ -198,7 +199,7 @@ namespace koalageddon::steamclient {
// But not continue forward, in order to avoid duplicate processing
return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
// On unconditional jump we should recurse as well
const auto jump_destination = get_absolute_address(instruction, current_address);
@ -341,7 +342,7 @@ namespace koalageddon::steamclient {
))) {
visited_addresses.insert(current_address);
LOG_TRACE(
"{} visiting {} | {}", __func__,
"{} visiting {} {}", __func__,
(void*) current_address, *get_instruction_string(instruction, current_address)
)
@ -376,7 +377,7 @@ namespace koalageddon::steamclient {
LOG_TRACE("Breaking recursion due to conditional branch")
return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE
) {
const auto jump_destination = get_absolute_address(instruction, current_address);
@ -385,9 +386,9 @@ namespace koalageddon::steamclient {
LOG_TRACE("Breaking recursion due to unconditional branch")
return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
operand.type == ZYDIS_OPERAND_TYPE_MEMORY &&
operand.mem.scale == sizeof(uintptr_t) &&
operand.mem.disp.has_displacement
operand.type == ZYDIS_OPERAND_TYPE_MEMORY &&
operand.mem.scale == sizeof(uintptr_t) &&
operand.mem.disp.has_displacement
) {
// Special handling for jump tables. Guaranteed to be present in the interface selector.
const auto* table = (uintptr_t*) operand.mem.disp.value;

@ -0,0 +1,33 @@
#pragma once
#include <core/types.hpp>
// IClientAppManager
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t, AppId_t));
// IClientApps
VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t));
VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(PARAMS(AppId_t, int, AppId_t*, bool*, char*, int));
// IClientInventory
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
VIRTUAL(bool) IClientInventory_GetResultItems(
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t, uint32_t *)
);
VIRTUAL(bool) IClientInventory_GetResultItemProperty(
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t, uint32_t*)
);
VIRTUAL(bool) IClientInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID));
VIRTUAL(bool) IClientInventory_GetAllItems(PARAMS(SteamInventoryResult_t*));
VIRTUAL(bool) IClientInventory_GetItemsByID(PARAMS(SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t));
VIRTUAL(bool) IClientInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t, uint32_t *));
VIRTUAL(bool) IClientInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t, uint32_t *));
// IClientUser
VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t));
namespace koalageddon::steamclient {
void process_client_engine(uintptr_t interface);
}

@ -1,26 +0,0 @@
#pragma once
#include <koalabox/core.hpp>
// Offset values are interpreted according to pointer arithmetic rules, i.e.
// 1 unit offset represents 4 and 8 bytes in 32-bit and 64-bit architectures respectively.
struct KoalageddonConfig {
uint32_t client_engine_steam_client_internal_ordinal = 12;
uint32_t steam_client_internal_interface_selector_ordinal = 18;
uint32_t vstdlib_callback_address_offset = 20;
uint32_t vstdlib_callback_data_offset = 0;
uint32_t vstdlib_callback_interceptor_address_offset = 1;
uint32_t vstdlib_callback_name_offset = 4;
// We do not use *_WITH_DEFAULT macro to ensure that overriding
// the koalageddon config requires definition of all keys
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
KoalageddonConfig, // NOLINT(misc-const-correctness)
client_engine_steam_client_internal_ordinal,
steam_client_internal_interface_selector_ordinal,
vstdlib_callback_address_offset,
vstdlib_callback_data_offset,
vstdlib_callback_interceptor_address_offset,
vstdlib_callback_name_offset
)
};

@ -1,5 +1,4 @@
#include <koalageddon/vstdlib.hpp>
#include <core/macros.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>

@ -1,4 +1,3 @@
#include <core/macros.hpp>
#include <koalageddon/koalageddon.hpp>
namespace koalageddon::vstdlib {

@ -1,9 +1,9 @@
#include <core/config.hpp>
#include <smoke_api/config.hpp>
#include <core/paths.hpp>
#include <koalabox/util.hpp>
#include <koalabox/io.hpp>
namespace config {
namespace smoke_api::config {
Config instance; // NOLINT(cert-err58-cpp)
// TODO: Reloading via export

@ -3,8 +3,7 @@
#include <core/types.hpp>
#include <koalabox/core.hpp>
// TODO: move to smoke_api namespace
namespace config {
namespace smoke_api::config {
enum class AppStatus {
LOCKED,
UNLOCKED,

@ -1,9 +1,8 @@
#include <smoke_api/smoke_api.hpp>
#include <build_config.h>
#include <core/config.hpp>
#include <smoke_api/config.hpp>
#include <core/globals.hpp>
#include <core/paths.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/dll_monitor.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/hook.hpp>
@ -11,6 +10,7 @@
#include <koalabox/loader.hpp>
#include <koalabox/win_util.hpp>
#include <koalabox/util.hpp>
#include <steam_api_exports/steam_api_exports.hpp>
#if COMPILE_KOALAGEDDON
#include <koalageddon/koalageddon.hpp>

@ -0,0 +1,35 @@
#pragma once
#include <core/types.hpp>
// Flat
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps*, AppId_t);
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps*, AppId_t);
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps*);
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(ISteamApps*, int, AppId_t*, bool*, char*, int);
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp(ISteamUser*, CSteamID, AppId_t);
DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(ISteamClient*, HSteamUser, HSteamPipe, const char*);
DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(ISteamInventory*, SteamInventoryResult_t);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
ISteamInventory*, SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*
);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
ISteamInventory*, SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*
);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(ISteamInventory*, SteamInventoryResult_t, CSteamID);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(ISteamInventory*, SteamInventoryResult_t*);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
ISteamInventory*, SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t
);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(ISteamInventory*, SteamInventoryResult_t, void*, uint32_t*);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(ISteamInventory*, SteamItemDef_t*, uint32_t*);
// Internal
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser, const char*);
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char*);
// Unversioned
DLL_EXPORT(void*) CreateInterface(const char*, int*);
DLL_EXPORT(void*) SteamApps();
DLL_EXPORT(void*) SteamClient();
DLL_EXPORT(void*) SteamUser();

@ -1,12 +1,8 @@
#include <core/macros.hpp>
#include <core/types.hpp>
#include <steam_api_exports/steam_api_exports.hpp>
#include <steam_impl/steam_apps.hpp>
#include <steam_impl/steam_client.hpp>
#include <steam_impl/steam_inventory.hpp>
#include <steam_impl/steam_user.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace koalabox;
// ISteamApps

@ -1,9 +1,5 @@
#include <core/macros.hpp>
#include <core/types.hpp>
#include <steam_api_exports/steam_api_exports.hpp>
#include <steam_impl/steam_client.hpp>
#include <koalabox/hook.hpp>
using namespace koalabox;
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) {
return steam_client::GetGenericInterface(

@ -1,13 +1,10 @@
#include <steam_api_exports/steam_api_exports.hpp>
#include <steam_impl/steam_client.hpp>
#include <core/macros.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/win_util.hpp>
#include <koalabox/util.hpp>
#include <steam_functions/steam_functions.hpp>
#include <regex>
using namespace koalabox;
/**
* Searches the `.rdata` section of the original dll for the full interface version string
* Results are cached for performance.
@ -17,7 +14,7 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
if (not version_map.contains(version_prefix)) {
try {
const String rdata = win_util::get_pe_section_data_or_throw(globals::steamapi_module, ".rdata");
const String rdata = koalabox::win_util::get_pe_section_data_or_throw(globals::steamapi_module, ".rdata");
const std::regex regex(version_prefix + "\\d{3}");
std::smatch match;
@ -26,7 +23,7 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
return version_map[version_prefix];
}
throw util::exception("No match found for '{}'", version_prefix);
throw koalabox::util::exception("No match found for '{}'", version_prefix);
} catch (const Exception& ex) {
LOG_ERROR(
"Failed to get versioned interface: {}."
@ -41,7 +38,7 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
}
DLL_EXPORT(void*) SteamClient() {
static auto version = get_versioned_interface(steam_functions::STEAM_CLIENT, "006");
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
return steam_client::GetGenericInterface(
__func__, version, [&]() {
@ -53,7 +50,7 @@ DLL_EXPORT(void*) SteamClient() {
}
DLL_EXPORT(void*) SteamApps() {
static auto version = get_versioned_interface(steam_functions::STEAM_APPS, "002");
static auto version = get_versioned_interface(STEAM_APPS, "002");
return steam_client::GetGenericInterface(
__func__, version, [&]() {
@ -65,7 +62,7 @@ DLL_EXPORT(void*) SteamApps() {
}
DLL_EXPORT(void*) SteamUser() {
static auto version = get_versioned_interface(steam_functions::STEAM_USER, "012");
static auto version = get_versioned_interface(STEAM_USER, "012");
return steam_client::GetGenericInterface(
__func__, version, [&]() {
@ -77,7 +74,7 @@ DLL_EXPORT(void*) SteamUser() {
}
DLL_EXPORT(void*) SteamInventory() {
static auto version = get_versioned_interface(steam_functions::STEAM_INVENTORY, "001");
static auto version = get_versioned_interface(STEAM_INVENTORY, "001");
return steam_client::GetGenericInterface(
__func__, version, [&]() {

@ -1,5 +1,5 @@
#include <steam_api_virtuals/steam_api_virtuals.hpp>
#include <steam_impl/steam_apps.hpp>
#include <core/macros.hpp>
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) {
return steam_apps::IsDlcUnlocked(

@ -1,5 +1,5 @@
#include <steam_api_virtuals/steam_api_virtuals.hpp>
#include <steam_impl/steam_client.hpp>
#include <steam_functions/steam_functions.hpp>
VIRTUAL(void*) ISteamClient_GetISteamApps(
PARAMS(

@ -1,5 +1,5 @@
#include <steam_api_virtuals/steam_api_virtuals.hpp>
#include <steam_impl/steam_inventory.hpp>
#include <steam_functions/steam_functions.hpp>
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
return steam_inventory::GetResultStatus(

@ -1,5 +1,5 @@
#include <steam_api_virtuals/steam_api_virtuals.hpp>
#include <steam_impl/steam_user.hpp>
#include <steam_functions/steam_functions.hpp>
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID steamID, AppId_t appID)) {
return steam_user::UserHasLicenseForApp(

@ -0,0 +1,31 @@
#pragma once
#include <core/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));
// 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*));
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*)
);
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));

@ -1,102 +0,0 @@
#pragma once
#include <core/macros.hpp>
#include <core/types.hpp>
// TODO: Refactor into multiple headers
// 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*));
// 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));
// ISteamUser
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
// ISteamInventory
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
VIRTUAL(bool) ISteamInventory_GetResultItems(PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*));
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*)
);
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));
// API
DLL_EXPORT(void*) CreateInterface(const char*, int*);
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser, const char*);
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char*);
DLL_EXPORT(void*) SteamApps();
DLL_EXPORT(void*) SteamClient();
DLL_EXPORT(void*) SteamUser();
// Flat interfaces
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps*, AppId_t);
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps*, AppId_t);
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps*);
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(ISteamApps*, int, AppId_t*, bool*, char*, int);
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp(ISteamUser*, CSteamID, AppId_t);
DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(ISteamClient*, HSteamUser, HSteamPipe, const char*);
DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(ISteamInventory*, SteamInventoryResult_t);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
ISteamInventory*, SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*
);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
ISteamInventory*, SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*
);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(ISteamInventory*, SteamInventoryResult_t, CSteamID);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(ISteamInventory*, SteamInventoryResult_t*);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
ISteamInventory*, SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t
);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(ISteamInventory*, SteamInventoryResult_t, void*, uint32_t*);
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(ISteamInventory*, SteamItemDef_t*, uint32_t*);
// 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_BIsSubscribedApp(PARAMS(AppId_t));
// IClientInventory
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
VIRTUAL(bool) IClientInventory_GetResultItems(
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t, uint32_t *)
);
VIRTUAL(bool) IClientInventory_GetResultItemProperty(
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t, uint32_t*)
);
VIRTUAL(bool) IClientInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID));
VIRTUAL(bool) IClientInventory_GetAllItems(PARAMS(SteamInventoryResult_t*));
VIRTUAL(bool) IClientInventory_GetItemsByID(PARAMS(SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t));
VIRTUAL(bool) IClientInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t, uint32_t *));
VIRTUAL(bool) IClientInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t, uint32_t *));
namespace steam_functions {
using namespace koalabox;
const String STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION"; // NOLINT(cert-err58-cpp)
const String STEAM_CLIENT = "SteamClient"; // NOLINT(cert-err58-cpp)
const String STEAM_USER = "SteamUser"; // NOLINT(cert-err58-cpp)
const String STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V"; // NOLINT(cert-err58-cpp)
const String CLIENT_ENGINE = "CLIENTENGINE_INTERFACE_VERSION"; // NOLINT(cert-err58-cpp)
void hook_virtuals(void* interface, const String& version_string);
uint32_t get_app_id_or_throw();
}

@ -1,23 +1,13 @@
#include <steam_impl/steam_apps.hpp>
#include <koalabox/http_client.hpp>
#include <steam_impl/steam_impl.hpp>
#include <smoke_api/app_cache.hpp>
#include <core/config.hpp>
#include <smoke_api/config.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <steam_functions/steam_functions.hpp>
#include <core/types.hpp>
#include <utility>
#include <core/api.hpp>
namespace steam_apps {
// TODO: Needs to go to API
struct SteamResponse {
uint32_t success = 0;
Vector<DLC> dlcs;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(SteamResponse, success, dlcs) // NOLINT(misc-const-correctness)
};
/// Steamworks may max GetDLCCount value at 64, depending on how much unowned DLCs the user has.
/// Despite this limit, some games with more than 64 DLCs still keep using this method.
/// This means we have to get extra DLC IDs from local config, remote config, or cache.
@ -26,38 +16,8 @@ namespace steam_apps {
Map<AppId_t, Vector<DLC>> app_dlcs; // NOLINT(cert-err58-cpp)
Set<AppId_t> fully_fetched; // NOLINT(cert-err58-cpp)
std::optional<Vector<DLC>> fetch_from_github(AppId_t app_id) noexcept {
try {
const auto* url
= "https://raw.githubusercontent.com/acidicoala/public-entitlements/main/steam/v2/dlc.json";
const auto json = koalabox::http_client::fetch_json(url);
const auto response = json.get<AppDlcNameMap>();
return DLC::get_dlcs_from_apps(response, app_id);
} catch (const Json::exception& e) {
LOG_ERROR("Failed to fetch dlc list from GitHub: {}", e.what())
return std::nullopt;
}
}
std::optional<Vector<DLC>> fetch_from_steam(AppId_t app_id) noexcept {
try {
const auto url = fmt::format("https://store.steampowered.com/dlc/{}/ajaxgetdlclist", app_id);
const auto json = koalabox::http_client::fetch_json(url);
LOG_TRACE("Steam response: \n{}", json.dump(2))
const auto response = json.get<SteamResponse>();
if (response.success != 1) {
throw std::runtime_error("Web API responded with 'success' != 1");
}
return response.dlcs;
} catch (const Exception& e) {
LOG_ERROR("Failed to fetch dlc list from Steam: {}", e.what())
return std::nullopt;
}
String get_app_id_log(const AppId_t app_id) {
return app_id ? fmt::format("App ID: {:>8}, ", app_id) : "";
}
/**
@ -72,7 +32,7 @@ namespace steam_apps {
// No app id means we are operating in game mode.
// Hence, we need to use utility functions to get app id.
try {
app_id = steam_functions::get_app_id_or_throw();
app_id = steam_impl::get_app_id_or_throw();
LOG_INFO("Detected App ID: {}", app_id)
} catch (const Exception& ex) {
LOG_ERROR("Failed to get app ID: {}", ex.what())
@ -96,19 +56,19 @@ namespace steam_apps {
aggregated_dlcs < append > source;
};
append_dlcs(config::get_extra_dlcs(app_id), "local config");
append_dlcs(smoke_api::config::get_extra_dlcs(app_id), "local config");
const auto github_dlcs = fetch_from_github(app_id);
if (github_dlcs) {
append_dlcs(*github_dlcs, "GitHub repository");
const auto github_dlcs_opt = api::fetch_dlcs_from_github(app_id);
if (github_dlcs_opt) {
append_dlcs(*github_dlcs_opt, "GitHub repository");
}
const auto steam_dlcs = fetch_from_steam(app_id);
if (steam_dlcs) {
append_dlcs(*steam_dlcs, "Steam API");
const auto steam_dlcs_opt = api::fetch_dlcs_from_steam(app_id);
if (steam_dlcs_opt) {
append_dlcs(*steam_dlcs_opt, "Steam API");
}
if (github_dlcs && steam_dlcs) {
if (github_dlcs_opt && steam_dlcs_opt) {
fully_fetched.insert(app_id);
} else {
append_dlcs(smoke_api::app_cache::get_dlcs(app_id), "disk cache");
@ -121,10 +81,6 @@ namespace steam_apps {
smoke_api::app_cache::save_dlcs(app_id, aggregated_dlcs);
}
String get_app_id_log(const AppId_t app_id) {
return app_id ? fmt::format("App ID: {:>8}, ", app_id) : "";
}
bool IsDlcUnlocked(
const String& function_name,
AppId_t app_id,
@ -132,7 +88,7 @@ namespace steam_apps {
const Function<bool()>& original_function
) {
try {
const auto unlocked = config::is_dlc_unlocked(app_id, dlc_id, original_function);
const auto unlocked = smoke_api::config::is_dlc_unlocked(app_id, dlc_id, original_function);
LOG_INFO("{} -> {}DLC ID: {:>8}, Unlocked: {}", function_name, get_app_id_log(app_id), dlc_id, unlocked)
@ -196,7 +152,7 @@ namespace steam_apps {
const auto inject_dlc = [&](const DLC& dlc) {
// Fill the output pointers
*pDlcId = dlc.get_id();
*pbAvailable = config::is_dlc_unlocked(
*pbAvailable = smoke_api::config::is_dlc_unlocked(
app_id, *pDlcId, [&]() {
return is_originally_unlocked(*pDlcId);
}
@ -223,7 +179,9 @@ namespace steam_apps {
const auto success = original_function();
if (success) {
*pbAvailable = config::is_dlc_unlocked(app_id, *pDlcId, [&]() { return *pbAvailable; });
*pbAvailable = smoke_api::config::is_dlc_unlocked(
app_id, *pDlcId, [&]() { return *pbAvailable; }
);
print_dlc_info("original");
} else {
LOG_WARN("{} -> original call failed for index: {}", function_name, iDLC)

@ -1,7 +1,6 @@
#pragma once
#include <core/types.hpp>
#include <koalabox/core.hpp>
namespace steam_apps {

@ -1,6 +1,6 @@
#include <steam_impl/steam_client.hpp>
#include <steam_impl/steam_impl.hpp>
#include <koalabox/logger.hpp>
#include <steam_functions/steam_functions.hpp>
namespace steam_client {
@ -13,7 +13,7 @@ namespace steam_client {
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface)
steam_functions::hook_virtuals(interface, interface_version);
steam_impl::hook_virtuals(interface, interface_version);
return interface;
}

@ -1,6 +1,6 @@
#pragma once
#include <koalabox/core.hpp>
#include <core/types.hpp>
namespace steam_client {

@ -1,4 +1,7 @@
#include <steam_functions/steam_functions.hpp>
#include <steam_impl/steam_impl.hpp>
#include <steam_api_virtuals/steam_api_virtuals.hpp>
#include <steam_api_exports/steam_api_exports.hpp>
#include <core/globals.hpp>
#include <build_config.h>
#include <koalabox/hook.hpp>
#include <koalabox/win_util.hpp>
@ -7,10 +10,10 @@
#include <polyhook2/Misc.hpp>
#if COMPILE_KOALAGEDDON
#include <koalageddon/steamclient.hpp>
#include <koalageddon/steamclient/steamclient.hpp>
#endif
namespace steam_functions {
namespace steam_impl {
typedef Map<String, Map<int, int>> FunctionOrdinalMap;
@ -19,7 +22,7 @@ namespace steam_functions {
{
{6, 16},
{7, 18},
{8, 15},
{8, 15},
{9, 16},
{12, 15},
}
@ -105,7 +108,7 @@ namespace steam_functions {
return version_number;
} catch (const std::exception& ex) {
util::panic("Failed to extract version number from: '{}'", version_string);
koalabox::util::panic("Failed to extract version number from: '{}'", version_string);
}
}
@ -120,11 +123,11 @@ namespace steam_functions {
}
}
util::panic("Invalid interface version ({}) for function {}", interface_version, function_name);
koalabox::util::panic("Invalid interface version ({}) for function {}", interface_version, function_name);
}
#define HOOK_VIRTUALS(MAP, FUNC) \
hook::swap_virtual_func( \
koalabox::hook::swap_virtual_func( \
globals::address_map, \
interface, \
#FUNC, \
@ -209,14 +212,14 @@ namespace steam_functions {
}
HSteamPipe get_steam_pipe_or_throw() {
const auto& steam_api_module = win_util::get_module_handle_or_throw(STEAMAPI_DLL);
const auto& steam_api_module = koalabox::win_util::get_module_handle_or_throw(STEAMAPI_DLL);
void* GetHSteamPipe_address;
try {
GetHSteamPipe_address = (void*) win_util::get_proc_address_or_throw(
GetHSteamPipe_address = (void*) koalabox::win_util::get_proc_address_or_throw(
steam_api_module, "SteamAPI_GetHSteamPipe"
);
} catch (const Exception& ex) {
GetHSteamPipe_address = (void*) win_util::get_proc_address_or_throw(
GetHSteamPipe_address = (void*) koalabox::win_util::get_proc_address_or_throw(
steam_api_module, "GetHSteamPipe"
);
}
@ -245,8 +248,8 @@ namespace steam_functions {
AppId_t get_app_id_or_throw() {
// Get CreateInterface
const auto& steam_client_module = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL);
auto* CreateInterface_address = (void*) win_util::get_proc_address_or_throw(
const auto& steam_client_module = koalabox::win_util::get_module_handle_or_throw(STEAMCLIENT_DLL);
auto* CreateInterface_address = (void*) koalabox::win_util::get_proc_address_or_throw(
steam_client_module, "CreateInterface"
);
auto* CreateInterface_o = PLH::FnCast(CreateInterface_address, CreateInterface);
@ -255,7 +258,7 @@ namespace steam_functions {
int result;
auto* i_steam_client = CreateInterface_o("SteamClient006", &result);
if (i_steam_client == nullptr) {
throw util::exception("Failed to obtain SteamClient006 interface. Result: {}", result);
throw koalabox::util::exception("Failed to obtain SteamClient006 interface. Result: {}", result);
}
// Get GetISteamUtils

@ -0,0 +1,11 @@
#pragma once
#include <core/types.hpp>
namespace steam_impl {
void hook_virtuals(void* interface, const String& version_string);
uint32_t get_app_id_or_throw();
}

@ -1,5 +1,5 @@
#include <steam_impl/steam_inventory.hpp>
#include <core/config.hpp>
#include <smoke_api/config.hpp>
#include <koalabox/logger.hpp>
namespace steam_inventory {
@ -53,11 +53,11 @@ namespace steam_inventory {
)
static uint32_t original_count = 0;
const auto injected_count = config::instance.extra_inventory_items.size();
const auto injected_count = smoke_api::config::instance.extra_inventory_items.size();
// Automatically get inventory items from steam
static Vector<SteamItemDef_t> auto_inventory_items;
if (config::instance.auto_inject_inventory) {
if (smoke_api::config::instance.auto_inject_inventory) {
CALL_ONCE({
uint32_t count = 0;
if (get_item_definition_ids(nullptr, &count)) {
@ -103,7 +103,7 @@ namespace steam_inventory {
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];
const auto item_def_id = smoke_api::config::instance.extra_inventory_items[i];
item = new_item(item_def_id);

@ -1,5 +1,5 @@
#include <steam_impl/steam_user.hpp>
#include <core/config.hpp>
#include <smoke_api/config.hpp>
#include <koalabox/logger.hpp>
namespace steam_user {
@ -16,7 +16,7 @@ namespace steam_user {
return result;
}
const auto has_license = config::is_dlc_unlocked(
const auto has_license = smoke_api::config::is_dlc_unlocked(
0, appID, [&]() {
return result == k_EUserHasLicenseResultHasLicense;
}

@ -1,4 +1,3 @@
#include <core/macros.hpp>
#include <steam_impl/steam_client.hpp>
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) {

Loading…
Cancel
Save