9 Commits

Author SHA1 Message Date
acidicoala
3bd112c8f4 Refactored version check 2026-01-17 12:06:19 +05:00
acidicoala
7b54b4bc7b Added null checks 2026-01-14 19:34:00 +05:00
acidicoala
077096b7ed renew steamapi_handle 2026-01-12 04:10:43 +05:00
acidicoala
bc8ee85e19 Fixed proxy mode detection 2026-01-08 23:16:10 +05:00
acidicoala
5aaa9ed151 Added trace logs to proxy exports 2026-01-04 21:41:26 +05:00
acidicoala
e2b126c8b6 Regenerated README [skip ci] 2026-01-04 07:22:14 +05:00
acidicoala
2f6d6cc9aa Regenerated linux proxy exports 2026-01-04 07:12:44 +05:00
acidicoala
8784df5f45 Fix mbedtls include attempt 3 2026-01-04 06:54:06 +05:00
acidicoala
dc12301090 Fix mbedtls include attempt 2 2026-01-04 06:13:58 +05:00
15 changed files with 3191 additions and 29 deletions

2
.idea/SmokeAPI.iml generated Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CIDR" type="CPP_MODULE" version="4" />

View File

@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="linux_exports_generator [32]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="--input_libs_glob $ProjectFileDir$/res/steamworks/*/binaries/linux32/libsteam_api.so --output_path $ProjectFileDir$/src/generated/32/proxy_exports" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="linux_exports_generator" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="linux_exports_generator">
<configuration default="false" name="linux_exports_generator [32]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="--input_libs_glob $ProjectFileDir$/res/steamworks/*/binaries/linux32/libsteam_api.so --output_path $ProjectFileDir$/src/generated/32/proxy_exports" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="linux_exports_generator" CONFIG_NAME="Debug [64]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="linux_exports_generator">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>

View File

@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="steamworks_downloader [prompt]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="$Prompt$" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/res" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="steamworks_downloader" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_downloader">
<configuration default="false" name="steamworks_downloader [prompt]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="$Prompt$" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/res" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="steamworks_downloader" CONFIG_NAME="Debug [64]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_downloader">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>

View File

@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="sync" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="sync" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="sync">
<configuration default="false" name="sync" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="sync" CONFIG_NAME="Debug [64]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="sync">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.24)
project(SmokeAPI VERSION 4.1.0)
project(SmokeAPI VERSION 4.1.3)
include(KoalaBox/cmake/KoalaBox.cmake)
add_subdirectory(KoalaBox)

View File

