mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2025-12-06 05:25:43 -05:00
Reworked algorithm for finding App ID
This commit is contained in:
@@ -39,7 +39,6 @@ set(SMOKE_API_SOURCES
|
|||||||
src/steam_api/virtuals/isteamhttp.cpp
|
src/steam_api/virtuals/isteamhttp.cpp
|
||||||
src/steam_api/virtuals/isteaminventory.cpp
|
src/steam_api/virtuals/isteaminventory.cpp
|
||||||
src/steam_api/virtuals/isteamuser.cpp
|
src/steam_api/virtuals/isteamuser.cpp
|
||||||
src/steam_api/virtuals/isteamutils.cpp
|
|
||||||
src/steam_api/virtuals/steam_api_virtuals.hpp
|
src/steam_api/virtuals/steam_api_virtuals.hpp
|
||||||
src/steam_api/steam_client.hpp
|
src/steam_api/steam_client.hpp
|
||||||
src/steam_api/steam_client.cpp
|
src/steam_api/steam_client.cpp
|
||||||
|
|||||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: 017dfda8db...d6afc170cc
@@ -114,6 +114,50 @@ namespace {
|
|||||||
void init_lib_monitor() {
|
void init_lib_monitor() {
|
||||||
kb::lib_monitor::init_listener({{STEAMCLIENT_DLL, on_steamclient_loaded}});
|
kb::lib_monitor::init_listener({{STEAMCLIENT_DLL, on_steamclient_loaded}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<AppId_t> get_app_id_from_env() noexcept {
|
||||||
|
if(const auto app_id_str = kb::util::get_env("SteamAppId")) {
|
||||||
|
try {
|
||||||
|
const auto app_id = std::stoi(*app_id_str);
|
||||||
|
|
||||||
|
LOG_DEBUG("Found AppID from environment: {}", app_id);
|
||||||
|
return app_id;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("Failed to parse AppID '{}' from environment: {}", *app_id_str, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<AppId_t> get_app_id_from_steam_client() noexcept {
|
||||||
|
try {
|
||||||
|
DECLARE_ARGS();
|
||||||
|
|
||||||
|
const auto& version_map = steam_interfaces::get_interface_name_to_version_map();
|
||||||
|
if((THIS = CreateInterface(version_map.at("ISteamClient").c_str(), nullptr))) {
|
||||||
|
if(const auto get_steam_utils = SMK_FIND_INTERFACE_FUNC(THIS, ISteamClient, GetISteamUtils)) {
|
||||||
|
constexpr auto steam_pipe = 1;
|
||||||
|
const auto& utils_version = version_map.at("ISteamUtils");
|
||||||
|
if((THIS = get_steam_utils(ARGS(steam_pipe, utils_version.c_str())))) {
|
||||||
|
if(const auto get_app_id = SMK_FIND_INTERFACE_FUNC(THIS, ISteamUtils, GetAppID)) {
|
||||||
|
if(const auto app_id = get_app_id(ARGS())) {
|
||||||
|
LOG_DEBUG("Found AppID from ISteamUtils: {}", app_id);
|
||||||
|
return app_id;
|
||||||
|
}
|
||||||
|
LOG_ERROR("ISteamUtils::GetAppID returned 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to create interface '{}'", version_map.at("ISteamClient"))
|
||||||
|
}
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("Failed to get app id. Unhandled exception: {}", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace smoke_api {
|
namespace smoke_api {
|
||||||
@@ -184,50 +228,28 @@ namespace smoke_api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AppId_t get_app_id() {
|
AppId_t get_app_id() {
|
||||||
static AppId_t app_id = 0;
|
static AppId_t cached_app_id = 0;
|
||||||
if(app_id) {
|
if(cached_app_id) {
|
||||||
return app_id; // cached value
|
return cached_app_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
LOG_DEBUG("No cached App ID found. Searching in environment variables.");
|
||||||
if(const auto app_id_str = kb::util::get_env("SteamAppId")) {
|
|
||||||
app_id = std::stoi(*app_id_str);
|
|
||||||
LOG_DEBUG("Found AppID from environment: {}", app_id);
|
|
||||||
|
|
||||||
return app_id;
|
if(const auto opt_app_id = get_app_id_from_env()) {
|
||||||
}
|
return cached_app_id = *opt_app_id;
|
||||||
} catch(std::exception&) {
|
|
||||||
LOG_WARN("No SteamAppId in environment. Falling back to ISteamUtils::GetAppID.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Then try to read steam_appid.txt here. SteamAppId env var is not available when it's present.
|
LOG_WARN("Failed to find App ID in environment variables. Falling back to ISteamUtils::GetAppID.");
|
||||||
|
|
||||||
try {
|
// IDEA: Try to read steam_appid.txt here. SteamAppId env var is not available when it's present.
|
||||||
DECLARE_ARGS();
|
// But what if the ID specified in steam_appid.txt is invalid?
|
||||||
|
|
||||||
|
if(const auto opt_app_id = get_app_id_from_steam_client()) {
|
||||||
|
return cached_app_id = *opt_app_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR("Failed to find App ID");
|
||||||
|
|
||||||
THIS = CreateInterface("SteamClient007", nullptr);
|
|
||||||
if(!THIS) {
|
|
||||||
LOG_ERROR("Failed to create SteamClient interface");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
THIS = ISteamClient_GetISteamGenericInterface(ARGS(1, 1, "SteamUtils002"));
|
|
||||||
if(!THIS) {
|
|
||||||
LOG_ERROR("Failed to get SteamUtils interface");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
app_id = ISteamUtils_GetAppID(ARGS());
|
|
||||||
if(!app_id) {
|
|
||||||
LOG_ERROR("ISteamUtils::GetAppID returned 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("Found AppID from ISteamUtils: {}", app_id);
|
|
||||||
return app_id;
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("Failed to get app id: {}", e.what());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
|
|||||||
constexpr auto STEAM_CLIENT = "SteamClient";
|
constexpr auto STEAM_CLIENT = "SteamClient";
|
||||||
constexpr auto STEAM_HTTP = "STEAMHTTP_INTERFACE_VERSION";
|
constexpr auto STEAM_HTTP = "STEAMHTTP_INTERFACE_VERSION";
|
||||||
constexpr auto STEAM_USER = "SteamUser";
|
constexpr auto STEAM_USER = "SteamUser";
|
||||||
constexpr auto STEAM_UTILS = "SteamUtils";
|
|
||||||
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
|
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
|
||||||
constexpr auto STEAM_GAME_SERVER = "SteamGameServer";
|
constexpr auto STEAM_GAME_SERVER = "SteamGameServer";
|
||||||
|
|
||||||
|
|||||||
@@ -104,15 +104,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
// Hooking SteamUtils for GetAppID should be avoided, since it leads to crashes in TW:WH3.
|
||||||
STEAM_UTILS,
|
// No idea why...
|
||||||
interface_data_t{
|
|
||||||
.fallback_version = "SteamUtils009",
|
|
||||||
.entry_map = {
|
|
||||||
ENTRY(ISteamUtils, GetAppID),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,4 +250,46 @@ namespace steam_interfaces {
|
|||||||
LOG_ERROR("{} -> Unhandled exception: {}", __func__, e.what());
|
LOG_ERROR("{} -> Unhandled exception: {}", __func__, e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* find_function(
|
||||||
|
const void* instance_ptr,
|
||||||
|
const std::string& interface_name,
|
||||||
|
const std::string& function_name
|
||||||
|
) {
|
||||||
|
if(!get_interface_name_to_version_map().contains(interface_name)) {
|
||||||
|
LOG_ERROR("Unsupported interface name: '{}'", interface_name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto& interface_version = get_interface_name_to_version_map().at(interface_name);
|
||||||
|
|
||||||
|
static const auto lookup = read_interface_lookup();
|
||||||
|
|
||||||
|
if(!lookup.contains(interface_version)) {
|
||||||
|
LOG_ERROR("Interface '{}' not found in lookup map", interface_version);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto interface_lookup = lookup.at(interface_version);
|
||||||
|
|
||||||
|
if(!interface_lookup.contains(function_name)) {
|
||||||
|
LOG_ERROR("Function '{}' not found in the map of '{}'", function_name, interface_version);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ordinal = interface_lookup.at(function_name);
|
||||||
|
|
||||||
|
const auto virtual_class = static_cast<const kb::hook::virtual_class_t*>(instance_ptr);
|
||||||
|
return virtual_class->vtable[ordinal];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, std::string>& get_interface_name_to_version_map() {
|
||||||
|
// Choose minimal supported versions for maximum compatibility
|
||||||
|
// Is it better to get the interface version found in steam_api library?
|
||||||
|
static const std::map<std::string, std::string> map = {
|
||||||
|
{"ISteamClient", "SteamClient007"},
|
||||||
|
{"ISteamUtils", "SteamUtils002"},
|
||||||
|
};
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#define SMK_FIND_INTERFACE_FUNC(INTERFACE_PTR, INTERFACE_NAME, FUNCTION_NAME) \
|
||||||
|
reinterpret_cast<decltype(&INTERFACE_NAME##_##FUNCTION_NAME)>( \
|
||||||
|
steam_interfaces::find_function(INTERFACE_PTR, #INTERFACE_NAME, #FUNCTION_NAME) \
|
||||||
|
)
|
||||||
|
|
||||||
namespace steam_interfaces {
|
namespace steam_interfaces {
|
||||||
void hook_virtuals(const void* interface_ptr, const std::string& version_string);
|
void hook_virtuals(const void* interface_ptr, const std::string& version_string);
|
||||||
|
|
||||||
@@ -15,4 +21,12 @@ namespace steam_interfaces {
|
|||||||
void* steamclient_handle,
|
void* steamclient_handle,
|
||||||
const std::string& steam_client_interface_version
|
const std::string& steam_client_interface_version
|
||||||
) noexcept;
|
) noexcept;
|
||||||
|
|
||||||
|
void* find_function(
|
||||||
|
const void* instance_ptr,
|
||||||
|
const std::string& interface_name,
|
||||||
|
const std::string& function_name
|
||||||
|
);
|
||||||
|
|
||||||
|
const std::map<std::string, std::string>& get_interface_name_to_version_map();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#include <koalabox/logger.hpp>
|
|
||||||
|
|
||||||
#include "smoke_api/smoke_api.hpp"
|
|
||||||
#include "smoke_api/interfaces/steam_user.hpp"
|
|
||||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
|
||||||
|
|
||||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept {
|
|
||||||
SWAPPED_CALL(THIS, ISteamUtils_GetAppID, ARGS());
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@ VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const c
|
|||||||
VIRTUAL(void*) ISteamClient_GetISteamUser(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_GetISteamGenericInterface(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamInventory(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
VIRTUAL(void*) ISteamClient_GetISteamInventory(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||||
|
VIRTUAL(void*) ISteamClient_GetISteamUtils(PARAMS(HSteamPipe, const char*)) noexcept; // Unhooked
|
||||||
|
|
||||||
// ISteamHTTP
|
// ISteamHTTP
|
||||||
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(PARAMS(HTTPRequestHandle, const uint8_t*, uint32_t)) noexcept;
|
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(PARAMS(HTTPRequestHandle, const uint8_t*, uint32_t)) noexcept;
|
||||||
@@ -43,7 +44,7 @@ VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t,
|
|||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
||||||
|
|
||||||
// ISteamUtils
|
// ISteamUtils
|
||||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept;
|
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept; // Unhooked
|
||||||
|
|
||||||
// ISteamGameServer
|
// ISteamGameServer
|
||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
||||||
|
|||||||
@@ -46,12 +46,12 @@
|
|||||||
#define PARAMS(...) const void* RCX __VA_OPT__(,) __VA_ARGS__
|
#define PARAMS(...) const void* RCX __VA_OPT__(,) __VA_ARGS__
|
||||||
#define ARGS(...) RCX __VA_OPT__(,) __VA_ARGS__
|
#define ARGS(...) RCX __VA_OPT__(,) __VA_ARGS__
|
||||||
#define THIS RCX
|
#define THIS RCX
|
||||||
#define DECLARE_ARGS() const void* RCX = nullptr;
|
#define DECLARE_ARGS() void* RCX = nullptr;
|
||||||
#else
|
#else
|
||||||
#define PARAMS(...) const void* ECX, const void* EDX __VA_OPT__(,) __VA_ARGS__
|
#define PARAMS(...) const void* ECX, const void* EDX __VA_OPT__(,) __VA_ARGS__
|
||||||
#define ARGS(...) ECX, EDX __VA_OPT__(,) __VA_ARGS__
|
#define ARGS(...) ECX, EDX __VA_OPT__(,) __VA_ARGS__
|
||||||
#define THIS ECX
|
#define THIS ECX
|
||||||
#define DECLARE_ARGS() const void* ECX = nullptr; const void* EDX = nullptr;
|
#define DECLARE_ARGS() void* ECX = nullptr; const void* EDX = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using AppId_t = uint32_t;
|
using AppId_t = uint32_t;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace {
|
|||||||
|
|
||||||
fs::remove(zip_file_path);
|
fs::remove(zip_file_path);
|
||||||
}
|
}
|
||||||
} // namespace
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tool for downloading Steamworks SDK and unpacking its headers and binaries
|
* A tool for downloading Steamworks SDK and unpacking its headers and binaries
|
||||||
|
|||||||
Reference in New Issue
Block a user