Implemented ISteamGameServer

This commit is contained in:
acidicoala
2025-08-26 05:07:17 +05:00
parent 902476cb3e
commit 9f84425e4e
59 changed files with 151 additions and 123 deletions

View File

@@ -69,4 +69,5 @@ misc-*,
-readability-named-parameter, -readability-named-parameter,
-readability-function-cognitive-complexity, -readability-function-cognitive-complexity,
-*-include-cleaner, -*-include-cleaner,
-*-lambda-function-name' -*-lambda-function-name,
-*-err58-cpp'

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text eol=lf

View File

@@ -40,6 +40,7 @@ set(SMOKE_API_SOURCES
src/steam_api/exports/steam_api_unversioned.cpp src/steam_api/exports/steam_api_unversioned.cpp
src/steam_api/virtuals/isteamapps.cpp src/steam_api/virtuals/isteamapps.cpp
src/steam_api/virtuals/isteamclient.cpp src/steam_api/virtuals/isteamclient.cpp
src/steam_api/virtuals/isteamgameserver.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/steam_api_virtuals.hpp src/steam_api/virtuals/steam_api_virtuals.hpp
@@ -82,6 +83,7 @@ target_include_directories(SmokeAPI PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_BINARY_DIR}") "${CMAKE_CURRENT_BINARY_DIR}")
## https://github.com/batterycenter/embed
CPMAddPackage( CPMAddPackage(
URI "gh:batterycenter/embed@1.2.19" URI "gh:batterycenter/embed@1.2.19"
OPTIONS "B_PRODUCTION_MODE ON" OPTIONS "B_PRODUCTION_MODE ON"

View File

@@ -73,21 +73,21 @@ SmokeAPI supports 2 installation modes: hook mode and proxy mode.
|=== |===
Try installing the unlocker in hook mode first. Try installing the unlocker in hook mode first.
If it doesn't work, try installing it in proxy mode. If it doesn't work, try installing it in proxy mode.
==== 🪝 Hook mode === 🪝 Hook mode
. Download the latest SmokeAPI release zip from {smokeapi_release}. . Download the latest SmokeAPI release zip from {smokeapi_release}.
. From SmokeAPI archive unpack `steam_api.dll` or `steam_api64.dll`, depending on the game bitness, rename it to `version.dll`, and place it next to the game exe file. . From SmokeAPI archive unpack `steam_api.dll` or `steam_api64.dll`, depending on the game bitness, rename it to `version.dll`, and place it next to the game exe file.
==== 🪝 Hook mode (Alternative) === 🪝 Hook mode (Alternative)
If a game doesn't load `version.dll`, you can use one of the {koaloader} DLLs that the game does in fact load. For example, assuming that the game loads `d3d9.dll`: If a game doesn't load `version.dll`, you can use one of the {koaloader} DLLs that the game does in fact load.
For example, assuming that the game loads `winmm.dll`:
. Download the latest Koaloader release zip from https://github.com/acidicoala/Koaloader/releases/latest[Koaloader Releases]. . Download the latest Koaloader release zip from https://github.com/acidicoala/Koaloader/releases/latest[Koaloader Releases].
. From Koaloader archive unpack `d3d9.dll` from `d3d9-32` or `d3d9-64`, depending on the game bitness, and place it next to the game exe file. . From Koaloader archive unpack `winmm.dll` from `winmm-32` or `winmm-64`, depending on the game bitness, and place it next to the game exe file.
. Download the latest SmokeAPI release zip from {smokeapi_release}. . Download the latest SmokeAPI release zip from {smokeapi_release}.
. From SmokeAPI archive unpack `steam_api.dll` or `steam_api64.dll`, depending on the game bitness, rename it to `SmokeAPI.dll`, and place it next to the game exe file. . From SmokeAPI archive unpack `steam_api.dll` or `steam_api64.dll`, depending on the game bitness, rename it to `SmokeAPI.dll`, and place it next to the game exe file.
@@ -265,9 +265,15 @@ For example:
.\build.ps1 64 Release .\build.ps1 64 Release
---- ----
== 🐞 Known issues
* Crashes on startup in Project Winter in hook mode (proxy mode works fine).
== 📚 Open-Source libraries == 📚 Open-Source libraries
TODO * https://github.com/batterycenter/embed[batterycenter/embed]
* https://github.com/bshoshany/thread-pool[bshoshany/thread-pool]
* + https://github.com/acidicoala/Koalabox?tab=readme-ov-file#-open-source-libraries[libraries used by KoalaBox]
== 📄 License == 📄 License

View File

@@ -3,7 +3,6 @@
"$version": 3, "$version": 3,
"logging": true, "logging": true,
"default_app_status": "unlocked", "default_app_status": "unlocked",
"override_app_id": 0,
"override_app_status": {}, "override_app_status": {},
"override_dlc_status": {}, "override_dlc_status": {},
"auto_inject_inventory": true, "auto_inject_inventory": true,

View File

@@ -5,6 +5,10 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"$schema": {
"type": "string",
"description": "The URI of the JSON Schema used to validate this config."
},
"$version": { "$version": {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
@@ -21,12 +25,6 @@
"default": "unlocked", "default": "unlocked",
"$ref": "#/$defs/AppStatus" "$ref": "#/$defs/AppStatus"
}, },
"override_app_id": {
"type": "integer",
"minimum": 0,
"default": 0,
"description": "Overrides the current app ID (0 means no override)."
},
"override_app_status": { "override_app_status": {
"type": "object", "type": "object",
"default": {}, "default": {},
@@ -113,6 +111,7 @@
}, },
"examples": [ "examples": [
{ {
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/heads/master/res/SmokeAPI.schema.json",
"$version": 3, "$version": 3,
"logging": true, "logging": true,
"default_app_status": "unlocked", "default_app_status": "unlocked",

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======= //====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
// //
// Purpose: Main interface for loading and accessing Steamworks API's from the // Purpose: Main interface for loading and accessing Steamworks API's from the
// Steam client. // Steam client.

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -1,4 +1,4 @@
//====== Copyright Valve Corporation, All rights reserved. ==================== //====== Copyright Valve Corporation, All rights reserved. ====================
// //
// Internal low-level access to Steamworks interfaces. // Internal low-level access to Steamworks interfaces.
// //

View File

@@ -37,19 +37,6 @@
namespace { namespace {
namespace kb = koalabox; namespace kb = koalabox;
namespace fs = std::filesystem;
void override_app_id() {
const auto override_app_id = smoke_api::config::instance.override_app_id;
if(override_app_id == 0) {
return;
}
spdlog::default_logger_raw();
LOG_DEBUG("Overriding app id to {}", override_app_id);
SetEnvironmentVariable(TEXT("SteamAppId"), std::to_wstring(override_app_id).c_str());
}
void init_proxy_mode() { void init_proxy_mode() {
LOG_INFO("Detected proxy mode"); LOG_INFO("Detected proxy mode");
@@ -61,27 +48,14 @@ namespace {
void init_hook_mode() { void init_hook_mode() {
LOG_INFO("Detected hook mode"); LOG_INFO("Detected hook mode");
kb::hook::init(true);
const std::vector<std::string> target_libraries{STEAMCLIENT_DLL, STEAMAPI_DLL};
kb::dll_monitor::init_listener( kb::dll_monitor::init_listener(
target_libraries, {STEAMCLIENT_DLL, STEAMAPI_DLL},
[&](const HMODULE& module_handle, const std::string& library_name) { [&](const HMODULE& module_handle, const std::string& library_name) {
static auto hook_count = 0U;
if(kb::str::eq(library_name, STEAMCLIENT_DLL)) { if(kb::str::eq(library_name, STEAMCLIENT_DLL)) {
KB_HOOK_DETOUR_MODULE(CreateInterface, module_handle); KB_HOOK_DETOUR_MODULE(CreateInterface, module_handle);
hook_count++;
} else if(kb::str::eq(library_name, STEAMAPI_DLL)) { } else if(kb::str::eq(library_name, STEAMAPI_DLL)) {
KB_HOOK_DETOUR_MODULE(SteamAPI_RestartAppIfNecessary, module_handle); KB_HOOK_DETOUR_MODULE(SteamAPI_RestartAppIfNecessary, module_handle);
KB_HOOK_DETOUR_MODULE(SteamAPI_Shutdown, module_handle); KB_HOOK_DETOUR_MODULE(SteamAPI_Shutdown, module_handle);
hook_count++;
}
if(hook_count == target_libraries.size()) {
kb::dll_monitor::shutdown_listener();
} }
} }
); );
@@ -111,7 +85,8 @@ namespace smoke_api {
LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::util::BITNESS); LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::util::BITNESS);
override_app_id(); // We need to hook functions in either mode
kb::hook::init(true);
if(kb::hook::is_hook_mode(module_handle, STEAMAPI_DLL)) { if(kb::hook::is_hook_mode(module_handle, STEAMAPI_DLL)) {
hook_mode = true; hook_mode = true;

View File

@@ -6,6 +6,7 @@ constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
constexpr auto STEAM_CLIENT = "SteamClient"; constexpr auto STEAM_CLIENT = "SteamClient";
constexpr auto STEAM_USER = "SteamUser"; constexpr auto STEAM_USER = "SteamUser";
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V"; constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
constexpr auto STEAM_GAME_SERVER = "SteamGameServer";
// IMPORTANT: DLL_EXPORT is hardcoded in exports_generator.cpp, // IMPORTANT: DLL_EXPORT is hardcoded in exports_generator.cpp,
// so any name changes here must be reflected there as well. // so any name changes here must be reflected there as well.

View File

@@ -5,10 +5,9 @@
#include "smoke_api/config.hpp" #include "smoke_api/config.hpp"
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(const AppId_t unOwnAppID) { DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(const AppId_t unOwnAppID) {
if(smoke_api::config::instance.override_app_id != 0) { LOG_INFO("{} -> unOwnAppID: {}", __func__, unOwnAppID);
LOG_DEBUG("{} -> {}. Preventing app restart", unOwnAppID, __func__);
return false; // Restart can be suppressed if needed
}
AUTO_CALL(SteamAPI_RestartAppIfNecessary, unOwnAppID); AUTO_CALL(SteamAPI_RestartAppIfNecessary, unOwnAppID);
} }

View File

@@ -9,7 +9,7 @@
// ISteamApps // ISteamApps
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void* self, AppId_t dlcID) { DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void* self, const AppId_t dlcID) {
try { try {
return smoke_api::steam_apps::IsDlcUnlocked( return smoke_api::steam_apps::IsDlcUnlocked(
__func__, __func__,
@@ -23,7 +23,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void* self, AppId_t dlcID)
} }
} }
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(void* self, AppId_t dlcID) { DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(void* self, const AppId_t dlcID) {
try { try {
return smoke_api::steam_apps::IsDlcUnlocked( return smoke_api::steam_apps::IsDlcUnlocked(
__func__, __func__,
@@ -294,3 +294,28 @@ DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp
return k_EUserHasLicenseResultDoesNotHaveLicense; 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

@@ -2,7 +2,6 @@
#include <map> #include <map>
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <koalabox/win.hpp> #include <koalabox/win.hpp>
#include "smoke_api.hpp" #include "smoke_api.hpp"
@@ -34,7 +33,7 @@ namespace {
return version_map[version_prefix]; return version_map[version_prefix];
} }
throw kb::util::exception("No match found for '{}'", version_prefix); throw std::runtime_error(std::format("No match found for '{}'", version_prefix));
} catch(const std::exception& ex) { } catch(const std::exception& ex) {
LOG_ERROR( LOG_ERROR(
"Failed to get versioned interface: {}." "Failed to get versioned interface: {}."

View File

@@ -5,7 +5,6 @@
#include <koalabox/hook.hpp> #include <koalabox/hook.hpp>
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <koalabox/win.hpp> #include <koalabox/win.hpp>
#include "smoke_api.hpp" #include "smoke_api.hpp"
@@ -67,17 +66,11 @@ namespace {
} }
}, },
{ {
STEAM_INVENTORY, STEAM_GAME_SERVER,
interface_data{ interface_data{
.fallback_version = "STEAMINVENTORY_INTERFACE_V003", .fallback_version = "SteamGameServer015",
.entry_map = { .entry_map = {
ENTRY(ISteamInventory, GetResultStatus), ENTRY(ISteamGameServer, UserHasLicenseForApp),
ENTRY(ISteamInventory, GetResultItems),
ENTRY(ISteamInventory, CheckResultSteamID),
ENTRY(ISteamInventory, GetAllItems),
ENTRY(ISteamInventory, GetItemsByID),
ENTRY(ISteamInventory, SerializeResult),
ENTRY(ISteamInventory, GetItemDefinitionIDs),
} }
} }
}, },

View File

@@ -1,6 +1,5 @@
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_apps.hpp" #include "smoke_api/interfaces/steam_apps.hpp"
#include "steam_api/steam_interface.hpp" #include "steam_api/steam_interface.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp" #include "steam_api/virtuals/steam_api_virtuals.hpp"

View File

@@ -1,6 +1,5 @@
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "steam_api/steam_client.hpp" #include "steam_api/steam_client.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp" #include "steam_api/virtuals/steam_api_virtuals.hpp"

View File

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

View File

@@ -1,4 +1,3 @@
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_inventory.hpp" #include "smoke_api/interfaces/steam_inventory.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp" #include "steam_api/virtuals/steam_api_virtuals.hpp"
@@ -130,7 +129,7 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
} }
VIRTUAL(bool) ISteamInventory_CheckResultSteamID( VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
PARAMS(SteamInventoryResult_t resultHandle, CSteamID steamIDExpected) PARAMS(const SteamInventoryResult_t resultHandle, CSteamID steamIDExpected)
) { ) {
return smoke_api::steam_inventory::CheckResultSteamID( return smoke_api::steam_inventory::CheckResultSteamID(
__func__, __func__,

View File

@@ -1,6 +1,5 @@
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include "smoke_api.hpp"
#include "smoke_api/interfaces/steam_user.hpp" #include "smoke_api/interfaces/steam_user.hpp"
#include "steam_api/steam_interface.hpp" #include "steam_api/steam_interface.hpp"
#include "steam_api/virtuals/steam_api_virtuals.hpp" #include "steam_api/virtuals/steam_api_virtuals.hpp"

View File

@@ -33,3 +33,8 @@ VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t,
// ISteamUser // ISteamUser
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)); VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
// ISteamGameServer
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
PARAMS(CSteamID, AppId_t)
);

View File

@@ -32,7 +32,7 @@ namespace smoke_api::api {
std::optional<std::vector<DLC>> fetch_dlcs_from_steam(const AppId_t app_id) { std::optional<std::vector<DLC>> fetch_dlcs_from_steam(const AppId_t app_id) {
try { try {
// TODO: Communicate directly with Steam servers. // TODO: Communicate directly with Steam servers?
// ref.: https://github.com/SteamRE/SteamKit // ref.: https://github.com/SteamRE/SteamKit
const auto url = const auto url =
std::format("https://store.steampowered.com/dlc/{}/ajaxgetdlclist", app_id); std::format("https://store.steampowered.com/dlc/{}/ajaxgetdlclist", app_id);

View File

@@ -32,6 +32,9 @@ namespace smoke_api::cache {
} }
bool save_dlcs(AppId_t app_id, const std::vector<DLC>& dlcs) noexcept { bool save_dlcs(AppId_t app_id, const std::vector<DLC>& dlcs) noexcept {
static std::mutex section;
const std::lock_guard lock(section);
try { try {
LOG_DEBUG("Caching DLC IDs for the app: {}", app_id); LOG_DEBUG("Caching DLC IDs for the app: {}", app_id);

View File

@@ -1,7 +1,6 @@
#include <koalabox/config.hpp> #include <koalabox/config.hpp>
#include <koalabox/io.hpp> #include <koalabox/io.hpp>
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include "smoke_api/config.hpp" #include "smoke_api/config.hpp"
@@ -40,6 +39,7 @@ namespace smoke_api::config {
break; break;
case AppStatus::ORIGINAL: case AppStatus::ORIGINAL:
case AppStatus::UNDEFINED: case AppStatus::UNDEFINED:
default:
is_unlocked = original_function(); is_unlocked = original_function();
break; break;
} }

View File

@@ -14,10 +14,10 @@ namespace smoke_api::config {
AppStatus, AppStatus,
// @formatter:off // @formatter:off
{ {
{AppStatus::UNDEFINED, nullptr}, { AppStatus::UNDEFINED, nullptr },
{AppStatus::ORIGINAL, "original"}, { AppStatus::ORIGINAL, "original" },
{AppStatus::UNLOCKED, "unlocked"}, { AppStatus::UNLOCKED, "unlocked" },
{AppStatus::LOCKED, "locked"}, { AppStatus::LOCKED, "locked" },
} }
// @formatter:on // @formatter:on
) )
@@ -26,7 +26,6 @@ namespace smoke_api::config {
uint32_t $version = 3; uint32_t $version = 3;
bool logging = false; bool logging = false;
AppStatus default_app_status = AppStatus::UNLOCKED; AppStatus default_app_status = AppStatus::UNLOCKED;
uint32_t override_app_id = 0;
std::map<std::string, AppStatus> override_app_status; std::map<std::string, AppStatus> override_app_status;
std::map<std::string, AppStatus> override_dlc_status; std::map<std::string, AppStatus> override_dlc_status;
AppDlcNameMap extra_dlcs; AppDlcNameMap extra_dlcs;
@@ -35,11 +34,9 @@ namespace smoke_api::config {
NLOHMANN_DEFINE_TYPE_INTRUSIVE( NLOHMANN_DEFINE_TYPE_INTRUSIVE(
Config, Config,
// NOLINT(misc-const-correctness)
$version, $version,
logging, logging,
default_app_status, default_app_status,
override_app_id,
override_app_status, override_app_status,
override_dlc_status, override_dlc_status,
extra_dlcs, extra_dlcs,

View File

@@ -1,7 +1,6 @@
#include <set> #include <set>
#include <koalabox/logger.hpp> #include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include "smoke_api/interfaces/steam_apps.hpp" #include "smoke_api/interfaces/steam_apps.hpp"
#include "smoke_api/api.hpp" #include "smoke_api/api.hpp"
@@ -88,7 +87,7 @@ namespace smoke_api::steam_apps {
const std::function<bool()>& original_function const std::function<bool()>& original_function
) { ) {
try { try {
const auto unlocked = smoke_api::config::is_dlc_unlocked( const auto unlocked = config::is_dlc_unlocked(
app_id, app_id,
dlc_id, dlc_id,
original_function original_function
@@ -172,10 +171,10 @@ namespace smoke_api::steam_apps {
); );
}; };
const auto inject_dlc = [&](const DLC& dlc) { const auto output_dlc = [&](const DLC& dlc) {
// Fill the output pointers // Fill the output pointers
*pDlcId = dlc.get_id(); *pDlcId = dlc.get_id();
*pbAvailable = smoke_api::config::is_dlc_unlocked( *pbAvailable = config::is_dlc_unlocked(
app_id, app_id,
*pDlcId, *pDlcId,
[&] { [&] {
@@ -192,7 +191,7 @@ namespace smoke_api::steam_apps {
const auto& dlcs = app_dlcs[app_id]; const auto& dlcs = app_dlcs[app_id];
if(iDLC >= 0 && iDLC < dlcs.size()) { if(iDLC >= 0 && iDLC < dlcs.size()) {
inject_dlc(dlcs[iDLC]); output_dlc(dlcs[iDLC]);
print_dlc_info("injected"); print_dlc_info("injected");
return true; return true;
} }
@@ -204,7 +203,7 @@ namespace smoke_api::steam_apps {
const auto success = original_function(); const auto success = original_function();
if(success) { if(success) {
*pbAvailable = smoke_api::config::is_dlc_unlocked( *pbAvailable = config::is_dlc_unlocked(
app_id, app_id,
*pDlcId, *pDlcId,
[&] { [&] {

View File

@@ -59,7 +59,7 @@ namespace smoke_api::steam_inventory {
"{} -> handle: {}, pOutItemsArray: {}, arraySize: {}", "{} -> handle: {}, pOutItemsArray: {}, arraySize: {}",
function_name, function_name,
resultHandle, resultHandle,
fmt::ptr(pOutItemsArray), reinterpret_cast<void*>(pOutItemsArray),
*punOutItemsArraySize *punOutItemsArraySize
); );
@@ -140,26 +140,32 @@ namespace smoke_api::steam_inventory {
const uint32_t* punValueBufferSizeOut, const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function const std::function<bool()>& original_function
) { ) {
const auto common_info = fmt::format( LOG_DEBUG(
"{} -> Handle: {}, Index: {}, Name: '{}'", "{} -> Handle: {}, Index: {}, Name: '{}'",
function_name, function_name,
resultHandle, resultHandle,
unItemIndex, unItemIndex,
pchPropertyName // 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) { if(!success) {
LOG_WARN("{}, Result is false", common_info); LOG_WARN("{} -> Result is false", function_name);
return false; return false;
} }
LOG_DEBUG( if(
"{}, Buffer: '{}'", pchValueBuffer && *pchValueBuffer &&
common_info, punValueBufferSizeOut && *punValueBufferSizeOut > 0
std::string(pchValueBuffer, *punValueBufferSizeOut - 1) ) {
); LOG_DEBUG(
R"({} -> Buffer: "{}")",
function_name,
std::string(pchValueBuffer, *punValueBufferSizeOut - 1)
);
}
return success; return success;
} }

View File

@@ -4,6 +4,7 @@ project(smoke-api-tools LANGUAGES CXX)
### Thread pool library ### Thread pool library
## https://github.com/bshoshany/thread-pool
CPMAddPackage( CPMAddPackage(
NAME BS_thread_pool NAME BS_thread_pool
GITHUB_REPOSITORY bshoshany/thread-pool GITHUB_REPOSITORY bshoshany/thread-pool