mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2026-01-31 08:52:50 -05:00
Compare commits
114 Commits
v3.1.4
...
15ba0ed447
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15ba0ed447 | ||
|
|
aa0504ff14 | ||
|
|
3312e92dce | ||
|
|
e6dbffb671 | ||
|
|
ef3b8894e3 | ||
|
|
009d839ec3 | ||
|
|
70160206b8 | ||
|
|
86eb2085e7 | ||
|
|
5f07cec291 | ||
|
|
4bf9898f83 | ||
|
|
1f8fab7b48 | ||
|
|
36d5143463 | ||
|
|
d5db62c2f2 | ||
|
|
7e9c4c42b9 | ||
|
|
cc17984702 | ||
|
|
293f490e1d | ||
|
|
060d6e15a3 | ||
|
|
96ec32228c | ||
|
|
725be9f346 | ||
|
|
5382c84906 | ||
|
|
5629b7b5e2 | ||
|
|
673cd11e47 | ||
|
|
ec99d79bf7 | ||
|
|
fb17902116 | ||
|
|
fce11580d6 | ||
|
|
2fad0ee43f | ||
|
|
73fab4020d | ||
|
|
bdbd1ff540 | ||
|
|
477f019b49 | ||
|
|
8d3d2c13d8 | ||
|
|
b362bb2828 | ||
|
|
06809b2c5d | ||
|
|
85710cce37 | ||
|
|
fe7eef72bd | ||
|
|
1572a0fd4a | ||
|
|
7e744f5492 | ||
|
|
c29445126b | ||
|
|
c6767419e4 | ||
|
|
dac3cad5e2 | ||
|
|
62071a1489 | ||
|
|
f8de04812a | ||
|
|
df43442fce | ||
|
|
76cf15126c | ||
|
|
8194a3333d | ||
|
|
599749a799 | ||
|
|
ef5bc217b0 | ||
|
|
9f1a5edd5f | ||
|
|
d879b21bd4 | ||
|
|
5aa9ffef85 | ||
|
|
0c6c8e02b6 | ||
|
|
0f5d98e42b | ||
|
|
2da049ec2a | ||
|
|
227a920e11 | ||
|
|
21a4f56145 | ||
|
|
3ab61365ce | ||
|
|
2ce8967257 | ||
|
|
83623841bd | ||
|
|
d46acb56e8 | ||
|
|
7ec6f5b277 | ||
|
|
7758663b2e | ||
|
|
3d5261e293 | ||
|
|
469299340f | ||
|
|
e3505e48fb | ||
|
|
35ea324898 | ||
|
|
b4c12f5a37 | ||
|
|
8a92c50fd3 | ||
|
|
fe5c4cede4 | ||
|
|
d7d5eb349b | ||
|
|
7b20bde2fc | ||
|
|
02e66ed624 | ||
|
|
23ee93464a | ||
|
|
ca5fcf8cb0 | ||
|
|
2b3930031f | ||
|
|
debb44c138 | ||
|
|
21cab6c469 | ||
|
|
7cb32f84db | ||
|
|
9a0ab12b86 | ||
|
|
05569a4019 | ||
|
|
49efd831bf | ||
|
|
9944f3bd3f | ||
|
|
53868e8bed | ||
|
|
842387bb2f | ||
|
|
c062696706 | ||
|
|
aea513fbd1 | ||
|
|
99564ae4b7 | ||
|
|
046df29a6b | ||
|
|
5012ed3da8 | ||
|
|
297382f6a2 | ||
|
|
e6fe7ad22e | ||
|
|
548ba0fe00 | ||
|
|
cd8be9f80a | ||
|
|
ca4457556c | ||
|
|
509b70c0b0 | ||
|
|
ac9c1a3fcc | ||
|
|
265829f434 | ||
|
|
d03f95adb7 | ||
|
|
d8e1333d42 | ||
|
|
922b649fc3 | ||
|
|
d829396c08 | ||
|
|
59d45c9dab | ||
|
|
81a8ef42ab | ||
|
|
e72bc29635 | ||
|
|
593c0cb4bc | ||
|
|
d3fd17779c | ||
|
|
f5b8c0c89f | ||
|
|
8decbafb53 | ||
|
|
7ab9895b58 | ||
|
|
c75bbcf636 | ||
|
|
c409ff3202 | ||
|
|
8a6c8d0fba | ||
|
|
7781636335 | ||
|
|
e0ba771d52 | ||
|
|
b0a4ea0f24 | ||
|
|
c5f8a37702 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
||||
* text eol=lf
|
||||
|
||||
*.dll binary
|
||||
*.so binary
|
||||
|
||||
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Continuous Integration
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI
|
||||
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@1bdfeefa9933092a747c46679b3d872470ef4998
|
||||
permissions:
|
||||
contents: write
|
||||
with:
|
||||
arch: '[ 32, 64 ]'
|
||||
config: Release
|
||||
modules: '[ "SmokeAPI" ]'
|
||||
zip_command: >
|
||||
zip -j $ZIP_NAME
|
||||
artifacts/*/*.dll
|
||||
res/SmokeAPI.config.json
|
||||
res/README.txt
|
||||
11
.github/workflows/dev-build.yml
vendored
Normal file
11
.github/workflows/dev-build.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
name: '🚧 Development Build'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**' # This prevents dev builds on tag pushes
|
||||
|
||||
jobs:
|
||||
dev-build:
|
||||
name: '🚧 Development Build'
|
||||
uses: acidicoala/SmokeAPI/.github/workflows/matrix-build.yml@master
|
||||
18
.github/workflows/matrix-build.yml
vendored
Normal file
18
.github/workflows/matrix-build.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Matrix Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ Linux, Windows ]
|
||||
bitness: [ 32, 64 ]
|
||||
|
||||
uses: acidicoala/KoalaBox/.github/workflows/build-cmake.yml@master
|
||||
with:
|
||||
module: SmokeAPI
|
||||
os: ${{ matrix.os }}
|
||||
bitness: ${{ matrix.bitness }}
|
||||
20
.github/workflows/tag-release.yml
vendored
Normal file
20
.github/workflows/tag-release.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: '🏷️ Tag Release'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-binaries:
|
||||
name: '🏗️ Build Binaries'
|
||||
uses: acidicoala/SmokeAPI/.github/workflows/matrix-build.yml@master
|
||||
|
||||
create-release:
|
||||
name: '📦 Create Release'
|
||||
uses: acidicoala/KoalaBox/.github/workflows/create-release.yml@master
|
||||
needs: build-binaries
|
||||
with:
|
||||
zip_files: >
|
||||
res/README.txt
|
||||
res/SmokeAPI.config.json
|
||||
17
.idea/dictionaries/project.xml
generated
17
.idea/dictionaries/project.xml
generated
@@ -4,9 +4,16 @@
|
||||
<w>abcdefghijklmnopqrstuvwxyz</w>
|
||||
<w>acidicoala</w>
|
||||
<w>ajaxgetdlclist</w>
|
||||
<w>cstring</w>
|
||||
<w>dlmopen</w>
|
||||
<w>dlopen</w>
|
||||
<w>dlsym</w>
|
||||
<w>dynsym</w>
|
||||
<w>elfio</w>
|
||||
<w>endfor</w>
|
||||
<w>ghcr</w>
|
||||
<w>indicies</w>
|
||||
<w>inja</w>
|
||||
<w>inlinentd</w>
|
||||
<w>isteamapps</w>
|
||||
<w>isteamclient</w>
|
||||
@@ -16,10 +23,20 @@
|
||||
<w>koality</w>
|
||||
<w>koaloader</w>
|
||||
<w>libgtk</w>
|
||||
<w>libsteam</w>
|
||||
<w>memcpy</w>
|
||||
<w>movabs</w>
|
||||
<w>movl</w>
|
||||
<w>peparse</w>
|
||||
<w>phnt</w>
|
||||
<w>polyhook</w>
|
||||
<w>rtld</w>
|
||||
<w>simplecpp</w>
|
||||
<w>steamapi</w>
|
||||
<w>steamapps</w>
|
||||
<w>steamclient</w>
|
||||
<w>winhttp</w>
|
||||
<w>winmm</w>
|
||||
<w>wstr</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
|
||||
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@@ -20,4 +20,5 @@
|
||||
<option name="useRustfmt" value="true" />
|
||||
<option name="version" value="2" />
|
||||
</component>
|
||||
<component name="WestSettings"><![CDATA[{}]]></component>
|
||||
</project>
|
||||
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="exports_generator [32] [linux]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="FALSE libsteam_api_o $ProjectFileDir$/res/steamworks/*/binaries/linux32/libsteam_api.so $CMakeCurrentGenerationDir$/generated/libsteam_api_exports.cpp" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="exports_generator" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="exports_generator">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="exports_generator [64] [win]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="FALSE steam_api64_o $ProjectFileDir$/res/steamworks/*/binaries/steam_api64.dll $CMakeCurrentGenerationDir$/generated/linker_exports_for_steam_api.h" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="exports_generator" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="exports_generator">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
7
.idea/runConfigurations/linux_exports_generator__32_.xml
generated
Normal file
7
.idea/runConfigurations/linux_exports_generator__32_.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<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">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
7
.idea/runConfigurations/linux_exports_generator__64_.xml
generated
Normal file
7
.idea/runConfigurations/linux_exports_generator__64_.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="linux_exports_generator [64]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="--input_libs_glob $ProjectFileDir$/res/steamworks/*/binaries/linux64/libsteam_api.so --output_path $ProjectFileDir$/src/generated/64/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">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
2
.idea/runConfigurations/steamworks_parser.xml
generated
2
.idea/runConfigurations/steamworks_parser.xml
generated
@@ -1,5 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="steamworks_parser" type="CMakeRunConfiguration" factoryName="Application" 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_parser" CONFIG_NAME="Debug [64]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_parser">
|
||||
<configuration default="false" name="steamworks_parser" type="CMakeRunConfiguration" factoryName="Application" 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_parser" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_parser">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
|
||||
7
.idea/runConfigurations/windows_exports_generator__64_.xml
generated
Normal file
7
.idea/runConfigurations/windows_exports_generator__64_.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="windows_exports_generator [64]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="--forwarded_dll_name "steam_api64_o" --lib_files_glob "$ProjectFileDir$\res\steamworks\*\binaries\steam_api64.dll" --output_file_path "$CMakeCurrentGenerationDir$\generated\linker_exports_for_steam_api.h" --sources_input_path """ REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="windows_exports_generator" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="windows_exports_generator">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,11 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(SmokeAPI VERSION 3.1.3)
|
||||
project(SmokeAPI VERSION 4.0.0)
|
||||
|
||||
include(KoalaBox/cmake/KoalaBox.cmake)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DKB_DEBUG)
|
||||
endif()
|
||||
add_subdirectory(KoalaBox)
|
||||
add_subdirectory(tools)
|
||||
|
||||
@@ -29,8 +26,22 @@ set(SMOKE_API_STATIC_SOURCES
|
||||
static/smoke_api/steamclient/steamclient.hpp
|
||||
)
|
||||
|
||||
if(IS_LINUX)
|
||||
set(GENERATED_SOURCES_DIR src/generated/${BITNESS})
|
||||
file(MAKE_DIRECTORY ${GENERATED_SOURCES_DIR})
|
||||
set(GENERATED_SOURCES
|
||||
${GENERATED_SOURCES_DIR}/proxy_exports.hpp
|
||||
${GENERATED_SOURCES_DIR}/proxy_exports.cpp
|
||||
)
|
||||
|
||||
foreach(SRC IN LISTS GENERATED_SOURCES)
|
||||
file(TOUCH ${SRC})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(SMOKE_API_SOURCES
|
||||
${SMOKE_API_STATIC_SOURCES}
|
||||
${GENERATED_SOURCES}
|
||||
src/smoke_api/smoke_api.cpp
|
||||
src/smoke_api/smoke_api.hpp
|
||||
src/steam_api/virtuals/isteamapps.cpp
|
||||
@@ -39,7 +50,6 @@ set(SMOKE_API_SOURCES
|
||||
src/steam_api/virtuals/isteamhttp.cpp
|
||||
src/steam_api/virtuals/isteaminventory.cpp
|
||||
src/steam_api/virtuals/isteamuser.cpp
|
||||
src/steam_api/virtuals/isteamutils.cpp
|
||||
src/steam_api/virtuals/steam_api_virtuals.hpp
|
||||
src/steam_api/steam_client.hpp
|
||||
src/steam_api/steam_client.cpp
|
||||
@@ -54,7 +64,6 @@ if(WIN32)
|
||||
|
||||
list(APPEND SMOKE_API_SOURCES src/main_win.cpp)
|
||||
else()
|
||||
set_32_and_64(LINUX_DIR linux32 linux64)
|
||||
set(STEAM_API_MODULE libsteam_api)
|
||||
set(STEAMCLIENT_DLL steamclient)
|
||||
|
||||
@@ -74,7 +83,6 @@ target_include_directories(SmokeAPI_common INTERFACE
|
||||
)
|
||||
target_link_libraries(SmokeAPI_common INTERFACE KoalaBox $<TARGET_OBJECTS:KoalaBox>)
|
||||
|
||||
|
||||
### Static SmokeAPI
|
||||
|
||||
add_library(SmokeAPI_static STATIC ${SMOKE_API_STATIC_SOURCES})
|
||||
@@ -106,23 +114,31 @@ if(WIN32)
|
||||
configure_linker_exports(
|
||||
TARGET SmokeAPI
|
||||
HEADER_NAME "linker_exports_for_steam_api.h"
|
||||
FORWARDED_DLL "${STEAM_API_MODULE}_o"
|
||||
INPUT_SOURCES_DIR ""
|
||||
DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${STEAM_API_MODULE}.dll"
|
||||
FORWARDED_DLL_NAME "${STEAM_API_MODULE}_o"
|
||||
LIB_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${STEAM_API_MODULE}.dll"
|
||||
SOURCES_INPUT_PATH ""
|
||||
)
|
||||
configure_linker_exports(
|
||||
TARGET SmokeAPI
|
||||
HEADER_NAME "linker_exports_for_version.h"
|
||||
FORWARDED_DLL "C:/Windows/System32/version.dll"
|
||||
INPUT_SOURCES_DIR ""
|
||||
DLL_FILES_GLOB "C:/Windows/System32/version.dll"
|
||||
|
||||
set(HEADER_CONTENT "#pragma once\n\n")
|
||||
|
||||
foreach(WIN_DLL version winhttp winmm)
|
||||
set(HEADER_NAME "linker_exports_for_${WIN_DLL}.h")
|
||||
configure_linker_exports(
|
||||
TARGET SmokeAPI
|
||||
HEADER_NAME "${HEADER_NAME}"
|
||||
FORWARDED_DLL_NAME "C:/Windows/System32/${WIN_DLL}.dll"
|
||||
LIB_FILES_GLOB "C:/Windows/System32/${WIN_DLL}.dll"
|
||||
SOURCES_INPUT_PATH ""
|
||||
)
|
||||
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#include <${HEADER_NAME}>\n")
|
||||
endforeach()
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/linker_exports_for_windows_dlls.h"
|
||||
CONTENT "${HEADER_CONTENT}"
|
||||
)
|
||||
else()
|
||||
# configure_linker_exports(
|
||||
# TARGET SmokeAPI
|
||||
# HEADER_NAME "libsteam_api_exports.cpp"
|
||||
# FORWARDED_DLL "${STEAM_API_MODULE}_o.so"
|
||||
# DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${LINUX_DIR}/${STEAM_API_MODULE}.so"
|
||||
# INPUT_SOURCES_DIR ""
|
||||
# )
|
||||
|
||||
# Ignore linker warnings regarding COM-related private exports
|
||||
set_target_properties(SmokeAPI PROPERTIES LINK_FLAGS "/ignore:4104")
|
||||
endif()
|
||||
|
||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: 44be3bf94f...7db1eb5602
164
README.md
164
README.md
@@ -3,12 +3,15 @@
|
||||
# SmokeAPI
|
||||
|
||||
|
||||
_Legit DLC Unlocker for Steamworks._
|
||||
|
||||
_Legit DLC ownership emulation for Steamworks._
|
||||
|
||||
## ✨ Features
|
||||
|
||||
* `🔓` Emulate DLC ownership in legitimately owned games
|
||||
* `🛅` Emulate Inventory item ownership
|
||||
* `📄` Optional configuration
|
||||
* `🐧` Support for 32-bit and 64-bit Windows and Linux systems
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
@@ -20,7 +23,7 @@ _Legit DLC Unlocker for Steamworks._
|
||||
|
||||
### ❓ What is SmokeAPI?
|
||||
|
||||
SmokeAPI is a DLC unlocker for games that are _legitimately_ owned in your Steam account.
|
||||
SmokeAPI is a tool for Steamworks DLC ownership emulation in games that are _legitimately_ owned in Steam.
|
||||
It attempts to fool games that use Steamworks SDK (Steamworks) into thinking that you own the game's DLCs.
|
||||
However, SmokeAPI does not modify the rest of the Steamworks, hence features like multiplayer, achievements, and so on remain fully functional.
|
||||
|
||||
@@ -33,7 +36,10 @@ Therefore, **you have to first research the game's topic**, to see if it support
|
||||
|
||||
Additionally, there are several points to bear in mind when it comes to unlocking DLCs with SmokeAPI:
|
||||
|
||||
* SmokeAPI most definitely will not work with games that use 3rd party DRM, such as games from Ubisoft, Rockstar, etc.* SmokeAPI is unlikely to unlock anything in Free-To-Play games since they typically store all player data on the corresponding game server and hence all the checks are server-side.
|
||||
|
||||
* SmokeAPI most definitely will not work with games that use 3rd party DRM, such as games from Ubisoft, Rockstar, etc.
|
||||
* SmokeAPI most likely will not work with games that use Denuvo SecureDLC.
|
||||
* SmokeAPI is unlikely to unlock anything in Free-To-Play games since they typically store all player data on the corresponding game server and hence all the checks are server-side.
|
||||
* SmokeAPI will not work with games that employ additional ownership protection or if the game is using alternative DLC verification mechanism.
|
||||
* SmokeAPI is unlikely to work with games that use an anti-cheat, since they typically detect any DLL/EXE that has been tampered with. Sometimes it is possible to disable an anti-cheat, but that typically entails the loss of online capabilities. Search in the respective game topic for more information about how to disable anti-cheat.
|
||||
* Some games include DLC files in their base game, regardless of whether you own the DLC or not. However, some games download additional DLC files only after a user has bought the corresponding DLC. In this case, not only will you need to install SmokeAPI, but you also have to get the additional DLC files from somewhere else and put them into the game folder. Up-to-date DLC files often can be found in corresponding game topics.
|
||||
@@ -66,13 +72,13 @@ SmokeAPI supports **2** installation modes: _Hook mode_ and _Proxy mode_.
|
||||
- **Advantages**:
|
||||
- Guaranteed to load
|
||||
- **Disadvantages**:
|
||||
- Might need reinstallation aftera game update
|
||||
- Might need reinstallation after a game update
|
||||
|
||||
My advice is to try installing the unlocker in hook mode first.
|
||||
If it doesn't work, try installing it in proxy mode instead.
|
||||
If that didn't work, refer to the _Troubleshooting_ section below.
|
||||
|
||||
## 🛠 Installation instructions
|
||||
## 🛠 Installation instructions (🪟 Windows)
|
||||
|
||||
> [!NOTE]
|
||||
> To determine the bitness of a game you can open _Task Manager_, navigate to _Details_ tab,
|
||||
@@ -81,37 +87,47 @@ If that didn't work, refer to the _Troubleshooting_ section below.
|
||||
|
||||
### 🪝 Hook mode
|
||||
|
||||
Hook mode itself has two sub-modes: Self-Hook and Hook with injector.
|
||||
|
||||
#### 🪝 Self-Hook mode
|
||||
|
||||
In self-hook mode SmokeAPI is injected automatically without the help of third-party injectors.
|
||||
It works best when a game doesn't have any protections against DLL injection.
|
||||
The main advantage of this mode is its minimal setup, which adds only 1 new DLL to the game folder.
|
||||
|
||||
- Download the [latest SmokeAPI release zip].
|
||||
- From this downloaded zip extract `SmokeAPI32.dll` or `SmokeAPI64.dll`, depending on a game's bitness.
|
||||
- Rename the unzipped DLL to `version.dll`.
|
||||
- Place this `version.dll` next to the game's `.exe` file.
|
||||
- From this downloaded zip extract `smoke_api32.dll` or `smoke_api64.dll`, depending on a game's bitness.
|
||||
- Rename the unzipped DLL to `version.dll` or `winhttp.dll` or `winmm.dll`.
|
||||
- Place this `version.dll` or `winhttp.dll` or `winmm.dll` next to the game's `.exe` file.
|
||||
|
||||
#### 🪝 Hook mode with Koaloader
|
||||
|
||||
If a game doesn't load
|
||||
`version.dll`, you can use an alternative injector to load SmokeAPI into the game process.
|
||||
If a game doesn't load `version.dll` or `winhttp.dll` or `winmm.dll`, you can use an alternative injector to load
|
||||
SmokeAPI into the game process.
|
||||
One such injector is [Koaloader], which supports different DLLs that a typical game might load.
|
||||
For example, assuming that the game loads `winmm.dll`:
|
||||
For example, assuming that the game loads `d3d11.dll`:
|
||||
|
||||
- Install Koaloader:
|
||||
- Download the [latest Koaloader release zip].
|
||||
- From this downloaded zip extract `winmm.dll` from `winmm-32` or `winmm-64`, depending on a game's bitness.
|
||||
- Place `winmm.dll` next to the game's `.exe` file.
|
||||
- From this downloaded zip extract `d3d11.dll` from `d3d11-32` or `d3d11-64`, depending on a game's bitness.
|
||||
- Place `d3d11.dll` next to the game's `.exe` file.
|
||||
- Install SmokeAPI
|
||||
- Download the [latest SmokeAPI release zip].
|
||||
- From this downloaded zip extract `SmokeAPI32.dll` or `SmokeAPI64.dll`, depending on a game's bitness.
|
||||
- Place `SmokeAPI32.dll` or `SmokeAPI64.dll` next to the game's `.exe` file.
|
||||
- From this downloaded zip extract `smoke_api32.dll` or `smoke_api64.dll`, depending on a game's bitness.
|
||||
- Place `smoke_api32.dll` or `smoke_api64.dll` next to the game's `.exe` file.
|
||||
|
||||
#### 🪝 Hook mode with Special K
|
||||
|
||||
There are games which have extra protections that break hook mode.
|
||||
In such cases, it might be worth trying [Special K], which can inject SmokeAPI as a [custom plugin].
|
||||
|
||||
---
|
||||
|
||||
### 🔀 Proxy mode
|
||||
|
||||
- Find a `steam_api.dll` or `steam_api64.dll` file in game directory, and rename it to `steam_api_o.dll` or `steam_api64_o.dll`.
|
||||
- Download the [latest SmokeAPI release zip].
|
||||
- From this downloaded zip extract `SmokeAPI32.dll` or `SmokeAPI64.dll`, depending on a game's bitness.
|
||||
- From this downloaded zip extract `smoke_api32.dll` or `smoke_api64.dll`, depending on a game's bitness.
|
||||
- Rename this extracted DLL to `steam_api.dll` or `steam_api64.dll`, depending on a game's bitness.
|
||||
- Place this renamed unlocker DLL next to the `steam_api_o.dll` or `steam_api64_o.dll` file.
|
||||
|
||||
@@ -120,6 +136,105 @@ In such cases, it might be worth trying [Special K], which can inject SmokeAPI a
|
||||
[Special K]: https://www.special-k.info
|
||||
[custom plugin]: https://wiki.special-k.info/en/SpecialK/Tools#custom-plugin
|
||||
|
||||
## 🛠️ Installation instructions (🐧 Linux)
|
||||
|
||||
> [!NOTE]
|
||||
> Linux support in SmokeAPI is highly experimental/unstable and has known issues.
|
||||
> If none of the methods below work for you, then consider running a Windows version of a game
|
||||
> via Proton compatibility layer and follow the instructions in the Windows section.
|
||||
|
||||
### ✔️ Requirements
|
||||
|
||||
Linux builds of SmokeAPI depend on several libraries. Make sure they are installed on your system.
|
||||
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.
|
||||
|
||||
Required libraries:
|
||||
- [brotli](https://archlinux.org/packages/core/x86_64/brotli/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-brotli/)]
|
||||
|
||||
- [gcc-libs](https://archlinux.org/packages/core/x86_64/gcc-libs/)
|
||||
[[32-bit](https://archlinux.org/packages/core/x86_64/lib32-gcc-libs/)]
|
||||
|
||||
- [glibc](https://archlinux.org/packages/core/x86_64/glibc/)
|
||||
[[32-bit](https://archlinux.org/packages/core/x86_64/lib32-glibc/)]
|
||||
|
||||
- [libidn2](https://archlinux.org/packages/core/x86_64/libidn2/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-libidn2/)]
|
||||
|
||||
- [libnghttp2](https://archlinux.org/packages/core/x86_64/libnghttp2/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-libnghttp2/)]
|
||||
|
||||
- [libssh2](https://archlinux.org/packages/core/x86_64/libssh2/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-libssh2/)]
|
||||
|
||||
- [openssl](https://archlinux.org/packages/core/x86_64/openssl/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-openssl/)]
|
||||
|
||||
- [zlib](https://archlinux.org/packages/core/x86_64/zlib/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-zlib/)]
|
||||
|
||||
- [zstd](https://archlinux.org/packages/core/x86_64/zstd/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-zstd/)]
|
||||
|
||||
|
||||
Optional libraries:
|
||||
- [gtk3](https://archlinux.org/packages/extra/x86_64/gtk3/)
|
||||
[[32-bit](https://archlinux.org/packages/multilib/x86_64/lib32-gtk3/)]
|
||||
|
||||
---
|
||||
|
||||
Just like on Windows, SmokeAPI features 32 and 64-bit Linux builds.
|
||||
In release archive they are named as `libsmoke_api32.so` or `libsmoke_api64.so` respectively.
|
||||
However, unlike Windows, it is recommended to use proxy mode, rather than hook mode.
|
||||
This is because the current hook mode installation method has to directly launch game
|
||||
executable. However, by default Steam doesn't do that, instead it launches certain wrappers
|
||||
that setup game environment with optimal parameters. Hence, launching a game without those
|
||||
wrappers might cause issues in theory. However, in practice real tests show that hook mode has higher
|
||||
chance of success compared to proxy mode. So, at the end of the day, try both modes to see which one works
|
||||
best for you.
|
||||
|
||||
|
||||
### 🔀 Proxy mode (🐧 Linux)
|
||||
|
||||
Same as on Windows:
|
||||
1. Rename the original `libsteam_api.so` to `libsteam_api_o.so`
|
||||
2. Extract and paste the `libsmoke_api32.so` or `libsmoke_api64.so` to the same directory, renaming it to `libsteam_api.so`.
|
||||
|
||||
### 🪝 Hook mode (🐧 Linux)
|
||||
|
||||
Linux doesn't have the same easily exploitable library injection mechanism that Windows has.
|
||||
However, it is possible to force any Linux executable to load any library by using the
|
||||
`LD_PRELOAD` environment variable. In fact, Steam itself already uses that to inject its overlay,
|
||||
hence we can use it as well. But we have to include that overlay library as well when specifying
|
||||
`LD_PRELOAD`, otherwise the game will be launched with SmokeAPI, but without Steam overlay.
|
||||
|
||||
For example:
|
||||
|
||||
1. Extract and paste the `libsmoke_api32.so` or `libsmoke_api64.so` in the root of game's installation directory.
|
||||
2. In Steam _Library_ open game's _Properties_, switch to the _General_ tab, and set the following _LAUNCH OPTIONS_:
|
||||
|
||||
| Bitness | Launch Options |
|
||||
|---------|------------------------------------------------------------------------------------------------------------------------|
|
||||
| 32-bit | `LD_PRELOAD="./libsmoke_api32.so $HOME/.local/share/Steam/ubuntu12_32/gameoverlayrenderer.so" ./<GameExe32> %command%` |
|
||||
| 64-bit | `LD_PRELOAD="./libsmoke_api64.so $HOME/.local/share/Steam/ubuntu12_64/gameoverlayrenderer.so" ./<GameExe64> %command%` |
|
||||
|
||||
Where `<GameExe32>` and `<GameExe64>` correspond to the actual filename of the game executable. For example:
|
||||
- `TheEscapists2.x86` (32-bit)
|
||||
- `TheEscapists2.x86_64` (64-bit)
|
||||
- `_linux/darkest.bin.x86` (32-bit)
|
||||
- `_linux/darkest.bin.x86_64` (64-bit)
|
||||
- `bin/linux_x64/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
|
||||
file name as it is. Naturally, the exact options might change depending on where files are located on your filesystem
|
||||
and other environment variables you might have specified previously.
|
||||
If you have other environment variables, and you don't know how to correctly combine them,
|
||||
then please make extensive use of search engines and LLMs for guidance and examples
|
||||
before seeking help the official forum topic.
|
||||
|
||||
|
||||
## ⚙ Configuration
|
||||
|
||||
SmokeAPI does not require any manual configuration.
|
||||
@@ -171,7 +286,7 @@ Below you can find an example config where nearly every option has been customiz
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v4.0.0/res/SmokeAPI.schema.json",
|
||||
"$version": 4,
|
||||
"logging": true,
|
||||
"log_steam_http": true,
|
||||
@@ -208,11 +323,12 @@ Below you can find an example config where nearly every option has been customiz
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## 🎓 Extra info
|
||||
|
||||
### 🔑 How SmokeAPI works in games with large number of DLCs
|
||||
|
||||
Some games that have a large number of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs.
|
||||
Some the games that have a large number of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs.
|
||||
Once the game receives the list, it will go over each item and check the ownership.
|
||||
The issue arises from the fact that response from Steamworks SDK may max out at 64, depending on how much unowned DLCs the user has.
|
||||
To alleviate this issue, SmokeAPI will make a web request to Steam API for a full list of DLCs, which works well most of the time.
|
||||
@@ -254,10 +370,10 @@ If you have made sure that you picked the right DLL for Koaloader, then try addi
|
||||
|
||||
### 💥 The game is crashing
|
||||
|
||||
If the game is crashing or not opening as expected after installing an unlocker, then try to download and install the latest [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017, 2019, and 2022](https://support.microsoft.com/en-gb/help/2977003/the-latest-supported-visual-c-downloads)
|
||||
<details><summary>Download page</summary>
|
||||
If the game is crashing or not opening as expected after installing an unlocker, then try to download and install the [Latest supported Visual C++ Redistributable version](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-supported-redistributable-version)
|
||||
<details><summary>Download page screenshot</summary>
|
||||
|
||||

|
||||

|
||||
</details>
|
||||
|
||||
## 🏗️ Building from source
|
||||
@@ -290,6 +406,7 @@ For example:
|
||||
```
|
||||
|
||||
[Visual Studio Build Tools 2022]: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022
|
||||
|
||||
[CMake]: https://cmake.org/
|
||||
|
||||
## 📚 Acknowledgments
|
||||
@@ -307,12 +424,17 @@ This project makes use of the following open source projects:
|
||||
- [microsoft/wil](https://github.com/microsoft/wil)
|
||||
- [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)
|
||||
- [bshoshany/thread-pool](https://github.com/bshoshany/thread-pool)
|
||||
- [batterycenter/embed](https://github.com/batterycenter/embed)
|
||||
|
||||
r
|
||||
|
||||
## 📄 License
|
||||
|
||||
This software is licensed under the [Unlicense](https://unlicense.org),
|
||||
terms of which are available in [UNLICENSE.txt](UNLICENSE.txt).
|
||||
|
||||
|
||||
[Koaloader]: https://github.com/acidicoala/Koaloader
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
{% extends "./KoalaBox/templates/README.base.md" %}
|
||||
{% block content %}
|
||||
|
||||
_Legit DLC Unlocker for Steamworks._
|
||||
_Legit DLC ownership emulation for Steamworks._
|
||||
|
||||
## ✨ Features
|
||||
|
||||
* `🔓` Emulate DLC ownership in legitimately owned games
|
||||
* `🛅` Emulate Inventory item ownership
|
||||
* `📄` Optional configuration
|
||||
* `🐧` Support for 32-bit and 64-bit Windows and Linux systems
|
||||
|
||||
{% include "KoalaBox/templates/markdown/links.md" %}
|
||||
|
||||
|
||||
{% include "KoalaBox/templates/markdown/intro.md" %}
|
||||
|
||||
|
||||
{% include "KoalaBox/templates/markdown/usage.md" %}
|
||||
|
||||
{% include "KoalaBox/templates/markdown/install-win.md" %}
|
||||
|
||||
{% include "KoalaBox/templates/markdown/installation.md" %}
|
||||
|
||||
{% include "KoalaBox/templates/markdown/install-linux.md" %}
|
||||
|
||||
{% include "KoalaBox/templates/markdown/configuration.md" %}
|
||||
|
||||
@@ -26,7 +26,7 @@ _Legit DLC Unlocker for Steamworks._
|
||||
|
||||
### 🔑 How SmokeAPI works in games with large number of DLCs
|
||||
|
||||
Some games that have a large number of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs.
|
||||
Some the games that have a large number of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs.
|
||||
Once the game receives the list, it will go over each item and check the ownership.
|
||||
The issue arises from the fact that response from Steamworks SDK may max out at 64, depending on how much unowned DLCs the user has.
|
||||
To alleviate this issue, SmokeAPI will make a web request to Steam API for a full list of DLCs, which works well most of the time.
|
||||
@@ -46,14 +46,9 @@ They will be added to the list of missing DLC IDs to facilitate config-less oper
|
||||
|
||||
{% include "KoalaBox/templates/markdown/troubleshooting.md" %}
|
||||
|
||||
|
||||
{% include "KoalaBox/templates/markdown/building.md" %}
|
||||
|
||||
|
||||
{% include "KoalaBox/templates/markdown/acknowledgements.md" %}
|
||||
{% block extra_oss_libs %}
|
||||
- [bshoshany/thread-pool](https://github.com/bshoshany/thread-pool)
|
||||
{% include "KoalaBox/templates/markdown/acknowledgements.md" %}{% block extra_oss_libs %}- [bshoshany/thread-pool](https://github.com/bshoshany/thread-pool)
|
||||
- [batterycenter/embed](https://github.com/batterycenter/embed)
|
||||
- [serge1/ELFIO](https://github.com/serge1/ELFIO)
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v4.0.0/res/SmokeAPI.schema.json",
|
||||
"$version": 4,
|
||||
"logging": true,
|
||||
"log_steam_http": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$id": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v4.0.0/res/SmokeAPI.schema.json",
|
||||
"title": "SmokeAPI configuration",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -120,7 +120,7 @@
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v4.0.0/res/SmokeAPI.schema.json",
|
||||
"$version": 4,
|
||||
"logging": true,
|
||||
"log_steam_http": true,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#define STEAM_API_MODULE "${STEAM_API_MODULE}"
|
||||
#define STEAMCLIENT_DLL "${STEAMCLIENT_DLL}"
|
||||
#define STEAMCLIENT_DLL "${STEAMCLIENT_DLL}"
|
||||
|
||||
14844
src/generated/32/proxy_exports.cpp
Normal file
14844
src/generated/32/proxy_exports.cpp
Normal file
File diff suppressed because it is too large
Load Diff
6
src/generated/32/proxy_exports.hpp
Normal file
6
src/generated/32/proxy_exports.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
// Auto-generated header file
|
||||
#pragma once
|
||||
|
||||
namespace proxy_exports {
|
||||
void init(void* self_lib_handle, void* original_lib_handle);
|
||||
}
|
||||
14454
src/generated/64/proxy_exports.cpp
Normal file
14454
src/generated/64/proxy_exports.cpp
Normal file
File diff suppressed because it is too large
Load Diff
6
src/generated/64/proxy_exports.hpp
Normal file
6
src/generated/64/proxy_exports.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
// Auto-generated header file
|
||||
#pragma once
|
||||
|
||||
namespace proxy_exports {
|
||||
void init(void* self_lib_handle, void* original_lib_handle);
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
// ReSharper disable CppUnusedIncludeDirective
|
||||
#include <koalabox/win.hpp>
|
||||
|
||||
#include "smoke_api/smoke_api.hpp"
|
||||
|
||||
// This header will be populated at build time
|
||||
// These headers will be populated at build time
|
||||
#include "linker_exports_for_steam_api.h"
|
||||
#include "linker_exports_for_version.h"
|
||||
#include "linker_exports_for_windows_dlls.h"
|
||||
|
||||
DLL_MAIN(void* handle, const uint32_t reason, void*) {
|
||||
if(reason == DLL_PROCESS_ATTACH) {
|
||||
|
||||
@@ -1,25 +1,38 @@
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
||||
#include <glob/glob.h>
|
||||
#include <polyhook2/MemProtector.hpp>
|
||||
|
||||
#include <koalabox/config.hpp>
|
||||
#include <koalabox/lib_monitor.hpp>
|
||||
#include <koalabox/globals.hpp>
|
||||
#include <koalabox/hook.hpp>
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/lib.hpp>
|
||||
#include <koalabox/lib_monitor.hpp>
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/path.hpp>
|
||||
#include <koalabox/paths.hpp>
|
||||
#include <koalabox/platform.hpp>
|
||||
#include <koalabox/util.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
|
||||
// static
|
||||
#include "smoke_api/config.hpp"
|
||||
#include "smoke_api/steamclient/steamclient.hpp"
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "steam_api/steam_interfaces.hpp"
|
||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
#include "build_config.h"
|
||||
|
||||
#if defined(KB_WIN)
|
||||
#include "koalabox/win.hpp"
|
||||
#elif defined(KB_LINUX) && defined(KB_32)
|
||||
#include "generated/32/proxy_exports.hpp"
|
||||
#elif defined(KB_LINUX) && defined(KB_64)
|
||||
#include "generated/64/proxy_exports.hpp"
|
||||
#endif
|
||||
|
||||
// Hooking steam_api has shown itself to be less desirable than steamclient
|
||||
// for the reasons outlined below:
|
||||
//
|
||||
@@ -42,6 +55,7 @@ namespace {
|
||||
namespace kb = koalabox;
|
||||
|
||||
void* original_steamapi_handle = nullptr;
|
||||
bool is_hook_mode;
|
||||
|
||||
std::set<std::string> find_steamclient_versions(void* steamapi_handle) {
|
||||
if(!steamapi_handle) {
|
||||
@@ -61,11 +75,13 @@ namespace {
|
||||
versions.insert(i->str());
|
||||
}
|
||||
|
||||
LOG_DEBUG("Found {} steamclient version(s) in read-only section: {}", versions.size(), versions);
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
void warn_if_late_injection(const std::string& steamclient_version) {
|
||||
#ifdef KB_WIN
|
||||
void warn_if_late_injection(const std::string& steamclient_version) {
|
||||
if(kb::util::is_wine_env()) {
|
||||
return;
|
||||
}
|
||||
@@ -77,22 +93,30 @@ namespace {
|
||||
"Probable cause: SmokeAPI was injected too late. If possible, try injecting it earlier."
|
||||
);
|
||||
LOG_WARN("NOTE: You can safely ignore this warning if running under Proton or native Linux");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// ReSharper disable once CppDFAConstantFunctionResult
|
||||
bool on_steamclient_loaded(void* steamclient_handle) {
|
||||
static const auto CreateInterface$ = KB_MOD_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
KB_HOOK_DETOUR_MODULE(CreateInterface, steamclient_handle);
|
||||
|
||||
auto* steamapi_handle = original_steamapi_handle
|
||||
? original_steamapi_handle
|
||||
: kb::lib::get_library_handle(STEAM_API_MODULE);
|
||||
if(steamapi_handle) {
|
||||
if(!is_hook_mode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for late hooking
|
||||
|
||||
static const auto CreateInterface$ = KB_LIB_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
|
||||
if(auto* steamapi_handle = kb::lib::get_lib_handle(STEAM_API_MODULE)) {
|
||||
// SteamAPI might have been initialized.
|
||||
// Hence, we need to query SteamClient interfaces and hook them if needed.
|
||||
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
|
||||
warn_if_late_injection(steamclient_version);
|
||||
#endif
|
||||
|
||||
steam_interfaces::hook_steamclient_interface(steamclient_handle, steamclient_version);
|
||||
} else {
|
||||
@@ -101,22 +125,109 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
KB_HOOK_DETOUR_MODULE(CreateInterface, steamclient_handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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 {
|
||||
const DECLARE_ARGS();
|
||||
|
||||
const auto& version_map = steam_interfaces::get_interface_name_to_version_map();
|
||||
THIS = CreateInterface(version_map.at("ISteamClient").c_str(), nullptr);
|
||||
if(THIS) {
|
||||
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");
|
||||
THIS = get_steam_utils(ARGS(steam_pipe, utils_version.c_str()));
|
||||
if(THIS) {
|
||||
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;
|
||||
}
|
||||
|
||||
void init_hook_mode([[maybe_unused]] void* self_module_handle) {
|
||||
is_hook_mode = true;
|
||||
#ifdef KB_LINUX
|
||||
// Because we got injected via LD_PRELOAD,
|
||||
// Linux loader will resolve all SteamAPI exports in unlocker instead of original library.
|
||||
// Hence, we need to patch the stubs even in hook mode.
|
||||
|
||||
const std::string lib_name = STEAM_API_MODULE ".so";
|
||||
for(const auto& lib_path : glob::rglob({"./" + lib_name, "**/" + lib_name})) {
|
||||
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));
|
||||
|
||||
original_steamapi_handle = *lib_handle;
|
||||
proxy_exports::init(self_module_handle, original_steamapi_handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!original_steamapi_handle) {
|
||||
kb::util::panic("Failed to find original " + lib_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void init_proxy_mode([[maybe_unused]] void* self_module_handle) {
|
||||
is_hook_mode = true;
|
||||
|
||||
original_steamapi_handle = kb::lib::load_original_library(kb::paths::get_self_dir(), STEAM_API_MODULE);
|
||||
#ifdef KB_LINUX
|
||||
proxy_exports::init(self_module_handle, original_steamapi_handle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace smoke_api {
|
||||
void init(void* module_handle) {
|
||||
void init(void* self_module_handle) {
|
||||
try {
|
||||
kb::globals::init_globals(module_handle, PROJECT_NAME);
|
||||
static std::mutex section;
|
||||
const std::lock_guard lock(section);
|
||||
|
||||
static bool init_complete = false;
|
||||
if(init_complete) {
|
||||
LOG_ERROR("{} is already initialized", PROJECT_NAME);
|
||||
}
|
||||
|
||||
kb::globals::init_globals(self_module_handle, PROJECT_NAME);
|
||||
|
||||
config::instance = kb::config::parse<config::Config>();
|
||||
|
||||
@@ -126,34 +237,33 @@ namespace smoke_api {
|
||||
kb::logger::init_null_logger();
|
||||
}
|
||||
|
||||
LOG_INFO("{} v{} | Built at '{}'", PROJECT_NAME, PROJECT_VERSION, __TIMESTAMP__);
|
||||
LOG_INFO("{} v{}{} | Built at '{}'", PROJECT_NAME, PROJECT_VERSION, VERSION_SUFFIX, __TIMESTAMP__);
|
||||
LOG_DEBUG("Parsed config:\n{}", nlohmann::ordered_json(config::instance).dump(2));
|
||||
|
||||
const auto exe_path = kb::lib::get_fs_path(nullptr);
|
||||
const auto exe_name = kb::path::to_str(exe_path.filename());
|
||||
|
||||
LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::util::BITNESS);
|
||||
LOG_DEBUG("Self handle: {}", module_handle);
|
||||
LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::platform::bitness);
|
||||
LOG_DEBUG("Self name: '{}'", kb::path::to_str(kb::lib::get_fs_path(self_module_handle).filename()));
|
||||
|
||||
#ifdef KB_WIN
|
||||
kb::win::check_self_duplicates();
|
||||
#endif
|
||||
|
||||
// We need to hook functions in either mode
|
||||
kb::hook::init(true);
|
||||
|
||||
if(kb::hook::is_hook_mode(module_handle, STEAM_API_MODULE)) {
|
||||
if(kb::hook::is_hook_mode(self_module_handle, STEAM_API_MODULE)) {
|
||||
LOG_INFO("Detected hook mode");
|
||||
|
||||
init_lib_monitor();
|
||||
init_hook_mode(self_module_handle);
|
||||
} else {
|
||||
LOG_INFO("Detected proxy mode");
|
||||
|
||||
init_lib_monitor();
|
||||
|
||||
const auto self_path = kb::paths::get_self_dir();
|
||||
original_steamapi_handle = kb::lib::load_original_library(
|
||||
self_path,
|
||||
STEAM_API_MODULE
|
||||
);
|
||||
init_proxy_mode(self_module_handle);
|
||||
}
|
||||
|
||||
init_lib_monitor();
|
||||
|
||||
init_complete = true;
|
||||
LOG_INFO("Initialization complete");
|
||||
} catch(const std::exception& e) {
|
||||
kb::util::panic(std::format("Initialization error: {}", e.what()));
|
||||
@@ -162,8 +272,13 @@ namespace smoke_api {
|
||||
|
||||
void shutdown() {
|
||||
try {
|
||||
static bool shutdown_complete = false;
|
||||
if(shutdown_complete) {
|
||||
LOG_ERROR("{} is already shut down", PROJECT_NAME);
|
||||
}
|
||||
|
||||
if(original_steamapi_handle != nullptr) {
|
||||
kb::lib::unload_library(original_steamapi_handle);
|
||||
kb::lib::unload(original_steamapi_handle);
|
||||
original_steamapi_handle = nullptr;
|
||||
}
|
||||
|
||||
@@ -173,6 +288,7 @@ namespace smoke_api {
|
||||
|
||||
// TODO: Unhook everything
|
||||
|
||||
shutdown_complete = true;
|
||||
LOG_INFO("Shutdown complete");
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("Shutdown error: {}", e.what());
|
||||
@@ -182,50 +298,28 @@ namespace smoke_api {
|
||||
}
|
||||
|
||||
AppId_t get_app_id() {
|
||||
static AppId_t app_id = 0;
|
||||
if(app_id) {
|
||||
return app_id; // cached value
|
||||
static AppId_t cached_app_id = 0;
|
||||
if(cached_app_id) {
|
||||
return cached_app_id;
|
||||
}
|
||||
|
||||
try {
|
||||
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);
|
||||
LOG_DEBUG("No cached App ID found. Searching in environment variables.");
|
||||
|
||||
return app_id;
|
||||
}
|
||||
} catch(std::exception&) {
|
||||
LOG_WARN("No SteamAppId in environment. Falling back to ISteamUtils::GetAppID.");
|
||||
if(const auto opt_app_id = get_app_id_from_env()) {
|
||||
return cached_app_id = *opt_app_id;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
DECLARE_ARGS();
|
||||
// IDEA: Try to read steam_appid.txt here. SteamAppId env var is not available when it's present.
|
||||
// But what if the ID specified in steam_appid.txt is invalid?
|
||||
|
||||
THIS = CreateInterface("SteamClient007", nullptr);
|
||||
if(!THIS) {
|
||||
LOG_ERROR("Failed to create SteamClient interface");
|
||||
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;
|
||||
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");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,8 @@
|
||||
|
||||
#include "smoke_api/types.hpp"
|
||||
|
||||
constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
|
||||
constexpr auto STEAM_CLIENT = "SteamClient";
|
||||
constexpr auto STEAM_HTTP = "STEAMHTTP_INTERFACE_VERSION";
|
||||
constexpr auto STEAM_USER = "SteamUser";
|
||||
constexpr auto STEAM_UTILS = "SteamUtils";
|
||||
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
|
||||
constexpr auto STEAM_GAME_SERVER = "SteamGameServer";
|
||||
|
||||
// IMPORTANT: DLL_EXPORT is hardcoded in exports_generator.cpp,
|
||||
// so any name changes here must be reflected there as well.
|
||||
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec(dllexport) TYPE __cdecl
|
||||
|
||||
namespace smoke_api {
|
||||
|
||||
void init(void* module_handle);
|
||||
void init(void* self_module_handle);
|
||||
void shutdown();
|
||||
|
||||
AppId_t get_app_id();
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "smoke_api/steamclient/steamclient.hpp"
|
||||
|
||||
#include "steam_api/steam_interfaces.hpp"
|
||||
#include "smoke_api/smoke_api.hpp"
|
||||
#include "virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
namespace {
|
||||
@@ -37,7 +36,7 @@ namespace {
|
||||
|
||||
return {
|
||||
{
|
||||
STEAM_APPS,
|
||||
"STEAMAPPS_INTERFACE_VERSION",
|
||||
interface_data_t{
|
||||
.fallback_version = "STEAMAPPS_INTERFACE_VERSION008",
|
||||
.entry_map = {
|
||||
@@ -49,7 +48,7 @@ namespace {
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_CLIENT,
|
||||
steam_interfaces::STEAM_CLIENT,
|
||||
interface_data_t{
|
||||
.fallback_version = "SteamClient021",
|
||||
.entry_map = {
|
||||
@@ -61,7 +60,7 @@ namespace {
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_GAME_SERVER,
|
||||
"SteamGameServer",
|
||||
interface_data_t{
|
||||
.fallback_version = "SteamGameServer015",
|
||||
.entry_map = {
|
||||
@@ -70,7 +69,7 @@ namespace {
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_HTTP,
|
||||
"STEAMHTTP_INTERFACE_VERSION",
|
||||
interface_data_t{
|
||||
.fallback_version = "STEAMHTTP_INTERFACE_VERSION003",
|
||||
.entry_map = {
|
||||
@@ -81,7 +80,7 @@ namespace {
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_INVENTORY,
|
||||
"STEAMINVENTORY_INTERFACE_V",
|
||||
interface_data_t{
|
||||
.fallback_version = "STEAMINVENTORY_INTERFACE_V003",
|
||||
.entry_map = {
|
||||
@@ -96,7 +95,7 @@ namespace {
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_USER,
|
||||
"SteamUser",
|
||||
interface_data_t{
|
||||
.fallback_version = "SteamUser023",
|
||||
.entry_map = {
|
||||
@@ -104,15 +103,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_UTILS,
|
||||
interface_data_t{
|
||||
.fallback_version = "SteamUtils009",
|
||||
.entry_map = {
|
||||
ENTRY(ISteamUtils, GetAppID),
|
||||
}
|
||||
}
|
||||
},
|
||||
// Hooking SteamUtils for GetAppID should be avoided, since it leads to crashes in TW:WH3.
|
||||
// No idea why...
|
||||
};
|
||||
}
|
||||
|
||||
@@ -218,7 +210,7 @@ namespace steam_interfaces {
|
||||
// Map virtual hook map to a set of keys
|
||||
const auto prefixes = std::views::keys(virtual_hook_map) | std::ranges::to<std::set>();
|
||||
|
||||
const auto CreateInterface$ = KB_MOD_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
const auto CreateInterface$ = KB_LIB_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
|
||||
DECLARE_ARGS();
|
||||
THIS = CreateInterface$(steam_client_interface_version.c_str(), nullptr);
|
||||
@@ -257,4 +249,46 @@ namespace steam_interfaces {
|
||||
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,8 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#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 {
|
||||
constexpr auto STEAM_CLIENT = "SteamClient";
|
||||
|
||||
void hook_virtuals(const void* interface_ptr, const std::string& version_string);
|
||||
|
||||
/**
|
||||
@@ -15,4 +23,12 @@ namespace steam_interfaces {
|
||||
void* steamclient_handle,
|
||||
const std::string& steam_client_interface_version
|
||||
) 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();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItems(
|
||||
SteamItemDetails_t* pOutItemsArray,
|
||||
uint32_t* punOutItemsArraySize
|
||||
)
|
||||
) noexcept {
|
||||
) noexcept {
|
||||
return smoke_api::steam_inventory::GetResultItems(
|
||||
__func__,
|
||||
resultHandle,
|
||||
|
||||
@@ -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_GetISteamGenericInterface(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
|
||||
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;
|
||||
|
||||
// ISteamUtils
|
||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept;
|
||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept; // Unhooked
|
||||
|
||||
// ISteamGameServer
|
||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#include <koalabox/hook.hpp>
|
||||
|
||||
#ifdef KB_WIN
|
||||
#if defined(KB_WIN)
|
||||
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall // NOLINT(*-macro-parentheses)
|
||||
#define C_DECL(TYPE) extern "C" __declspec(noinline) TYPE __cdecl
|
||||
#elifdef KB_LINUX
|
||||
#elif defined(KB_LINUX)
|
||||
#define VIRTUAL(TYPE) __attribute__ ((__noinline__)) TYPE
|
||||
#define C_DECL(TYPE) extern "C" __attribute__ ((__noinline__)) TYPE
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@
|
||||
#define SWAPPED_CALL_CLOSURE(FUNC, ...) \
|
||||
[&] { SWAPPED_CALL(THIS, FUNC, __VA_ARGS__); }
|
||||
|
||||
#if defined(KB_WIN)
|
||||
/**
|
||||
* By default, virtual functions are declared with __thiscall
|
||||
* convention, which is normal since they are class members.
|
||||
@@ -46,12 +47,32 @@
|
||||
#define PARAMS(...) const void* RCX __VA_OPT__(,) __VA_ARGS__
|
||||
#define ARGS(...) RCX __VA_OPT__(,) __VA_ARGS__
|
||||
#define THIS RCX
|
||||
#define DECLARE_ARGS() const void* RCX = nullptr;
|
||||
#define DECLARE_ARGS() void* RCX = nullptr;
|
||||
#else
|
||||
#define PARAMS(...) const void* ECX, const void* EDX __VA_OPT__(,) __VA_ARGS__
|
||||
#define ARGS(...) ECX, EDX __VA_OPT__(,) __VA_ARGS__
|
||||
#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
|
||||
#elif defined(KB_LINUX)
|
||||
/**
|
||||
* In 64-bit mode, Linux binaries pass first 6 arguments via registers.
|
||||
* `this` pointer is passed as the first argument via the RDI register.
|
||||
*
|
||||
* In 32-bit mode, Linux binaries pass arguments via stack.
|
||||
* `this` pointer is passed as the first argument via the first stack parameter.
|
||||
*/
|
||||
#ifdef KB_64
|
||||
#define PARAMS(...) const void* $RDI __VA_OPT__(,) __VA_ARGS__
|
||||
#define ARGS(...) $RDI __VA_OPT__(,) __VA_ARGS__
|
||||
#define THIS $RDI
|
||||
#define DECLARE_ARGS() void* $RDI = nullptr;
|
||||
#else
|
||||
#define PARAMS(...) const void* $STACK1 __VA_OPT__(,) __VA_ARGS__
|
||||
#define ARGS(...) $STACK1 __VA_OPT__(,) __VA_ARGS__
|
||||
#define THIS $STACK1
|
||||
#define DECLARE_ARGS() void* $STACK1 = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using AppId_t = uint32_t;
|
||||
|
||||
12
sync.json
12
sync.json
@@ -5,16 +5,20 @@
|
||||
"store_name": "Steam",
|
||||
"store_sdk": "Steamworks",
|
||||
"store_sdk_full": "Steamworks SDK",
|
||||
"sdk_dll_names": "`steam_api.dll` or `steam_api64.dll`",
|
||||
"sdk_dll_orig_names": "`steam_api_o.dll` or `steam_api64_o.dll`",
|
||||
"sdk_libs_win": "`steam_api.dll` or `steam_api64.dll`",
|
||||
"sdk_libs_linux": "`libsteam_api.so`",
|
||||
"sdk_libs_orig_win": "`steam_api_o.dll` or `steam_api64_o.dll`",
|
||||
"sdk_libs_orig_linux": "`libsteam_api_o.so`",
|
||||
"show_3rd_party_point": true,
|
||||
"unlocker_dll_names": "`SmokeAPI32.dll` or `SmokeAPI64.dll`",
|
||||
"unlocker_libs_win": "`smoke_api32.dll` or `smoke_api64.dll`",
|
||||
"unlocker_libs_linux": "`libsmoke_api32.so` or `libsmoke_api64.so`",
|
||||
"config_filename": "SmokeAPI.config.json",
|
||||
"github_repo_url": "https://github.com/acidicoala/SmokeAPI",
|
||||
"forum_topic_url": "https://cs.rin.ru/forum/viewtopic.php?p=2597932#p2597932",
|
||||
"dlc_database": "SteamDB",
|
||||
"dlc_database_url": "https://steamdb.info/",
|
||||
"json_schema_path": "./res/SmokeAPI.schema.json"
|
||||
"json_schema_path": "./res/SmokeAPI.schema.json",
|
||||
"self_inject_dll": "`version.dll` or `winhttp.dll` or `winmm.dll`"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
|
||||
@@ -1,33 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(smoke-api-tools LANGUAGES CXX)
|
||||
|
||||
### Thread pool library
|
||||
|
||||
## https://github.com/bshoshany/thread-pool
|
||||
CPMAddPackage(
|
||||
NAME BS_thread_pool
|
||||
GITHUB_REPOSITORY bshoshany/thread-pool
|
||||
VERSION 5.0.0
|
||||
EXCLUDE_FROM_ALL
|
||||
SYSTEM
|
||||
)
|
||||
add_library(BS_thread_pool INTERFACE)
|
||||
target_include_directories(BS_thread_pool INTERFACE ${BS_thread_pool_SOURCE_DIR}/include)
|
||||
project(SmokeAPITools LANGUAGES CXX)
|
||||
|
||||
### Steamworks Downloader executable
|
||||
|
||||
CPMAddPackage("gh:serge1/ELFIO#Release_3.12")
|
||||
add_executable(steamworks_downloader src/steamworks_downloader.cpp)
|
||||
target_link_libraries(steamworks_downloader PRIVATE
|
||||
KoalaBox
|
||||
elfio
|
||||
)
|
||||
target_link_libraries(steamworks_downloader PRIVATE KoalaBoxTools)
|
||||
|
||||
### Steamworks Parser executable
|
||||
|
||||
add_executable(steamworks_parser src/steamworks_parser.cpp)
|
||||
target_link_libraries(steamworks_parser PRIVATE
|
||||
KoalaBox
|
||||
BS_thread_pool
|
||||
)
|
||||
target_link_libraries(steamworks_parser PRIVATE KoalaBoxTools)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/path.hpp>
|
||||
#include <koalabox/str.hpp>
|
||||
#include <koalabox/zip.hpp>
|
||||
#include <koalabox_tools/zip.hpp>
|
||||
|
||||
namespace {
|
||||
namespace fs = std::filesystem;
|
||||
@@ -90,7 +90,7 @@ namespace {
|
||||
}
|
||||
|
||||
void unzip_sdk(const fs::path& zip_file_path, const fs::path& unzip_dir) {
|
||||
kb::zip::extract_files(
|
||||
kb::tools::zip::extract_files(
|
||||
zip_file_path,
|
||||
[&](const std::string& name, const bool) {
|
||||
if(name.starts_with("sdk/public/steam/") && name.ends_with(".h")) {
|
||||
@@ -140,7 +140,7 @@ namespace {
|
||||
|
||||
fs::remove(zip_file_path);
|
||||
}
|
||||
} // namespace
|
||||
}
|
||||
|
||||
/**
|
||||
* A tool for downloading Steamworks SDK and unpacking its headers and binaries
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
#include <koalabox/io.hpp>
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/parser.hpp>
|
||||
#include <koalabox/path.hpp>
|
||||
#include <koalabox/str.hpp>
|
||||
|
||||
#include <koalabox_tools/parser.hpp>
|
||||
|
||||
namespace {
|
||||
namespace fs = std::filesystem;
|
||||
namespace kb = koalabox;
|
||||
namespace parser = kb::tools::parser;
|
||||
|
||||
std::string_view unquote_if_quoted(const std::string_view& s) {
|
||||
if(s.size() >= 2 && s.front() == '"' && s.back() == '"') {
|
||||
@@ -26,13 +28,13 @@ namespace {
|
||||
}
|
||||
|
||||
void parse_header(const std::string_view& source, nlohmann::ordered_json& lookup) {
|
||||
const auto tree = kb::parser::parse_source(source);
|
||||
const auto tree = parser::parse_source(source);
|
||||
const auto root = tree.getRootNode();
|
||||
|
||||
nlohmann::ordered_json current_lookup = {};
|
||||
std::string interface_version;
|
||||
|
||||
kb::parser::walk(
|
||||
parser::walk(
|
||||
root,
|
||||
[&](const ts::Node& current_node) {
|
||||
const auto current_type = current_node.getType();
|
||||
@@ -43,7 +45,7 @@ namespace {
|
||||
std::string interface_name;
|
||||
[[maybe_unused]] int vt_idx = 0;
|
||||
|
||||
kb::parser::walk(
|
||||
parser::walk(
|
||||
current_node,
|
||||
[&](const ts::Node& class_node) {
|
||||
const auto type = class_node.getType();
|
||||
@@ -53,12 +55,12 @@ namespace {
|
||||
interface_name = value;
|
||||
LOG_DEBUG("Found interface: {}", interface_name);
|
||||
|
||||
return kb::parser::visit_result::Continue;
|
||||
return parser::visit_result::Continue;
|
||||
}
|
||||
|
||||
if(type == "field_declaration" && value.starts_with("virtual ")) {
|
||||
if(value.starts_with("virtual ")) {
|
||||
kb::parser::walk(
|
||||
parser::walk(
|
||||
class_node,
|
||||
[&](const ts::Node& decl_node) {
|
||||
if(decl_node.getType() == "field_identifier") {
|
||||
@@ -71,29 +73,29 @@ namespace {
|
||||
// functions. Hence, no fixes have been implemented so far.
|
||||
|
||||
current_lookup[function_name] = vt_idx++;
|
||||
return kb::parser::visit_result::Stop;
|
||||
return parser::visit_result::Stop;
|
||||
}
|
||||
return kb::parser::visit_result::Continue;
|
||||
return parser::visit_result::Continue;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return kb::parser::visit_result::SkipChildren;
|
||||
return parser::visit_result::SkipChildren;
|
||||
}
|
||||
|
||||
return kb::parser::visit_result::Continue;
|
||||
return parser::visit_result::Continue;
|
||||
}
|
||||
);
|
||||
} else if(current_type == "preproc_def") {
|
||||
kb::parser::walk(
|
||||
parser::walk(
|
||||
current_node,
|
||||
[&](const ts::Node& preproc_node) {
|
||||
if(preproc_node.getType() == "identifier") {
|
||||
const auto identifier = preproc_node.getSourceRange(source);
|
||||
|
||||
return identifier.ends_with("INTERFACE_VERSION")
|
||||
? kb::parser::visit_result::Continue
|
||||
: kb::parser::visit_result::Stop;
|
||||
? parser::visit_result::Continue
|
||||
: parser::visit_result::Stop;
|
||||
}
|
||||
|
||||
if(preproc_node.getType() == "preproc_arg") {
|
||||
@@ -102,17 +104,17 @@ namespace {
|
||||
interface_version = unquote_if_quoted(trimmed_version);
|
||||
LOG_DEBUG("Interface version: {}", interface_version);
|
||||
|
||||
return kb::parser::visit_result::Stop;
|
||||
return parser::visit_result::Stop;
|
||||
}
|
||||
|
||||
return kb::parser::visit_result::Continue;
|
||||
return parser::visit_result::Continue;
|
||||
}
|
||||
);
|
||||
} else if(current_type == "translation_unit" || current_type == "preproc_ifdef") {
|
||||
return kb::parser::visit_result::Continue;
|
||||
return parser::visit_result::Continue;
|
||||
}
|
||||
|
||||
return kb::parser::visit_result::SkipChildren;
|
||||
return parser::visit_result::SkipChildren;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -155,7 +157,6 @@ namespace {
|
||||
for(const auto& entry : fs::directory_iterator(headers_dir)) {
|
||||
if(const auto& header_path = entry.path(); header_path.extension() == ".h") {
|
||||
const auto task = pool.submit_task(
|
||||
// NOLINT(*-unused-local-non-trivial-variable)
|
||||
[&, header_path] {
|
||||
try {
|
||||
LOG_DEBUG("Parsing header: {}", kb::path::to_str(header_path));
|
||||
@@ -164,7 +165,7 @@ namespace {
|
||||
parse_header(processed_header, lookup);
|
||||
} catch(std::exception& e) {
|
||||
LOG_CRITICAL(e.what());
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user