@@ -145,7 +145,11 @@ In such cases, it might be worth trying [Special K], which can inject SmokeAPI a
### ✔️ Requirements
Linux builds of SmokeAPI depend on several libraries. Make sure they are installed on your system.
Linux builds of SmokeAPI depend on several libraries. These libraries are usually included in the
[Steam Linux Runtime 3.0 (sniper)](https://github.com/ValveSoftware/steam-runtime#readme),
so nothing is required to be installed on the system. But when launching a game directly via its executable
(such as in case of hook mode) your system needs to have the following required libraries installed.
The following list features links in Arch Linux repositories, but if you are using a different distribution,
you should use the equivalent package for your distro.
@@ -214,7 +218,7 @@ Where `<GameExe32>` and `<GameExe64>` correspond to the actual filename of the g
- `TheEscapists2.x86_64` (64-bit)
- `_linux/darkest.bin.x86` (32-bit)
- `_linux/darkest.bin.x86_64` (64-bit)
- `bin/linux_x64/eurotrucks2` (64-bit)
- `eurotrucks2` (64-bit)
- `binaries/victoria3` (64-bit)
And so on. Notice that Linux executables do not have `.exe` extension like on Windows, so make sure to copy the entire
@@ -431,7 +435,8 @@ This project makes use of the following open source projects:
- [p-ranav/glob](https://github.com/p-ranav/glob)
- [pantor/inja](https://github.com/pantor/inja)
- [jarro2783/cxxopts](https://github.com/jarro2783/cxxopts)
- [serge1/ELFIO](https://github.com/serge1/ELFIO)
- [serge1/ELFIO](https://github.com/serge1/ELFIO)
- [Mbed-TLS/mbedtls](https://github.com/Mbed-TLS/mbedtls)
- [bshoshany/thread-pool](https://github.com/bshoshany/thread-pool)
- [batterycenter/embed](https://github.com/batterycenter/embed)

View File

@@ -20,8 +20,8 @@
"logging": {
"type": "boolean",
"default": false,
"x-packaged-default": true,
"description": "Enables logging to SmokeAPI.log.log file.",
"x-packaged-default": true,
"x-valid-values": "`true` or `false`."
},
"log_steam_http": {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@
#include <koalabox/config.hpp>
#include <koalabox/globals.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/http_client.hpp>
#include <koalabox/lib.hpp>
#include <koalabox/lib_monitor.hpp>
#include <koalabox/logger.hpp>
@@ -57,6 +58,31 @@ namespace {
void* original_steamapi_handle = nullptr;
bool is_hook_mode;
void check_for_updates() {
try {
const auto latest_release_url = std::format(
"https://api.github.com/repos/acidicoala/{}/releases/latest",
PROJECT_NAME
);
const auto res = kb::http_client::get_json(latest_release_url);
const auto latest_tag = res["tag_name"].get<std::string>();
const auto current_tag = std::format("v{}", PROJECT_VERSION);
if(current_tag == latest_tag) {
LOG_DEBUG("Running the latest version");
} else {
const auto release_page = std::format(
"https://github.com/acidicoala/{}/releases/{}",
PROJECT_NAME, latest_tag
);
LOG_WARN("New version {} available: {}", latest_tag, release_page);
}
} catch(const std::exception& e) {
LOG_ERROR("{} -> Unexpected error: {}", __func__, e.what());
}
}
std::set<std::string> find_steamclient_versions(void* steamapi_handle) {
if(!steamapi_handle) {
kb::util::panic("Invalid state. steamapi_handle is null.");
@@ -111,10 +137,19 @@ namespace {
static const auto CreateInterface$ = KB_LIB_GET_FUNC(steamclient_handle, CreateInterface);
if(original_steamapi_handle) {
if(auto* steamapi_handle = kb::lib::get_lib_handle(STEAM_API_MODULE)) {
if(original_steamapi_handle == nullptr) { // hook mode on Windows
original_steamapi_handle = steamapi_handle;
} else if(steamapi_handle != original_steamapi_handle) {
LOG_WARN(
"{} -> steamapi_handle ({}) != original_steamapi_handle ({})",
__func__, steamapi_handle, original_steamapi_handle
);
}
// SteamAPI might have been initialized.
// Hence, we need to query SteamClient interfaces and hook them if needed.
const auto steamclient_versions = find_steamclient_versions(original_steamapi_handle);
const auto steamclient_versions = find_steamclient_versions(steamapi_handle);
for(const auto& steamclient_version : steamclient_versions) {
if(CreateInterface$(steamclient_version.c_str(), nullptr)) {
#ifdef KB_WIN
@@ -127,7 +162,7 @@ namespace {
}
}
} else {
LOG_ERROR("{} -> original_steamapi_handle is null", __func__);
LOG_ERROR("{} -> steamapi_handle is null", __func__);
}
return true;
@@ -195,7 +230,10 @@ namespace {
if(const auto lib_bitness = kb::lib::get_bitness(lib_path)) {
if(static_cast<uint8_t>(*lib_bitness) == kb::platform::bitness) {
if(const auto lib_handle = kb::lib::load(lib_path)) {
LOG_INFO("Found original library: {}", kb::path::to_str(lib_path));
LOG_INFO(
"Found & loaded original library '{}' @ {}",
kb::path::to_str(lib_path), *lib_handle
);
original_steamapi_handle = *lib_handle;
proxy_exports::init(self_module_handle, original_steamapi_handle);
@@ -212,7 +250,7 @@ namespace {
}
void init_proxy_mode([[maybe_unused]] void* self_module_handle) {
is_hook_mode = true;
is_hook_mode = false;
original_steamapi_handle = kb::lib::load_original_library(kb::paths::get_self_dir(), STEAM_API_MODULE);
#ifdef KB_LINUX
@@ -275,6 +313,14 @@ namespace smoke_api {
}
}
void post_init() {
#ifdef KB_DEBUG
// TODO: Add config option to toggle this and show native OS notification
// The real reason behind this is for automatic testing of HTTPs dependencies
std::thread(check_for_updates).detach();
#endif
}
void shutdown() {
try {
static bool shutdown_complete = false;

View File

@@ -4,6 +4,14 @@
namespace smoke_api {
void init(void* self_module_handle);
/**
* Post-initialization procedures that must be done after the module is finished loading.
* Reason being that on Windows we should not start new threads while being in DllMain callback,
* otherwise we would run into deadlocks/race-conditions/undefined behavior.
*/
void post_init();
void shutdown();
AppId_t get_app_id();

View File

@@ -15,7 +15,9 @@ namespace steam_client {
if(interface_version) {
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
steam_interfaces::hook_virtuals(interface, interface_version);
if(interface) {
steam_interfaces::hook_virtuals(interface, interface_version);
}
}
return interface;

View File

@@ -237,13 +237,10 @@ namespace steam_interfaces {
continue;
}
const auto* const interface_ptr = ISteamClient_GetISteamGenericInterface(
ISteamClient_GetISteamGenericInterface(
ARGS(steam_user, steam_pipe, interface_version.c_str())
);
if(not interface_ptr) {
LOG_ERROR("Failed to get generic interface: '{}'", interface_version)
}
}
} catch(const std::exception& e) {
LOG_ERROR("{} -> Unhandled exception: {}", __func__, e.what());

View File

@@ -4,6 +4,7 @@
#include <koalabox/logger.hpp>
#include "smoke_api/steamclient/steamclient.hpp"
#include "smoke_api/smoke_api.hpp"
#include "smoke_api/types.hpp"
#include "steam_api/steam_client.hpp"
@@ -16,6 +17,9 @@ C_DECL(void*) CreateInterface(const char* interface_version, create_interface_re
static std::mutex section;
const std::lock_guard lock(section);
static std::once_flag once_flag;
std::call_once(once_flag, smoke_api::post_init);
return steam_client::GetGenericInterface(
__func__,
interface_version,