mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2026-01-26 14:32:54 -05:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee2d77115 | ||
|
|
4c08816eb6 | ||
|
|
6b4b7610f4 | ||
|
|
61ff1df065 | ||
|
|
141a0bcc58 | ||
|
|
bdab9b574f | ||
|
|
4581c36913 | ||
|
|
8ec9b4e374 | ||
|
|
c376b793c1 | ||
|
|
eac7e87880 | ||
|
|
09e1187ab0 | ||
|
|
6432eb3ec9 | ||
|
|
ec5778d452 | ||
|
|
1174dcb57a | ||
|
|
7685628b6f | ||
|
|
1e79ce103b | ||
|
|
49a8a76b28 | ||
|
|
dfbd7d00d9 |
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -4,16 +4,15 @@ on: push
|
|||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
name: CI
|
name: CI
|
||||||
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@a053502132e51e936820f27b7c99316fdb62b3e4
|
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@1bdfeefa9933092a747c46679b3d872470ef4998
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
with:
|
with:
|
||||||
modules: >-
|
arch: '[ 32, 64 ]'
|
||||||
["SmokeAPI"]
|
config: Release
|
||||||
|
modules: '[ "SmokeAPI" ]'
|
||||||
zip_command: >
|
zip_command: >
|
||||||
zip -j $ZIP_NAME
|
zip -j $ZIP_NAME
|
||||||
artifacts/*/*.dll
|
artifacts/*/*.dll
|
||||||
res/SmokeAPI.config.json
|
res/SmokeAPI.config.json
|
||||||
|
res/README.txt
|
||||||
config: Release
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.24)
|
cmake_minimum_required(VERSION 3.24)
|
||||||
|
|
||||||
project(SmokeAPI VERSION 3.0.0)
|
project(SmokeAPI VERSION 3.1.1)
|
||||||
|
|
||||||
include(KoalaBox/cmake/KoalaBox.cmake)
|
include(KoalaBox/cmake/KoalaBox.cmake)
|
||||||
|
|
||||||
@@ -9,13 +9,16 @@ add_subdirectory(tools)
|
|||||||
|
|
||||||
set_32_and_64(STEAMAPI_DLL steam_api)
|
set_32_and_64(STEAMAPI_DLL steam_api)
|
||||||
set_32_and_64(STEAMCLIENT_DLL steamclient)
|
set_32_and_64(STEAMCLIENT_DLL steamclient)
|
||||||
set_32_and_64(STEAM_API_DLL steam_api.dll steam_api64.dll)
|
set_32_and_64(STEAM_API_DLL steam_api steam_api64)
|
||||||
|
set_32_and_64(SMOKEAPI_DLL SmokeAPI32 SmokeAPI64)
|
||||||
|
|
||||||
configure_build_config(extra_build_config)
|
configure_build_config(extra_build_config)
|
||||||
|
|
||||||
set(SMOKE_API_STATIC_SOURCES
|
set(SMOKE_API_STATIC_SOURCES
|
||||||
static/smoke_api/interfaces/steam_apps.hpp
|
static/smoke_api/interfaces/steam_apps.hpp
|
||||||
static/smoke_api/interfaces/steam_apps.cpp
|
static/smoke_api/interfaces/steam_apps.cpp
|
||||||
|
static/smoke_api/interfaces/steam_http.hpp
|
||||||
|
static/smoke_api/interfaces/steam_http.cpp
|
||||||
static/smoke_api/interfaces/steam_inventory.hpp
|
static/smoke_api/interfaces/steam_inventory.hpp
|
||||||
static/smoke_api/interfaces/steam_inventory.cpp
|
static/smoke_api/interfaces/steam_inventory.cpp
|
||||||
static/smoke_api/interfaces/steam_user.hpp
|
static/smoke_api/interfaces/steam_user.hpp
|
||||||
@@ -33,55 +36,55 @@ set(SMOKE_API_STATIC_SOURCES
|
|||||||
|
|
||||||
set(SMOKE_API_SOURCES
|
set(SMOKE_API_SOURCES
|
||||||
${SMOKE_API_STATIC_SOURCES}
|
${SMOKE_API_STATIC_SOURCES}
|
||||||
src/steam_api/exports/steam_api.cpp
|
src/smoke_api/smoke_api.cpp
|
||||||
src/steam_api/exports/steam_api.hpp
|
src/smoke_api/smoke_api.hpp
|
||||||
src/steam_api/exports/steam_api_flat.cpp
|
|
||||||
src/steam_api/exports/steam_api_internal.cpp
|
|
||||||
src/steam_api/exports/steam_api_unversioned.cpp
|
|
||||||
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/isteamgameserver.cpp
|
||||||
|
src/steam_api/virtuals/isteamhttp.cpp
|
||||||
src/steam_api/virtuals/isteaminventory.cpp
|
src/steam_api/virtuals/isteaminventory.cpp
|
||||||
src/steam_api/virtuals/isteamuser.cpp
|
src/steam_api/virtuals/isteamuser.cpp
|
||||||
src/steam_api/virtuals/steam_api_virtuals.hpp
|
src/steam_api/virtuals/steam_api_virtuals.hpp
|
||||||
src/steam_api/steam_client.hpp
|
src/steam_api/steam_client.hpp
|
||||||
src/steam_api/steam_client.cpp
|
src/steam_api/steam_client.cpp
|
||||||
src/steam_api/steam_interface.cpp
|
src/steam_api/steam_interfaces.cpp
|
||||||
src/steam_api/steam_interface.hpp
|
src/steam_api/steam_interfaces.hpp
|
||||||
src/steamclient.cpp
|
src/steamclient/steamclient.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/smoke_api.cpp
|
|
||||||
src/smoke_api.hpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
### SmokeAPI interface
|
### SmokeAPI interface
|
||||||
|
|
||||||
add_library(SmokeAPI_interface INTERFACE)
|
add_library(SmokeAPI_common INTERFACE)
|
||||||
|
add_library(SmokeAPI::common ALIAS SmokeAPI_common)
|
||||||
|
|
||||||
target_include_directories(SmokeAPI_interface INTERFACE
|
target_include_directories(SmokeAPI_common INTERFACE
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/static>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/static>"
|
||||||
)
|
)
|
||||||
target_link_libraries(SmokeAPI_interface INTERFACE KoalaBox $<TARGET_OBJECTS:KoalaBox>)
|
target_link_libraries(SmokeAPI_common INTERFACE KoalaBox $<TARGET_OBJECTS:KoalaBox>)
|
||||||
|
|
||||||
|
|
||||||
### Static SmokeAPI
|
### Static SmokeAPI
|
||||||
|
|
||||||
add_library(SmokeAPI_static STATIC ${SMOKE_API_STATIC_SOURCES})
|
add_library(SmokeAPI_static STATIC ${SMOKE_API_STATIC_SOURCES})
|
||||||
target_link_libraries(SmokeAPI_static PUBLIC SmokeAPI_interface)
|
add_library(SmokeAPI::static ALIAS SmokeAPI_static)
|
||||||
|
|
||||||
|
target_link_libraries(SmokeAPI_static PUBLIC SmokeAPI::common)
|
||||||
|
|
||||||
### Shared SmokeAPI
|
### Shared SmokeAPI
|
||||||
|
|
||||||
add_library(SmokeAPI SHARED ${SMOKE_API_SOURCES})
|
add_library(SmokeAPI SHARED ${SMOKE_API_SOURCES})
|
||||||
target_link_libraries(SmokeAPI PUBLIC SmokeAPI_interface)
|
target_link_libraries(SmokeAPI PUBLIC SmokeAPI::common)
|
||||||
set_target_properties(SmokeAPI PROPERTIES RUNTIME_OUTPUT_NAME ${STEAMAPI_DLL})
|
set_target_properties(SmokeAPI PROPERTIES RUNTIME_OUTPUT_NAME ${SMOKEAPI_DLL})
|
||||||
configure_version_resource(
|
configure_version_resource(
|
||||||
TARGET SmokeAPI
|
TARGET SmokeAPI
|
||||||
FILE_DESC "Steamworks DLC unlocker"
|
FILE_DESC "Steamworks DLC unlocker"
|
||||||
ORIG_NAME ${STEAMAPI_DLL}
|
ORIG_NAME ${SMOKEAPI_DLL}
|
||||||
)
|
)
|
||||||
target_include_directories(SmokeAPI PRIVATE
|
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
|
## https://github.com/batterycenter/embed
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
@@ -94,8 +97,8 @@ configure_linker_exports(
|
|||||||
TARGET SmokeAPI
|
TARGET SmokeAPI
|
||||||
HEADER_NAME "linker_exports_for_steam_api"
|
HEADER_NAME "linker_exports_for_steam_api"
|
||||||
FORWARDED_DLL "${STEAMAPI_DLL}_o"
|
FORWARDED_DLL "${STEAMAPI_DLL}_o"
|
||||||
INPUT_SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/steam_api/exports"
|
INPUT_SOURCES_DIR ""
|
||||||
DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${STEAM_API_DLL}"
|
DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${STEAM_API_DLL}.dll"
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_linker_exports(
|
configure_linker_exports(
|
||||||
|
|||||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: a053502132...ceff9cfe5f
42
README.adoc
42
README.adoc
@@ -64,7 +64,7 @@ SmokeAPI supports 2 installation modes: hook mode and proxy mode.
|
|||||||
|Mode |Advantages |Disadvantages
|
|Mode |Advantages |Disadvantages
|
||||||
|
|
||||||
|🪝 Hook mode
|
|🪝 Hook mode
|
||||||
|Persists after game updates
|
|Persists after game updates; Can be loaded by other injectors.
|
||||||
|Might need an additional DLL (Koaloader)
|
|Might need an additional DLL (Koaloader)
|
||||||
|
|
||||||
|🔀 Proxy mode
|
|🔀 Proxy mode
|
||||||
@@ -79,9 +79,14 @@ 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 `SmokeAPI32.dll` / `SmokeAPI64.dll`, depending on the game bitness
|
||||||
|
. Rename the unpacked DLL to `version.dll`.
|
||||||
|
. Place `version.dll` next to the game's `.exe` file.
|
||||||
|
|
||||||
=== 🪝 Hook mode (Alternative)
|
=== 🪝 Hook mode (Alternative installation)
|
||||||
|
|
||||||
|
:special_k: https://www.special-k.info[Special K]
|
||||||
|
:custom_plugin: https://wiki.special-k.info/en/SpecialK/Tools#custom-plugin[custom plugin]
|
||||||
|
|
||||||
If a game doesn't load `version.dll`, you can use one of the {koaloader} DLLs that the game does in fact load.
|
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`:
|
For example, assuming that the game loads `winmm.dll`:
|
||||||
@@ -89,20 +94,31 @@ 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 `winmm.dll` from `winmm-32` or `winmm-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 `SmokeAPI32.dll` / `SmokeAPI64.dll`, depending on the game bitness.
|
||||||
|
. Place the unpacked DLL next to the game's `exe` file.
|
||||||
|
|
||||||
|
[[special_k_note]]
|
||||||
|
IMPORTANT: 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
|
==== 🔀 Proxy mode
|
||||||
|
|
||||||
. Find `steam_api.dll` / `steam_api64.dll` file in game directory, and rename it to `steam_api_o.dll` / `steam_api64_o.dll`.
|
. Find `steam_api.dll` / `steam_api64.dll` file in game directory, and rename it to `steam_api_o.dll` / `steam_api64_o.dll`.
|
||||||
. 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`/`steam_api64.dll`, depending on the game bitness, and place it next to the original steam_api DLL file.
|
. From SmokeAPI archive unpack `SmokeAPI32.dll` / `SmokeAPI64.dll`, depending on the game bitness.
|
||||||
|
. Rename the unpacked DLL to `steam_api.dll` / `steam_api64.dll` and place it next to the `steam_api_o.dll` / `steam_api64_o.dll` file.
|
||||||
|
|
||||||
|
IMPORTANT: There are games which have extra protections that break proxy mode.
|
||||||
|
In such cases, see the note on <<special_k_note, Hook mode with Special K>>
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
If the unlocker is not working as expected, then please fully read the https://gist.github.com/acidicoala/2c131cb90e251f97c0c1dbeaf2c174dc[Generic Unlocker Installation Instructions] before seeking support in the {forum-topic}.
|
If the unlocker is not working as expected, then please fully read the https://gist.github.com/acidicoala/2c131cb90e251f97c0c1dbeaf2c174dc[Generic Unlocker Installation Instructions] before seeking support in the {forum-topic}.
|
||||||
|
|
||||||
== ⚙ Configuration
|
== ⚙ Configuration
|
||||||
|
|
||||||
NOTE: This document describes configuration for version 3 of SmokeAPI.
|
NOTE: This document describes configuration for version 4 of SmokeAPI.
|
||||||
You can find the version 2 documentation https://github.com/acidicoala/SmokeAPI/blob/v2.0.5/README.md#-configuration[here].
|
You can find the version 3 documentation https://github.com/acidicoala/SmokeAPI/blob/v3.0.0/README.adoc#-configuration[here].
|
||||||
|
|
||||||
:fn-app-id: footnote:fn-app-id[App/DLC IDs can be obtained from https://steamdb.info[SteamDB] or https://steambase.io[Steambase]. Keep in mind that you need to be signed in with a steam account in order to see accurate inventory item IDs on that website.]
|
:fn-app-id: footnote:fn-app-id[App/DLC IDs can be obtained from https://steamdb.info[SteamDB] or https://steambase.io[Steambase]. Keep in mind that you need to be signed in with a steam account in order to see accurate inventory item IDs on that website.]
|
||||||
|
|
||||||
@@ -114,6 +130,7 @@ To use it, simply place it next to the SmokeAPI DLL.
|
|||||||
It will be read upon each launch of the game.
|
It will be read upon each launch of the game.
|
||||||
In the absence of the config file, default values specified below will be used.
|
In the absence of the config file, default values specified below will be used.
|
||||||
The configuration file is expected to conform to the JSON standard.
|
The configuration file is expected to conform to the JSON standard.
|
||||||
|
All options within the config file are optional.
|
||||||
|
|
||||||
`logging`:: Toggles generation of a `SmokeAPI.log.log` file.
|
`logging`:: Toggles generation of a `SmokeAPI.log.log` file.
|
||||||
+
|
+
|
||||||
@@ -121,6 +138,12 @@ The configuration file is expected to conform to the JSON standard.
|
|||||||
Type::: Boolean
|
Type::: Boolean
|
||||||
Default::: `false`
|
Default::: `false`
|
||||||
|
|
||||||
|
`log_steam_http`:: Toggles logging of _SteamHTTP_ traffic.
|
||||||
|
+
|
||||||
|
[horizontal]
|
||||||
|
Type::: Boolean
|
||||||
|
Default::: `false`
|
||||||
|
|
||||||
`default_app_status`:: This option sets the default DLC unlocking behaviour.
|
`default_app_status`:: This option sets the default DLC unlocking behaviour.
|
||||||
+
|
+
|
||||||
[horizontal]
|
[horizontal]
|
||||||
@@ -184,8 +207,9 @@ Default::: `{}`
|
|||||||
[source,json]
|
[source,json]
|
||||||
----
|
----
|
||||||
{
|
{
|
||||||
"$version": 3,
|
"$version": 4,
|
||||||
"logging": true,
|
"logging": true,
|
||||||
|
"log_steam_http": true,
|
||||||
"default_app_status": "unlocked",
|
"default_app_status": "unlocked",
|
||||||
"override_app_status": {
|
"override_app_status": {
|
||||||
"1234": "original",
|
"1234": "original",
|
||||||
@@ -223,7 +247,7 @@ Some games that have a large number of DLCs begin ownership verification by quer
|
|||||||
Once the game receives the list, it will go over each item and check the ownership.
|
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.
|
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.
|
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.
|
||||||
Unfortunately, even the web API does not solve all of our problems, because it will only return DLCs that are available in Steam store.
|
Unfortunately, even the web API does not solve all of our problems, because it will return only DLCs that are available in Steam store.
|
||||||
This means that DLCs without a dedicated store offer, such as pre-order DLCs will be left out.
|
This means that DLCs without a dedicated store offer, such as pre-order DLCs will be left out.
|
||||||
That's where the `extra_dlcs` config option comes into play.
|
That's where the `extra_dlcs` config option comes into play.
|
||||||
You can specify those missing DLC IDs there, and SmokeAPI will make them available to the game.
|
You can specify those missing DLC IDs there, and SmokeAPI will make them available to the game.
|
||||||
|
|||||||
12
res/README.txt
Normal file
12
res/README.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Project page: https://github.com/acidicoala/SmokeAPI#readme
|
||||||
|
Forum topic: https://cs.rin.ru/forum/viewtopic.php?p=2597932#p2597932
|
||||||
|
DLC Database: https://steamdb.info/
|
||||||
|
|
||||||
|
### NOTE ###
|
||||||
|
|
||||||
|
Do NOT use the SmokeAPI.config.json file unless you have a good reason.
|
||||||
|
The default config file enables logging, which might have a negative impact on performance in games.
|
||||||
|
So, unless you really need to see logs for debugging issues, it is advised to either:
|
||||||
|
disable logging in the config file by setting the "logging" field to false
|
||||||
|
or
|
||||||
|
not use the SmokeAPI.config.json file at all
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.0.0/res/SmokeAPI.schema.json",
|
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.0/res/SmokeAPI.schema.json",
|
||||||
"$version": 3,
|
"$version": 4,
|
||||||
"logging": true,
|
"logging": true,
|
||||||
|
"log_steam_http": true,
|
||||||
"default_app_status": "unlocked",
|
"default_app_status": "unlocked",
|
||||||
"override_app_status": {},
|
"override_app_status": {},
|
||||||
"override_dlc_status": {},
|
"override_dlc_status": {},
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
},
|
},
|
||||||
"$version": {
|
"$version": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 0,
|
"const": 4,
|
||||||
"default": 3,
|
|
||||||
"description": "A technical field reserved for tools like GUI config editors. Do not modify this value."
|
"description": "A technical field reserved for tools like GUI config editors. Do not modify this value."
|
||||||
},
|
},
|
||||||
"logging": {
|
"logging": {
|
||||||
@@ -20,6 +19,11 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Toggles generation of a SmokeAPI.log.log file."
|
"description": "Toggles generation of a SmokeAPI.log.log file."
|
||||||
},
|
},
|
||||||
|
"log_steam_http": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Toggles logging of SteamHTTP traffic"
|
||||||
|
},
|
||||||
"default_app_status": {
|
"default_app_status": {
|
||||||
"description": "Sets the default DLC unlocking behaviour.",
|
"description": "Sets the default DLC unlocking behaviour.",
|
||||||
"default": "unlocked",
|
"default": "unlocked",
|
||||||
@@ -111,9 +115,10 @@
|
|||||||
},
|
},
|
||||||
"examples": [
|
"examples": [
|
||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/heads/master/res/SmokeAPI.schema.json",
|
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.0/res/SmokeAPI.schema.json",
|
||||||
"$version": 3,
|
"$version": 4,
|
||||||
"logging": true,
|
"logging": true,
|
||||||
|
"log_steam_http": true,
|
||||||
"default_app_status": "unlocked",
|
"default_app_status": "unlocked",
|
||||||
"override_app_status": {
|
"override_app_status": {
|
||||||
"1234": "original",
|
"1234": "original",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "smoke_api.hpp"
|
#include "smoke_api/smoke_api.hpp"
|
||||||
|
|
||||||
// This header will be populated at build time
|
// This header will be populated at build time
|
||||||
#include "linker_exports_for_steam_api.h"
|
#include "linker_exports_for_steam_api.h"
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
#include <koalabox/config.hpp>
|
|
||||||
#include <koalabox/dll_monitor.hpp>
|
|
||||||
#include <koalabox/globals.hpp>
|
|
||||||
#include <koalabox/hook.hpp>
|
|
||||||
#include <koalabox/loader.hpp>
|
|
||||||
#include <koalabox/logger.hpp>
|
|
||||||
#include <koalabox/path.hpp>
|
|
||||||
#include <koalabox/paths.hpp>
|
|
||||||
#include <koalabox/str.hpp>
|
|
||||||
#include <koalabox/util.hpp>
|
|
||||||
#include <koalabox/win.hpp>
|
|
||||||
|
|
||||||
#include "build_config.h"
|
|
||||||
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "smoke_api/config.hpp"
|
|
||||||
#include "smoke_api/steamclient/steamclient.hpp"
|
|
||||||
#include "steam_api/exports/steam_api.hpp"
|
|
||||||
|
|
||||||
// Hooking steam_api has shown itself to be less desirable than steamclient
|
|
||||||
// for the reasons outlined below:
|
|
||||||
//
|
|
||||||
// Calling original in flat functions will actually call the hooked functions
|
|
||||||
// because the original function redirects the execution to a function taken
|
|
||||||
// from self pointer, which would have been hooked by SteamInternal_*Interface
|
|
||||||
// functions.
|
|
||||||
//
|
|
||||||
// Furthermore, turns out that many flat functions share the same body,
|
|
||||||
// which looks like the following snippet:
|
|
||||||
//
|
|
||||||
// mov rax, qword ptr ds:[rcx]
|
|
||||||
// jmp qword ptr ds:[rax+immediate]
|
|
||||||
//
|
|
||||||
// This means that we end up inadvertently hooking unintended functions.
|
|
||||||
// Given that hooking steam_api has no apparent benefits, but has inherent flaws,
|
|
||||||
// the support for it has been dropped from this project.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
namespace kb = koalabox;
|
|
||||||
|
|
||||||
void init_proxy_mode() {
|
|
||||||
LOG_INFO("Detected proxy mode");
|
|
||||||
|
|
||||||
const auto self_path = kb::paths::get_self_dir();
|
|
||||||
smoke_api::steamapi_module = kb::loader::load_original_library(self_path, STEAMAPI_DLL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_hook_mode() {
|
|
||||||
LOG_INFO("Detected hook mode");
|
|
||||||
|
|
||||||
kb::dll_monitor::init_listener(
|
|
||||||
{STEAMCLIENT_DLL, STEAMAPI_DLL},
|
|
||||||
[&](const HMODULE& module_handle, const std::string& library_name) {
|
|
||||||
if(kb::str::eq(library_name, STEAMCLIENT_DLL)) {
|
|
||||||
KB_HOOK_DETOUR_MODULE(CreateInterface, module_handle);
|
|
||||||
} else if(kb::str::eq(library_name, STEAMAPI_DLL)) {
|
|
||||||
KB_HOOK_DETOUR_MODULE(SteamAPI_RestartAppIfNecessary, module_handle);
|
|
||||||
KB_HOOK_DETOUR_MODULE(SteamAPI_Shutdown, module_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace smoke_api {
|
|
||||||
HMODULE steamapi_module = nullptr;
|
|
||||||
bool hook_mode = false;
|
|
||||||
|
|
||||||
void init(const HMODULE module_handle) {
|
|
||||||
try {
|
|
||||||
kb::globals::init_globals(module_handle, PROJECT_NAME);
|
|
||||||
|
|
||||||
config::instance = kb::config::parse<config::Config>();
|
|
||||||
|
|
||||||
if(config::instance.logging) {
|
|
||||||
kb::logger::init_file_logger(kb::paths::get_log_path());
|
|
||||||
}
|
|
||||||
|
|
||||||
// This kind of timestamp is reliable only for CI builds, as it will reflect the
|
|
||||||
// compilation time stamp only when this file gets recompiled.
|
|
||||||
LOG_INFO("{} v{} | Compiled at '{}'", PROJECT_NAME, PROJECT_VERSION, __TIMESTAMP__);
|
|
||||||
|
|
||||||
const auto exe_path = kb::win::get_module_path(nullptr);
|
|
||||||
const auto exe_name = kb::path::to_str(exe_path.filename());
|
|
||||||
|
|
||||||
LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::util::BITNESS);
|
|
||||||
|
|
||||||
// We need to hook functions in either mode
|
|
||||||
kb::hook::init(true);
|
|
||||||
|
|
||||||
if(kb::hook::is_hook_mode(module_handle, STEAMAPI_DLL)) {
|
|
||||||
hook_mode = true;
|
|
||||||
init_hook_mode();
|
|
||||||
} else {
|
|
||||||
init_proxy_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("Initialization complete");
|
|
||||||
} catch(const std::exception& ex) {
|
|
||||||
kb::util::panic(fmt::format("Initialization error: {}", ex.what()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shutdown() {
|
|
||||||
try {
|
|
||||||
if(steamapi_module != nullptr) {
|
|
||||||
kb::win::free_library(steamapi_module);
|
|
||||||
steamapi_module = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("Shutdown complete");
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
const auto msg = std::format("Shutdown error: {}", e.what());
|
|
||||||
LOG_ERROR(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
kb::logger::shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <koalabox/hook.hpp>
|
|
||||||
|
|
||||||
constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
|
|
||||||
constexpr auto STEAM_CLIENT = "SteamClient";
|
|
||||||
constexpr auto STEAM_USER = "SteamUser";
|
|
||||||
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
|
|
||||||
constexpr auto 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
|
|
||||||
|
|
||||||
// These macros are meant to be used for callbacks that should return original result
|
|
||||||
|
|
||||||
#define MODULE_CALL(FUNC, ...) \
|
|
||||||
static const auto _##FUNC = KB_HOOK_GET_MODULE_FN(smoke_api::steamapi_module, FUNC); \
|
|
||||||
return _##FUNC(__VA_ARGS__)
|
|
||||||
|
|
||||||
#define MODULE_CALL_CLOSURE(FUNC, ...) \
|
|
||||||
[&] { MODULE_CALL(FUNC, __VA_ARGS__); }
|
|
||||||
|
|
||||||
#define AUTO_CALL(FUNC, ...) \
|
|
||||||
static const auto _##FUNC = smoke_api::hook_mode \
|
|
||||||
? KB_HOOK_GET_HOOKED_FN(FUNC) \
|
|
||||||
: KB_HOOK_GET_MODULE_FN(smoke_api::steamapi_module, FUNC); \
|
|
||||||
return _##FUNC(__VA_ARGS__)
|
|
||||||
|
|
||||||
namespace smoke_api {
|
|
||||||
extern HMODULE steamapi_module;
|
|
||||||
|
|
||||||
extern bool hook_mode;
|
|
||||||
|
|
||||||
void init(HMODULE module_handle);
|
|
||||||
|
|
||||||
void shutdown();
|
|
||||||
}
|
|
||||||
168
src/smoke_api/smoke_api.cpp
Normal file
168
src/smoke_api/smoke_api.cpp
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
#include <regex>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <koalabox/config.hpp>
|
||||||
|
#include <koalabox/dll_monitor.hpp>
|
||||||
|
#include <koalabox/globals.hpp>
|
||||||
|
#include <koalabox/hook.hpp>
|
||||||
|
#include <koalabox/loader.hpp>
|
||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
#include <koalabox/path.hpp>
|
||||||
|
#include <koalabox/paths.hpp>
|
||||||
|
#include <koalabox/util.hpp>
|
||||||
|
#include <koalabox/win.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api.hpp"
|
||||||
|
|
||||||
|
#include "smoke_api/config.hpp"
|
||||||
|
#include "smoke_api/steamclient/steamclient.hpp"
|
||||||
|
#include "steam_api/steam_interfaces.hpp"
|
||||||
|
|
||||||
|
#include "build_config.h"
|
||||||
|
|
||||||
|
// Hooking steam_api has shown itself to be less desirable than steamclient
|
||||||
|
// for the reasons outlined below:
|
||||||
|
//
|
||||||
|
// Calling original in flat functions will actually call the hooked functions
|
||||||
|
// because the original function redirects the execution to a function taken
|
||||||
|
// from self pointer, which would have been hooked by SteamInternal_*Interface
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// Furthermore, turns out that many flat functions share the same body,
|
||||||
|
// which looks like the following snippet:
|
||||||
|
//
|
||||||
|
// mov rax, qword ptr ds:[rcx]
|
||||||
|
// jmp qword ptr ds:[rax+immediate]
|
||||||
|
//
|
||||||
|
// This means that we end up inadvertently hooking unintended functions.
|
||||||
|
// Given that hooking steam_api has no apparent benefits, but has inherent flaws,
|
||||||
|
// the support for it has been dropped from this project.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
namespace kb = koalabox;
|
||||||
|
|
||||||
|
HMODULE original_steamapi_handle = nullptr;
|
||||||
|
|
||||||
|
std::set<std::string> find_steamclient_versions(const HMODULE steamapi_handle) {
|
||||||
|
std::set<std::string> versions;
|
||||||
|
|
||||||
|
const auto rdata = kb::win::get_pe_section_or_throw(steamapi_handle, ".rdata").to_string();
|
||||||
|
|
||||||
|
const std::regex pattern(R"(SteamClient\d{3})");
|
||||||
|
auto matches_begin = std::sregex_iterator(rdata.begin(), rdata.end(), pattern);
|
||||||
|
auto matches_end = std::sregex_iterator();
|
||||||
|
|
||||||
|
for(std::sregex_iterator i = matches_begin; i != matches_end; ++i) {
|
||||||
|
versions.insert(i->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once CppDFAConstantFunctionResult
|
||||||
|
bool on_steamclient_loaded(const HMODULE steamclient_handle) noexcept {
|
||||||
|
auto* const steamapi_handle = original_steamapi_handle
|
||||||
|
? original_steamapi_handle
|
||||||
|
: GetModuleHandle(TEXT(STEAMAPI_DLL));
|
||||||
|
if(!steamapi_handle) {
|
||||||
|
LOG_ERROR("{} -> {} is not loaded", __func__, STEAMAPI_DLL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const auto CreateInterface$ = KB_WIN_GET_PROC(steamclient_handle, CreateInterface);
|
||||||
|
|
||||||
|
const auto steamclient_versions = find_steamclient_versions(steamapi_handle);
|
||||||
|
for(const auto& steamclient_version : steamclient_versions) {
|
||||||
|
if(CreateInterface$(steamclient_version.c_str(), nullptr)) {
|
||||||
|
LOG_WARN("'{}' was already initialized. SmokeAPI might not work as expected.", steamclient_version);
|
||||||
|
LOG_WARN("Probable cause: SmokeAPI was injected too late. If possible, try injecting it earlier.");
|
||||||
|
|
||||||
|
steam_interfaces::hook_steamclient_interface(steamclient_handle, steamclient_version);
|
||||||
|
} else {
|
||||||
|
LOG_INFO("'{}' is not initialized. Waiting for initialization.", steamclient_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KB_HOOK_DETOUR_MODULE(CreateInterface, steamclient_handle);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_dll_listener() {
|
||||||
|
kb::dll_monitor::init_listener({{STEAMCLIENT_DLL, on_steamclient_loaded}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace smoke_api {
|
||||||
|
void init(const HMODULE module_handle) {
|
||||||
|
try {
|
||||||
|
kb::globals::init_globals(module_handle, PROJECT_NAME);
|
||||||
|
|
||||||
|
config::instance = kb::config::parse<config::Config>();
|
||||||
|
|
||||||
|
if(config::instance.logging) {
|
||||||
|
kb::logger::init_file_logger(kb::paths::get_log_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("{} v{} | Built at '{}'", PROJECT_NAME, PROJECT_VERSION, __TIMESTAMP__);
|
||||||
|
LOG_DEBUG("Parsed config:\n{}", nlohmann::ordered_json(config::instance).dump(2));
|
||||||
|
|
||||||
|
const auto exe_path = kb::win::get_module_path(nullptr);
|
||||||
|
const auto exe_name = kb::path::to_str(exe_path.filename());
|
||||||
|
|
||||||
|
LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::util::BITNESS);
|
||||||
|
|
||||||
|
// We need to hook functions in either mode
|
||||||
|
kb::hook::init(true);
|
||||||
|
|
||||||
|
if(kb::hook::is_hook_mode(module_handle, STEAMAPI_DLL)) {
|
||||||
|
LOG_INFO("Detected hook mode");
|
||||||
|
|
||||||
|
start_dll_listener();
|
||||||
|
} else {
|
||||||
|
LOG_INFO("Detected proxy mode");
|
||||||
|
|
||||||
|
const auto self_path = kb::paths::get_self_dir();
|
||||||
|
original_steamapi_handle = kb::loader::load_original_library(
|
||||||
|
self_path,
|
||||||
|
STEAMAPI_DLL
|
||||||
|
);
|
||||||
|
|
||||||
|
start_dll_listener();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Initialization complete");
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
kb::util::panic(fmt::format("Initialization error: {}", e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdown() {
|
||||||
|
try {
|
||||||
|
if(original_steamapi_handle != nullptr) {
|
||||||
|
kb::win::free_library(original_steamapi_handle);
|
||||||
|
original_steamapi_handle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Unhook everything
|
||||||
|
|
||||||
|
LOG_INFO("Shutdown complete");
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
const auto msg = std::format("Shutdown error: {}", e.what());
|
||||||
|
LOG_ERROR(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
kb::logger::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
AppId_t get_app_id() {
|
||||||
|
try {
|
||||||
|
const auto app_id_str = kb::win::get_env_var("SteamAppId");
|
||||||
|
static auto app_id = std::stoi(app_id_str);
|
||||||
|
return app_id;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("Failed to get app id: {}", e.what());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/smoke_api/smoke_api.hpp
Normal file
22
src/smoke_api/smoke_api.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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_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(HMODULE module_handle);
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
AppId_t get_app_id();
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#include <koalabox/logger.hpp>
|
|
||||||
|
|
||||||
#include "steam_api/exports/steam_api.hpp"
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "smoke_api/config.hpp"
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(const AppId_t unOwnAppID) {
|
|
||||||
LOG_INFO("{} -> unOwnAppID: {}", __func__, unOwnAppID);
|
|
||||||
|
|
||||||
// Restart can be suppressed if needed
|
|
||||||
|
|
||||||
AUTO_CALL(SteamAPI_RestartAppIfNecessary, unOwnAppID);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(void) SteamAPI_Shutdown() {
|
|
||||||
LOG_INFO("{} -> Game requested shutdown", __func__);
|
|
||||||
|
|
||||||
AUTO_CALL(SteamAPI_Shutdown);
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "smoke_api/types.hpp"
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(AppId_t unOwnAppID);
|
|
||||||
|
|
||||||
DLL_EXPORT(void) SteamAPI_Shutdown();
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
#include <koalabox/logger.hpp>
|
|
||||||
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "smoke_api/interfaces/steam_apps.hpp"
|
|
||||||
#include "smoke_api/interfaces/steam_inventory.hpp"
|
|
||||||
#include "smoke_api/interfaces/steam_user.hpp"
|
|
||||||
#include "steam_api/steam_client.hpp"
|
|
||||||
#include "steam_api/steam_interface.hpp"
|
|
||||||
|
|
||||||
// ISteamApps
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void* self, const AppId_t dlcID) {
|
|
||||||
try {
|
|
||||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
|
||||||
__func__,
|
|
||||||
steam_interface::get_app_id(),
|
|
||||||
dlcID,
|
|
||||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_BIsSubscribedApp, self, dlcID)
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(void* self, const AppId_t dlcID) {
|
|
||||||
try {
|
|
||||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
|
||||||
__func__,
|
|
||||||
steam_interface::get_app_id(),
|
|
||||||
dlcID,
|
|
||||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_BIsDlcInstalled, self, dlcID)
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(void* self) {
|
|
||||||
try {
|
|
||||||
return smoke_api::steam_apps::GetDLCCount(
|
|
||||||
__func__,
|
|
||||||
steam_interface::get_app_id(),
|
|
||||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_GetDLCCount, self)
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
|
|
||||||
void* self,
|
|
||||||
const int iDLC,
|
|
||||||
AppId_t* pDlcID,
|
|
||||||
bool* pbAvailable,
|
|
||||||
char* pchName,
|
|
||||||
const int cchNameBufferSize
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return smoke_api::steam_apps::GetDLCDataByIndex(
|
|
||||||
__func__,
|
|
||||||
steam_interface::get_app_id(),
|
|
||||||
iDLC,
|
|
||||||
pDlcID,
|
|
||||||
pbAvailable,
|
|
||||||
pchName,
|
|
||||||
cchNameBufferSize,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamApps_BGetDLCDataByIndex,
|
|
||||||
self,
|
|
||||||
iDLC,
|
|
||||||
pDlcID,
|
|
||||||
pbAvailable,
|
|
||||||
pchName,
|
|
||||||
cchNameBufferSize
|
|
||||||
),
|
|
||||||
[&](const AppId_t dlc_id) {
|
|
||||||
return SteamAPI_ISteamApps_BIsDlcInstalled(self, dlc_id);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISteamClient
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(
|
|
||||||
void* self,
|
|
||||||
const HSteamUser hSteamUser,
|
|
||||||
const HSteamPipe hSteamPipe,
|
|
||||||
const char* pchVersion
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
pchVersion,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamClient_GetISteamGenericInterface,
|
|
||||||
self,
|
|
||||||
hSteamUser,
|
|
||||||
hSteamPipe,
|
|
||||||
pchVersion
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISteamInventory
|
|
||||||
|
|
||||||
DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(
|
|
||||||
void* self,
|
|
||||||
const SteamInventoryResult_t resultHandle
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::GetResultStatus(
|
|
||||||
__func__,
|
|
||||||
resultHandle,
|
|
||||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamInventory_GetResultStatus, self, resultHandle)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
|
|
||||||
void* self,
|
|
||||||
SteamItemDef_t* pItemDefIDs,
|
|
||||||
uint32_t* punItemDefIDsArraySize
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::GetItemDefinitionIDs(
|
|
||||||
__func__,
|
|
||||||
pItemDefIDs,
|
|
||||||
punItemDefIDsArraySize,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamInventory_GetItemDefinitionIDs,
|
|
||||||
self,
|
|
||||||
pItemDefIDs,
|
|
||||||
punItemDefIDsArraySize
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
|
|
||||||
void* self,
|
|
||||||
const SteamInventoryResult_t resultHandle,
|
|
||||||
SteamItemDetails_t* pOutItemsArray,
|
|
||||||
uint32_t* punOutItemsArraySize
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::GetResultItems(
|
|
||||||
__func__,
|
|
||||||
resultHandle,
|
|
||||||
pOutItemsArray,
|
|
||||||
punOutItemsArraySize,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamInventory_GetResultItems,
|
|
||||||
self,
|
|
||||||
resultHandle,
|
|
||||||
pOutItemsArray,
|
|
||||||
punOutItemsArraySize
|
|
||||||
),
|
|
||||||
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
|
|
||||||
MODULE_CALL(
|
|
||||||
SteamAPI_ISteamInventory_GetItemDefinitionIDs,
|
|
||||||
self,
|
|
||||||
pItemDefIDs,
|
|
||||||
punItemDefIDsArraySize
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
|
|
||||||
void* self,
|
|
||||||
const SteamInventoryResult_t resultHandle,
|
|
||||||
const uint32_t unItemIndex,
|
|
||||||
const char* pchPropertyName,
|
|
||||||
char* pchValueBuffer,
|
|
||||||
uint32_t* punValueBufferSizeOut
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::GetResultItemProperty(
|
|
||||||
__func__,
|
|
||||||
resultHandle,
|
|
||||||
unItemIndex,
|
|
||||||
pchPropertyName,
|
|
||||||
pchValueBuffer,
|
|
||||||
punValueBufferSizeOut,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamInventory_GetResultItemProperty,
|
|
||||||
self,
|
|
||||||
resultHandle,
|
|
||||||
unItemIndex,
|
|
||||||
pchPropertyName,
|
|
||||||
pchValueBuffer,
|
|
||||||
punValueBufferSizeOut
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
|
|
||||||
void* self,
|
|
||||||
const SteamInventoryResult_t resultHandle,
|
|
||||||
const CSteamID steamIDExpected
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::CheckResultSteamID(
|
|
||||||
__func__,
|
|
||||||
resultHandle,
|
|
||||||
steamIDExpected,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamInventory_CheckResultSteamID,
|
|
||||||
self,
|
|
||||||
resultHandle,
|
|
||||||
steamIDExpected
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(
|
|
||||||
void* self,
|
|
||||||
SteamInventoryResult_t* pResultHandle
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::GetAllItems(
|
|
||||||
__func__,
|
|
||||||
pResultHandle,
|
|
||||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamInventory_GetAllItems, self, pResultHandle)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
|
|
||||||
void* self,
|
|
||||||
SteamInventoryResult_t* pResultHandle,
|
|
||||||
const SteamItemInstanceID_t* pInstanceIDs,
|
|
||||||
const uint32_t unCountInstanceIDs
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::GetItemsByID(
|
|
||||||
__func__,
|
|
||||||
pResultHandle,
|
|
||||||
pInstanceIDs,
|
|
||||||
unCountInstanceIDs,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamInventory_GetItemsByID,
|
|
||||||
self,
|
|
||||||
pResultHandle,
|
|
||||||
pInstanceIDs,
|
|
||||||
unCountInstanceIDs
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
|
|
||||||
void* self,
|
|
||||||
const SteamInventoryResult_t resultHandle,
|
|
||||||
void* pOutBuffer,
|
|
||||||
uint32_t* punOutBufferSize
|
|
||||||
) {
|
|
||||||
return smoke_api::steam_inventory::SerializeResult(
|
|
||||||
__func__,
|
|
||||||
resultHandle,
|
|
||||||
pOutBuffer,
|
|
||||||
punOutBufferSize,
|
|
||||||
MODULE_CALL_CLOSURE(
|
|
||||||
SteamAPI_ISteamInventory_SerializeResult,
|
|
||||||
self,
|
|
||||||
resultHandle,
|
|
||||||
pOutBuffer,
|
|
||||||
punOutBufferSize
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISteamUser
|
|
||||||
|
|
||||||
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_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_ISteamUser_UserHasLicenseForApp,
|
|
||||||
self,
|
|
||||||
steamID,
|
|
||||||
dlcID
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#include "smoke_api.hpp"
|
|
||||||
#include "smoke_api/types.hpp"
|
|
||||||
#include "steam_api/steam_client.hpp"
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(
|
|
||||||
const HSteamUser hSteamUser,
|
|
||||||
const char* version
|
|
||||||
) {
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
version,
|
|
||||||
MODULE_CALL_CLOSURE(SteamInternal_FindOrCreateUserInterface, hSteamUser, version)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char* version) {
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
version,
|
|
||||||
MODULE_CALL_CLOSURE(SteamInternal_CreateInterface, version)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
#include <regex>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <koalabox/logger.hpp>
|
|
||||||
#include <koalabox/win.hpp>
|
|
||||||
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "steam_api/steam_client.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
namespace kb = koalabox;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches the `.rdata` section of the original dll for the full interface version string
|
|
||||||
* Results are cached for performance.
|
|
||||||
*/
|
|
||||||
std::string get_versioned_interface(
|
|
||||||
const std::string& version_prefix,
|
|
||||||
const std::string& fallback
|
|
||||||
) {
|
|
||||||
static std::map<std::string, std::string> version_map;
|
|
||||||
|
|
||||||
if(not version_map.contains(version_prefix)) {
|
|
||||||
try {
|
|
||||||
const std::string rdata = kb::win::get_pe_section_data_or_throw(
|
|
||||||
smoke_api::steamapi_module,
|
|
||||||
".rdata"
|
|
||||||
);
|
|
||||||
|
|
||||||
const std::regex regex(version_prefix + "\\d{3}");
|
|
||||||
if(std::smatch match; std::regex_search(rdata, match, regex)) {
|
|
||||||
version_map[version_prefix] = match[0];
|
|
||||||
return version_map[version_prefix];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::runtime_error(std::format("No match found for '{}'", version_prefix));
|
|
||||||
} catch(const std::exception& ex) {
|
|
||||||
LOG_ERROR(
|
|
||||||
"Failed to get versioned interface: {}."
|
|
||||||
"Falling back to version {}",
|
|
||||||
ex.what(),
|
|
||||||
fallback
|
|
||||||
);
|
|
||||||
|
|
||||||
version_map[version_prefix] = version_prefix + fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return version_map[version_prefix];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamClient() {
|
|
||||||
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
|
|
||||||
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
version,
|
|
||||||
MODULE_CALL_CLOSURE(SteamClient)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamApps() {
|
|
||||||
static auto version = get_versioned_interface(STEAM_APPS, "002");
|
|
||||||
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
version,
|
|
||||||
MODULE_CALL_CLOSURE(SteamApps)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamUser() {
|
|
||||||
static auto version = get_versioned_interface(STEAM_USER, "012");
|
|
||||||
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
version,
|
|
||||||
MODULE_CALL_CLOSURE(SteamUser)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamInventory() {
|
|
||||||
static auto version = get_versioned_interface(STEAM_INVENTORY, "001");
|
|
||||||
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
version,
|
|
||||||
MODULE_CALL_CLOSURE(SteamInventory)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,25 @@
|
|||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
#include "steam_api/steam_interface.hpp"
|
#include "steam_client.hpp"
|
||||||
|
#include "steam_api/steam_interfaces.hpp"
|
||||||
|
|
||||||
namespace steam_client {
|
namespace steam_client {
|
||||||
void* GetGenericInterface(
|
void* GetGenericInterface(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const std::string& interface_version,
|
const std::string& interface_version,
|
||||||
const std::function<void*()>& original_function
|
const std::function<void*()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
auto* const interface = original_function();
|
try {
|
||||||
|
auto* const interface = original_function();
|
||||||
|
|
||||||
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
|
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
|
||||||
|
|
||||||
steam_interface::hook_virtuals(interface, interface_version);
|
steam_interfaces::hook_virtuals(interface, interface_version);
|
||||||
|
|
||||||
return interface;
|
return interface;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: '{}' @ {}", function_name, interface_version, e.what());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ namespace steam_client {
|
|||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const std::string& interface_version,
|
const std::string& interface_version,
|
||||||
const std::function<void*()>& original_function
|
const std::function<void*()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
#include <ranges>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <battery/embed.hpp>
|
|
||||||
|
|
||||||
#include <koalabox/hook.hpp>
|
|
||||||
#include <koalabox/logger.hpp>
|
|
||||||
#include <koalabox/win.hpp>
|
|
||||||
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "virtuals/steam_api_virtuals.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct interface_entry {
|
|
||||||
// function_name must match the function identifier to be able to call original functions
|
|
||||||
std::string function_name; // e.g. "ISteamClient_GetISteamApps"
|
|
||||||
uintptr_t function_address; // e.g. ISteamClient_GetISteamApps
|
|
||||||
};
|
|
||||||
|
|
||||||
struct interface_data {
|
|
||||||
std::string fallback_version; // e.g. "SteamClient021"
|
|
||||||
std::map<std::string, interface_entry> entry_map;
|
|
||||||
// e.g. {ENTRY(ISteamClient, GetISteamApps), ...}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<std::string, interface_data> get_virtual_hook_map() {
|
|
||||||
#define ENTRY(INTERFACE, FUNC) \
|
|
||||||
{ \
|
|
||||||
#FUNC, { \
|
|
||||||
#INTERFACE "_" #FUNC, reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
STEAM_CLIENT,
|
|
||||||
interface_data{
|
|
||||||
.fallback_version = "SteamClient021",
|
|
||||||
.entry_map = {
|
|
||||||
ENTRY(ISteamClient, GetISteamApps),
|
|
||||||
ENTRY(ISteamClient, GetISteamUser),
|
|
||||||
ENTRY(ISteamClient, GetISteamGenericInterface),
|
|
||||||
ENTRY(ISteamClient, GetISteamInventory),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
STEAM_APPS,
|
|
||||||
interface_data{
|
|
||||||
.fallback_version = "STEAMAPPS_INTERFACE_VERSION008",
|
|
||||||
.entry_map = {
|
|
||||||
ENTRY(ISteamApps, BIsSubscribedApp),
|
|
||||||
ENTRY(ISteamApps, BIsDlcInstalled),
|
|
||||||
ENTRY(ISteamApps, GetDLCCount),
|
|
||||||
ENTRY(ISteamApps, BGetDLCDataByIndex),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
STEAM_USER,
|
|
||||||
interface_data{
|
|
||||||
.fallback_version = "SteamUser023",
|
|
||||||
.entry_map = {
|
|
||||||
ENTRY(ISteamUser, UserHasLicenseForApp),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
STEAM_GAME_SERVER,
|
|
||||||
interface_data{
|
|
||||||
.fallback_version = "SteamGameServer015",
|
|
||||||
.entry_map = {
|
|
||||||
ENTRY(ISteamGameServer, UserHasLicenseForApp),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json read_interface_lookup() {
|
|
||||||
const auto lookup_str = b::embed<"res/interface_lookup.json">().str();
|
|
||||||
return nlohmann::json::parse(lookup_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nlohmann::json& find_lookup(
|
|
||||||
const std::string& interface_version,
|
|
||||||
const std::string& fallback_version
|
|
||||||
) {
|
|
||||||
static const auto lookup = read_interface_lookup();
|
|
||||||
|
|
||||||
if(lookup.contains(interface_version)) {
|
|
||||||
return lookup[interface_version];
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_WARN(
|
|
||||||
"Interface version '{}' not found in lookup map. Using fallback: '{}'",
|
|
||||||
interface_version,
|
|
||||||
fallback_version
|
|
||||||
);
|
|
||||||
|
|
||||||
return lookup[fallback_version];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace steam_interface {
|
|
||||||
namespace kb = koalabox;
|
|
||||||
|
|
||||||
AppId_t get_app_id_or_throw() {
|
|
||||||
const auto app_id_str = kb::win::get_env_var("SteamAppId");
|
|
||||||
return std::stoi(app_id_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppId_t get_app_id() {
|
|
||||||
try {
|
|
||||||
static const auto app_id = get_app_id_or_throw();
|
|
||||||
return app_id;
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("Failed to get app id: {}", e.what());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hook_virtuals(void* interface, const std::string& version_string) {
|
|
||||||
if(interface == nullptr) {
|
|
||||||
// Game has tried to use an interface before initializing steam api
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::set<void*> processed_interfaces;
|
|
||||||
|
|
||||||
if(processed_interfaces.contains(interface)) {
|
|
||||||
LOG_DEBUG("Interface {} at {} has already been processed.", version_string, interface);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::mutex section;
|
|
||||||
const std::lock_guard guard(section);
|
|
||||||
|
|
||||||
static const auto virtual_hook_map = get_virtual_hook_map();
|
|
||||||
for(const auto& [prefix, data] : virtual_hook_map) {
|
|
||||||
if(version_string.starts_with(prefix)) {
|
|
||||||
const auto& lookup = find_lookup(version_string, data.fallback_version);
|
|
||||||
|
|
||||||
for(const auto& [function, entry] : data.entry_map) {
|
|
||||||
if(lookup.contains(function)) {
|
|
||||||
kb::hook::swap_virtual_func(
|
|
||||||
interface,
|
|
||||||
entry.function_name,
|
|
||||||
lookup[function],
|
|
||||||
entry.function_address
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processed_interfaces.insert(interface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "smoke_api/types.hpp"
|
|
||||||
|
|
||||||
namespace steam_interface {
|
|
||||||
AppId_t get_app_id_or_throw();
|
|
||||||
AppId_t get_app_id();
|
|
||||||
|
|
||||||
void hook_virtuals(void* interface, const std::string& version_string);
|
|
||||||
}
|
|
||||||
252
src/steam_api/steam_interfaces.cpp
Normal file
252
src/steam_api/steam_interfaces.cpp
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
#include <ranges>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <battery/embed.hpp>
|
||||||
|
|
||||||
|
#include <koalabox/hook.hpp>
|
||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
#include <koalabox/win.hpp>
|
||||||
|
|
||||||
|
#include "steam_api/steam_interfaces.hpp"
|
||||||
|
#include "smoke_api/smoke_api.hpp"
|
||||||
|
#include "smoke_api/steamclient/steamclient.hpp"
|
||||||
|
#include "virtuals/steam_api_virtuals.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct interface_entry {
|
||||||
|
// function_name must match the function identifier to be able to call original functions
|
||||||
|
std::string function_name; // e.g. "ISteamClient_GetISteamApps"
|
||||||
|
void* function_address; // e.g. ISteamClient_GetISteamApps
|
||||||
|
};
|
||||||
|
|
||||||
|
struct interface_data_t { // NOLINT(*-exception-escape)
|
||||||
|
std::string fallback_version; // e.g. "SteamClient021"
|
||||||
|
// Key is function name without interface prefix
|
||||||
|
std::map<std::string, interface_entry> entry_map;
|
||||||
|
// e.g. {ENTRY(ISteamClient, GetISteamApps), ...}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Key is interface name, e.g. "SteamClient"
|
||||||
|
std::map<std::string, interface_data_t> get_virtual_hook_map() {
|
||||||
|
#define ENTRY(INTERFACE, FUNC) \
|
||||||
|
{ \
|
||||||
|
#FUNC, { \
|
||||||
|
#INTERFACE "_" #FUNC, reinterpret_cast<void*>(INTERFACE##_##FUNC) \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
{
|
||||||
|
STEAM_APPS,
|
||||||
|
interface_data_t{
|
||||||
|
.fallback_version = "STEAMAPPS_INTERFACE_VERSION008",
|
||||||
|
.entry_map = {
|
||||||
|
ENTRY(ISteamApps, BIsSubscribedApp),
|
||||||
|
ENTRY(ISteamApps, BIsDlcInstalled),
|
||||||
|
ENTRY(ISteamApps, GetDLCCount),
|
||||||
|
ENTRY(ISteamApps, BGetDLCDataByIndex),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
STEAM_CLIENT,
|
||||||
|
interface_data_t{
|
||||||
|
.fallback_version = "SteamClient021",
|
||||||
|
.entry_map = {
|
||||||
|
ENTRY(ISteamClient, GetISteamApps),
|
||||||
|
ENTRY(ISteamClient, GetISteamUser),
|
||||||
|
ENTRY(ISteamClient, GetISteamGenericInterface),
|
||||||
|
ENTRY(ISteamClient, GetISteamInventory),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
STEAM_GAME_SERVER,
|
||||||
|
interface_data_t{
|
||||||
|
.fallback_version = "SteamGameServer015",
|
||||||
|
.entry_map = {
|
||||||
|
ENTRY(ISteamGameServer, UserHasLicenseForApp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
STEAM_HTTP,
|
||||||
|
interface_data_t{
|
||||||
|
.fallback_version = "STEAMHTTP_INTERFACE_VERSION003",
|
||||||
|
.entry_map = {
|
||||||
|
ENTRY(ISteamHTTP, GetHTTPResponseBodyData),
|
||||||
|
ENTRY(ISteamHTTP, GetHTTPStreamingResponseBodyData),
|
||||||
|
ENTRY(ISteamHTTP, SetHTTPRequestRawPostBody),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
STEAM_INVENTORY,
|
||||||
|
interface_data_t{
|
||||||
|
.fallback_version = "STEAMINVENTORY_INTERFACE_V003",
|
||||||
|
.entry_map = {
|
||||||
|
ENTRY(ISteamInventory, GetResultStatus),
|
||||||
|
ENTRY(ISteamInventory, GetResultItems),
|
||||||
|
ENTRY(ISteamInventory, CheckResultSteamID),
|
||||||
|
ENTRY(ISteamInventory, GetAllItems),
|
||||||
|
ENTRY(ISteamInventory, GetItemsByID),
|
||||||
|
ENTRY(ISteamInventory, SerializeResult),
|
||||||
|
ENTRY(ISteamInventory, GetItemDefinitionIDs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
STEAM_USER,
|
||||||
|
interface_data_t{
|
||||||
|
.fallback_version = "SteamUser023",
|
||||||
|
.entry_map = {
|
||||||
|
ENTRY(ISteamUser, UserHasLicenseForApp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key is function name, Value is ordinal
|
||||||
|
using ordinal_map_t = std::map<std::string, uint16_t>;
|
||||||
|
|
||||||
|
// Key is interface version string
|
||||||
|
using lookup_map_t = std::map<std::string, ordinal_map_t>;
|
||||||
|
|
||||||
|
lookup_map_t read_interface_lookup() {
|
||||||
|
lookup_map_t lookup_map;
|
||||||
|
|
||||||
|
const auto lookup_str = b::embed<"res/interface_lookup.json">().str();
|
||||||
|
const auto lookup_json = nlohmann::json::parse(lookup_str);
|
||||||
|
lookup_json.get_to(lookup_map);
|
||||||
|
|
||||||
|
return lookup_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, uint16_t>& find_lookup(
|
||||||
|
const std::string& interface_version,
|
||||||
|
const std::string& fallback_version
|
||||||
|
) {
|
||||||
|
static const auto lookup = read_interface_lookup();
|
||||||
|
|
||||||
|
if(lookup.contains(interface_version)) {
|
||||||
|
return lookup.at(interface_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARN(
|
||||||
|
"Interface version '{}' not found in lookup map. Using fallback: '{}'",
|
||||||
|
interface_version,
|
||||||
|
fallback_version
|
||||||
|
);
|
||||||
|
|
||||||
|
return lookup.at(fallback_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace steam_interfaces {
|
||||||
|
namespace kb = koalabox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param interface_ptr Pointer to the interface
|
||||||
|
* @param version_string Example: 'SteamClient007'
|
||||||
|
*/
|
||||||
|
void hook_virtuals(const void* interface_ptr, const std::string& version_string) {
|
||||||
|
if(interface_ptr == nullptr) {
|
||||||
|
// Game has tried to use an interface before initializing steam api
|
||||||
|
// This does happen in practice.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::mutex section;
|
||||||
|
const std::lock_guard guard(section);
|
||||||
|
|
||||||
|
static std::set<const void*> processed_interfaces;
|
||||||
|
|
||||||
|
if(processed_interfaces.contains(interface_ptr)) {
|
||||||
|
LOG_DEBUG("Interface '{}' @ {} has already been processed.", version_string, interface_ptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processed_interfaces.insert(interface_ptr);
|
||||||
|
|
||||||
|
static const auto virtual_hook_map = get_virtual_hook_map();
|
||||||
|
for(const auto& [prefix, data] : virtual_hook_map) {
|
||||||
|
if(not version_string.starts_with(prefix)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Processing '{}' @ {} found in virtual hook map", version_string, interface_ptr);
|
||||||
|
|
||||||
|
const auto& lookup = find_lookup(version_string, data.fallback_version);
|
||||||
|
|
||||||
|
for(const auto& [function, entry] : data.entry_map) {
|
||||||
|
if(not lookup.contains(function)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kb::hook::swap_virtual_func(
|
||||||
|
interface_ptr,
|
||||||
|
entry.function_name,
|
||||||
|
lookup.at(function),
|
||||||
|
entry.function_address
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hook_steamclient_interface(
|
||||||
|
const HMODULE steamclient_handle,
|
||||||
|
const std::string& steam_client_interface_version
|
||||||
|
) noexcept {
|
||||||
|
try {
|
||||||
|
// Create a copy for modification
|
||||||
|
auto virtual_hook_map = get_virtual_hook_map();
|
||||||
|
|
||||||
|
// Remove steam client map since we don't want to hook its methods
|
||||||
|
virtual_hook_map.erase(STEAM_CLIENT);
|
||||||
|
|
||||||
|
// Map remaining virtual hook map to a set of keys
|
||||||
|
const auto prefixes = std::views::keys(virtual_hook_map) | std::ranges::to<std::set>();
|
||||||
|
|
||||||
|
// Prepare HSteamPipe and HSteamUser
|
||||||
|
const auto CreateInterface$ = KB_WIN_GET_PROC(steamclient_handle, CreateInterface);
|
||||||
|
const auto* const THIS = CreateInterface$(steam_client_interface_version.c_str(), nullptr);
|
||||||
|
hook_virtuals(THIS, steam_client_interface_version);
|
||||||
|
|
||||||
|
const auto interface_lookup = read_interface_lookup();
|
||||||
|
for(const auto& interface_version : interface_lookup | std::views::keys) {
|
||||||
|
// SteamUser and SteamPipe handles must match the ones previously used by the game,
|
||||||
|
// otherwise SteamAPI will just create new instances of interfaces, instead of returning
|
||||||
|
// existing instances that are used by the game. Usually these handles default to 1,
|
||||||
|
// but if a game creates several of them, then we need to somehow find them out dynamically.
|
||||||
|
constexpr auto steam_pipe = 1;
|
||||||
|
constexpr auto steam_user = 1;
|
||||||
|
|
||||||
|
const bool should_hook = std::ranges::any_of(
|
||||||
|
prefixes,
|
||||||
|
[&](const auto& prefix) {
|
||||||
|
return std::ranges::starts_with(interface_version, prefix);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if(not should_hook) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_EDX();
|
||||||
|
const auto* const interface_ptr = ISteamClient_GetISteamGenericInterface(
|
||||||
|
ARGS(steam_user, steam_pipe, interface_version.c_str())
|
||||||
|
);
|
||||||
|
|
||||||
|
if(not interface_ptr) {
|
||||||
|
LOG_ERROR("Failed to get generic interface: '{}'", interface_version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kb::hook::unhook_vt_all(THIS);
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Unhandled exception: {}", __func__, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/steam_api/steam_interfaces.hpp
Normal file
18
src/steam_api/steam_interfaces.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "smoke_api/types.hpp"
|
||||||
|
|
||||||
|
namespace steam_interfaces {
|
||||||
|
void hook_virtuals(const void* interface_ptr, const std::string& version_string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fallback mechanism used when SteamAPI has already been initialized.
|
||||||
|
* It will hook the SteamClient interface and hook its interface accessors.
|
||||||
|
* This allows us to hook interfaces that are no longer being created,
|
||||||
|
* such as in the case of late injection.
|
||||||
|
*/
|
||||||
|
void hook_steamclient_interface(
|
||||||
|
HMODULE steamclient_handle,
|
||||||
|
const std::string& steam_client_interface_version
|
||||||
|
) noexcept;
|
||||||
|
}
|
||||||
@@ -1,48 +1,33 @@
|
|||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api/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/virtuals/steam_api_virtuals.hpp"
|
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(const AppId_t dlc_id)) {
|
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(const AppId_t dlc_id)) noexcept {
|
||||||
try {
|
return smoke_api::steam_apps::IsDlcUnlocked(
|
||||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
__func__,
|
||||||
__func__,
|
smoke_api::get_app_id(),
|
||||||
steam_interface::get_app_id(),
|
dlc_id,
|
||||||
dlc_id,
|
SWAPPED_CALL_CLOSURE(ISteamApps_BIsSubscribedApp, ARGS(dlc_id))
|
||||||
HOOKED_CALL_CLOSURE(ISteamApps_BIsSubscribedApp, ARGS(dlc_id))
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(const AppId_t dlc_id)) {
|
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(const AppId_t dlc_id)) noexcept {
|
||||||
try {
|
return smoke_api::steam_apps::IsDlcUnlocked(
|
||||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
__func__,
|
||||||
__func__,
|
smoke_api::get_app_id(),
|
||||||
steam_interface::get_app_id(),
|
dlc_id,
|
||||||
dlc_id,
|
SWAPPED_CALL_CLOSURE(ISteamApps_BIsDlcInstalled, ARGS(dlc_id))
|
||||||
HOOKED_CALL_CLOSURE(ISteamApps_BIsDlcInstalled, ARGS(dlc_id))
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) {
|
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) noexcept {
|
||||||
try {
|
return smoke_api::steam_apps::GetDLCCount(
|
||||||
return smoke_api::steam_apps::GetDLCCount(
|
__func__,
|
||||||
__func__,
|
smoke_api::get_app_id(),
|
||||||
steam_interface::get_app_id(),
|
SWAPPED_CALL_CLOSURE(ISteamApps_GetDLCCount, ARGS())
|
||||||
HOOKED_CALL_CLOSURE(ISteamApps_GetDLCCount, ARGS())
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
|
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
|
||||||
@@ -53,26 +38,22 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
|
|||||||
char* pchName,
|
char* pchName,
|
||||||
const int cchNameBufferSize
|
const int cchNameBufferSize
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return smoke_api::steam_apps::GetDLCDataByIndex(
|
||||||
return smoke_api::steam_apps::GetDLCDataByIndex(
|
__func__,
|
||||||
__func__,
|
smoke_api::get_app_id(),
|
||||||
steam_interface::get_app_id(),
|
iDLC,
|
||||||
iDLC,
|
p_dlc_id,
|
||||||
p_dlc_id,
|
pbAvailable,
|
||||||
pbAvailable,
|
pchName,
|
||||||
pchName,
|
cchNameBufferSize,
|
||||||
cchNameBufferSize,
|
SWAPPED_CALL_CLOSURE(
|
||||||
HOOKED_CALL_CLOSURE(
|
ISteamApps_BGetDLCDataByIndex,
|
||||||
ISteamApps_BGetDLCDataByIndex,
|
ARGS(iDLC, p_dlc_id, pbAvailable, pchName, cchNameBufferSize)
|
||||||
ARGS(iDLC, p_dlc_id, pbAvailable, pchName, cchNameBufferSize)
|
),
|
||||||
),
|
SWAPPED_CALL_CLOSURE(
|
||||||
[&](const AppId_t dlc_id) {
|
ISteamApps_BIsSubscribedApp,
|
||||||
return ISteamApps_BIsDlcInstalled(ARGS(dlc_id));
|
ARGS(*p_dlc_id)
|
||||||
}
|
)
|
||||||
);
|
);
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,60 +7,45 @@ VIRTUAL(void*) ISteamClient_GetISteamApps(
|
|||||||
PARAMS(
|
PARAMS(
|
||||||
const HSteamUser hSteamUser,
|
const HSteamUser hSteamUser,
|
||||||
const HSteamPipe hSteamPipe,
|
const HSteamPipe hSteamPipe,
|
||||||
const char* version
|
const char* pchVersion
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return steam_client::GetGenericInterface(
|
||||||
return steam_client::GetGenericInterface(
|
__func__,
|
||||||
__func__,
|
pchVersion,
|
||||||
version,
|
SWAPPED_CALL_CLOSURE(ISteamClient_GetISteamApps, ARGS(hSteamUser, hSteamPipe, pchVersion))
|
||||||
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamApps, ARGS(hSteamUser, hSteamPipe, version))
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamUser(
|
VIRTUAL(void*) ISteamClient_GetISteamUser(
|
||||||
PARAMS(
|
PARAMS(
|
||||||
const HSteamUser hSteamUser,
|
const HSteamUser hSteamUser,
|
||||||
const HSteamPipe hSteamPipe,
|
const HSteamPipe hSteamPipe,
|
||||||
const char* version
|
const char* pchVersion
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return steam_client::GetGenericInterface(
|
||||||
return steam_client::GetGenericInterface(
|
__func__,
|
||||||
__func__,
|
pchVersion,
|
||||||
version,
|
SWAPPED_CALL_CLOSURE(ISteamClient_GetISteamUser, ARGS(hSteamUser, hSteamPipe, pchVersion))
|
||||||
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamUser, ARGS(hSteamUser, hSteamPipe, version))
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
|
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
|
||||||
PARAMS(
|
PARAMS(
|
||||||
HSteamUser hSteamUser,
|
const HSteamUser hSteamUser,
|
||||||
HSteamPipe hSteamPipe,
|
const HSteamPipe hSteamPipe,
|
||||||
const char* pchVersion
|
const char* pchVersion
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return steam_client::GetGenericInterface(
|
||||||
return steam_client::GetGenericInterface(
|
__func__,
|
||||||
__func__,
|
pchVersion,
|
||||||
pchVersion,
|
SWAPPED_CALL_CLOSURE(
|
||||||
HOOKED_CALL_CLOSURE(
|
ISteamClient_GetISteamGenericInterface,
|
||||||
ISteamClient_GetISteamGenericInterface,
|
ARGS(hSteamUser, hSteamPipe, pchVersion)
|
||||||
ARGS(hSteamUser, hSteamPipe, pchVersion)
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamInventory(
|
VIRTUAL(void*) ISteamClient_GetISteamInventory(
|
||||||
@@ -69,18 +54,13 @@ VIRTUAL(void*) ISteamClient_GetISteamInventory(
|
|||||||
const HSteamPipe hSteamPipe,
|
const HSteamPipe hSteamPipe,
|
||||||
const char* pchVersion
|
const char* pchVersion
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return steam_client::GetGenericInterface(
|
||||||
return steam_client::GetGenericInterface(
|
__func__,
|
||||||
__func__,
|
pchVersion,
|
||||||
pchVersion,
|
SWAPPED_CALL_CLOSURE(
|
||||||
HOOKED_CALL_CLOSURE(
|
ISteamClient_GetISteamInventory,
|
||||||
ISteamClient_GetISteamInventory,
|
ARGS(hSteamUser, hSteamPipe, pchVersion)
|
||||||
ARGS(hSteamUser, hSteamPipe, pchVersion)
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api/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/virtuals/steam_api_virtuals.hpp"
|
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||||
|
|
||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
|
||||||
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
|
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return smoke_api::steam_user::UserHasLicenseForApp(
|
||||||
return smoke_api::steam_user::UserHasLicenseForApp(
|
__func__,
|
||||||
__func__,
|
smoke_api::get_app_id(),
|
||||||
steam_interface::get_app_id(),
|
dlc_id,
|
||||||
dlc_id,
|
SWAPPED_CALL_CLOSURE(ISteamGameServer_UserHasLicenseForApp, ARGS(steamID, 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/steam_api/virtuals/isteamhttp.cpp
Normal file
65
src/steam_api/virtuals/isteamhttp.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api/interfaces/steam_http.hpp"
|
||||||
|
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||||
|
|
||||||
|
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(
|
||||||
|
PARAMS(
|
||||||
|
const HTTPRequestHandle hRequest,
|
||||||
|
const uint8_t* pBodyDataBuffer,
|
||||||
|
const uint32_t unBufferSize
|
||||||
|
)
|
||||||
|
) noexcept {
|
||||||
|
return smoke_api::steam_http::GetHTTPResponseBodyData(
|
||||||
|
__func__,
|
||||||
|
hRequest,
|
||||||
|
pBodyDataBuffer,
|
||||||
|
unBufferSize,
|
||||||
|
SWAPPED_CALL_CLOSURE(
|
||||||
|
ISteamHTTP_GetHTTPResponseBodyData,
|
||||||
|
ARGS(hRequest, pBodyDataBuffer, unBufferSize)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
VIRTUAL(bool) ISteamHTTP_GetHTTPStreamingResponseBodyData(
|
||||||
|
PARAMS(
|
||||||
|
const HTTPRequestHandle hRequest,
|
||||||
|
const uint32_t cOffset,
|
||||||
|
const uint8_t* pBodyDataBuffer,
|
||||||
|
const uint32_t unBufferSize
|
||||||
|
)
|
||||||
|
) noexcept {
|
||||||
|
return smoke_api::steam_http::GetHTTPStreamingResponseBodyData(
|
||||||
|
__func__,
|
||||||
|
hRequest,
|
||||||
|
cOffset,
|
||||||
|
pBodyDataBuffer,
|
||||||
|
unBufferSize,
|
||||||
|
SWAPPED_CALL_CLOSURE(
|
||||||
|
ISteamHTTP_GetHTTPStreamingResponseBodyData,
|
||||||
|
ARGS(hRequest, cOffset, pBodyDataBuffer, unBufferSize)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
VIRTUAL(bool) ISteamHTTP_SetHTTPRequestRawPostBody(
|
||||||
|
PARAMS(
|
||||||
|
const HTTPRequestHandle hRequest,
|
||||||
|
const char* pchContentType,
|
||||||
|
const uint8_t* pubBody,
|
||||||
|
const uint32_t unBodyLen
|
||||||
|
)
|
||||||
|
) noexcept {
|
||||||
|
return smoke_api::steam_http::SetHTTPRequestRawPostBody(
|
||||||
|
__func__,
|
||||||
|
hRequest,
|
||||||
|
pchContentType,
|
||||||
|
pubBody,
|
||||||
|
unBodyLen,
|
||||||
|
SWAPPED_CALL_CLOSURE(
|
||||||
|
ISteamHTTP_SetHTTPRequestRawPostBody,
|
||||||
|
ARGS(hRequest, pchContentType, pubBody, unBodyLen)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
VIRTUAL(EResult) ISteamInventory_GetResultStatus(
|
VIRTUAL(EResult) ISteamInventory_GetResultStatus(
|
||||||
PARAMS(const SteamInventoryResult_t resultHandle)
|
PARAMS(const SteamInventoryResult_t resultHandle)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::GetResultStatus(
|
return smoke_api::steam_inventory::GetResultStatus(
|
||||||
__func__,
|
__func__,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
HOOKED_CALL_CLOSURE(ISteamInventory_GetResultStatus, ARGS(resultHandle))
|
SWAPPED_CALL_CLOSURE(ISteamInventory_GetResultStatus, ARGS(resultHandle))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,18 +17,19 @@ VIRTUAL(bool) ISteamInventory_GetResultItems(
|
|||||||
SteamItemDetails_t* pOutItemsArray,
|
SteamItemDetails_t* pOutItemsArray,
|
||||||
uint32_t* punOutItemsArraySize
|
uint32_t* punOutItemsArraySize
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::GetResultItems(
|
return smoke_api::steam_inventory::GetResultItems(
|
||||||
__func__,
|
__func__,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
pOutItemsArray,
|
pOutItemsArray,
|
||||||
punOutItemsArraySize,
|
punOutItemsArraySize,
|
||||||
HOOKED_CALL_CLOSURE(
|
SWAPPED_CALL_CLOSURE(
|
||||||
ISteamInventory_GetResultItems,
|
ISteamInventory_GetResultItems,
|
||||||
ARGS(resultHandle, pOutItemsArray, punOutItemsArraySize)
|
ARGS(resultHandle, pOutItemsArray, punOutItemsArraySize)
|
||||||
),
|
),
|
||||||
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
|
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
|
||||||
HOOKED_CALL(
|
SWAPPED_CALL(
|
||||||
|
THIS,
|
||||||
ISteamInventory_GetItemDefinitionIDs,
|
ISteamInventory_GetItemDefinitionIDs,
|
||||||
ARGS(pItemDefIDs, punItemDefIDsArraySize)
|
ARGS(pItemDefIDs, punItemDefIDsArraySize)
|
||||||
);
|
);
|
||||||
@@ -44,7 +45,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
|||||||
char* pchValueBuffer,
|
char* pchValueBuffer,
|
||||||
uint32_t* punValueBufferSizeOut
|
uint32_t* punValueBufferSizeOut
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::GetResultItemProperty(
|
return smoke_api::steam_inventory::GetResultItemProperty(
|
||||||
__func__,
|
__func__,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
@@ -52,7 +53,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
|||||||
pchPropertyName,
|
pchPropertyName,
|
||||||
pchValueBuffer,
|
pchValueBuffer,
|
||||||
punValueBufferSizeOut,
|
punValueBufferSizeOut,
|
||||||
HOOKED_CALL_CLOSURE(
|
SWAPPED_CALL_CLOSURE(
|
||||||
ISteamInventory_GetResultItemProperty,
|
ISteamInventory_GetResultItemProperty,
|
||||||
ARGS(
|
ARGS(
|
||||||
resultHandle,
|
resultHandle,
|
||||||
@@ -65,11 +66,11 @@ VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) {
|
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) noexcept {
|
||||||
return smoke_api::steam_inventory::GetAllItems(
|
return smoke_api::steam_inventory::GetAllItems(
|
||||||
__func__,
|
__func__,
|
||||||
pResultHandle,
|
pResultHandle,
|
||||||
HOOKED_CALL_CLOSURE(ISteamInventory_GetAllItems, ARGS(pResultHandle))
|
SWAPPED_CALL_CLOSURE(ISteamInventory_GetAllItems, ARGS(pResultHandle))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,13 +80,13 @@ VIRTUAL(bool) ISteamInventory_GetItemsByID(
|
|||||||
const SteamItemInstanceID_t* pInstanceIDs,
|
const SteamItemInstanceID_t* pInstanceIDs,
|
||||||
const uint32_t unCountInstanceIDs
|
const uint32_t unCountInstanceIDs
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::GetItemsByID(
|
return smoke_api::steam_inventory::GetItemsByID(
|
||||||
__func__,
|
__func__,
|
||||||
pResultHandle,
|
pResultHandle,
|
||||||
pInstanceIDs,
|
pInstanceIDs,
|
||||||
unCountInstanceIDs,
|
unCountInstanceIDs,
|
||||||
HOOKED_CALL_CLOSURE(
|
SWAPPED_CALL_CLOSURE(
|
||||||
ISteamInventory_GetItemsByID,
|
ISteamInventory_GetItemsByID,
|
||||||
ARGS(pResultHandle, pInstanceIDs, unCountInstanceIDs)
|
ARGS(pResultHandle, pInstanceIDs, unCountInstanceIDs)
|
||||||
)
|
)
|
||||||
@@ -98,13 +99,13 @@ VIRTUAL(bool) ISteamInventory_SerializeResult(
|
|||||||
void* pOutBuffer,
|
void* pOutBuffer,
|
||||||
uint32_t* punOutBufferSize
|
uint32_t* punOutBufferSize
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::SerializeResult(
|
return smoke_api::steam_inventory::SerializeResult(
|
||||||
__func__,
|
__func__,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
pOutBuffer,
|
pOutBuffer,
|
||||||
punOutBufferSize,
|
punOutBufferSize,
|
||||||
HOOKED_CALL_CLOSURE(
|
SWAPPED_CALL_CLOSURE(
|
||||||
ISteamInventory_SerializeResult,
|
ISteamInventory_SerializeResult,
|
||||||
ARGS(resultHandle, pOutBuffer, punOutBufferSize)
|
ARGS(resultHandle, pOutBuffer, punOutBufferSize)
|
||||||
)
|
)
|
||||||
@@ -116,12 +117,12 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
|
|||||||
SteamItemDef_t*pItemDefIDs,
|
SteamItemDef_t*pItemDefIDs,
|
||||||
uint32_t* punItemDefIDsArraySize
|
uint32_t* punItemDefIDsArraySize
|
||||||
)
|
)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::GetItemDefinitionIDs(
|
return smoke_api::steam_inventory::GetItemDefinitionIDs(
|
||||||
__func__,
|
__func__,
|
||||||
pItemDefIDs,
|
pItemDefIDs,
|
||||||
punItemDefIDsArraySize,
|
punItemDefIDsArraySize,
|
||||||
HOOKED_CALL_CLOSURE(
|
SWAPPED_CALL_CLOSURE(
|
||||||
ISteamInventory_GetItemDefinitionIDs,
|
ISteamInventory_GetItemDefinitionIDs,
|
||||||
ARGS(pItemDefIDs, punItemDefIDsArraySize)
|
ARGS(pItemDefIDs, punItemDefIDsArraySize)
|
||||||
)
|
)
|
||||||
@@ -130,14 +131,11 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
|
|||||||
|
|
||||||
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
|
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
|
||||||
PARAMS(const SteamInventoryResult_t resultHandle, CSteamID steamIDExpected)
|
PARAMS(const SteamInventoryResult_t resultHandle, CSteamID steamIDExpected)
|
||||||
) {
|
) noexcept {
|
||||||
return smoke_api::steam_inventory::CheckResultSteamID(
|
return smoke_api::steam_inventory::CheckResultSteamID(
|
||||||
__func__,
|
__func__,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
steamIDExpected,
|
steamIDExpected,
|
||||||
HOOKED_CALL_CLOSURE(
|
SWAPPED_CALL_CLOSURE(ISteamInventory_CheckResultSteamID, ARGS(resultHandle, steamIDExpected))
|
||||||
ISteamInventory_CheckResultSteamID,
|
|
||||||
ARGS(resultHandle, steamIDExpected)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api/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/virtuals/steam_api_virtuals.hpp"
|
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||||
|
|
||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(
|
||||||
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
|
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
return smoke_api::steam_user::UserHasLicenseForApp(
|
||||||
static const auto app_id = steam_interface::get_app_id();
|
__func__,
|
||||||
return smoke_api::steam_user::UserHasLicenseForApp(
|
smoke_api::get_app_id(),
|
||||||
__func__,
|
dlc_id,
|
||||||
app_id,
|
SWAPPED_CALL_CLOSURE(ISteamUser_UserHasLicenseForApp, ARGS(steamID, dlc_id))
|
||||||
dlc_id,
|
);
|
||||||
HOOKED_CALL_CLOSURE(ISteamUser_UserHasLicenseForApp, ARGS(steamID, dlc_id))
|
|
||||||
);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
|
||||||
return k_EUserHasLicenseResultDoesNotHaveLicense;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,38 +3,63 @@
|
|||||||
#include "smoke_api/types.hpp"
|
#include "smoke_api/types.hpp"
|
||||||
|
|
||||||
// ISteamApps
|
// ISteamApps
|
||||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t));
|
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t)) noexcept;
|
||||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t));
|
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t)) noexcept;
|
||||||
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS());
|
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) noexcept;
|
||||||
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*, int));
|
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*, int)) noexcept;
|
||||||
|
|
||||||
// ISteamClient
|
// ISteamClient
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*));
|
VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*));
|
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(PARAMS(HSteamUser, HSteamPipe, const char*));
|
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamInventory(PARAMS(HSteamUser, HSteamPipe, const char*));
|
PARAMS(HSteamUser, HSteamPipe, const char*)
|
||||||
|
|
||||||
|
|
||||||
|
) noexcept;
|
||||||
|
VIRTUAL(void*) ISteamClient_GetISteamInventory(
|
||||||
|
PARAMS(HSteamUser, HSteamPipe, const char*)
|
||||||
|
|
||||||
|
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
// ISteamHTTP
|
||||||
|
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(
|
||||||
|
PARAMS(HTTPRequestHandle, const uint8_t*, uint32_t)
|
||||||
|
) noexcept;
|
||||||
|
VIRTUAL(bool) ISteamHTTP_GetHTTPStreamingResponseBodyData(
|
||||||
|
PARAMS(HTTPRequestHandle, uint32_t, const uint8_t*, uint32_t)
|
||||||
|
) noexcept;
|
||||||
|
VIRTUAL(bool) ISteamHTTP_SetHTTPRequestRawPostBody(
|
||||||
|
PARAMS(HTTPRequestHandle, const char*, const uint8_t*, uint32_t)
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
// ISteamInventory
|
// ISteamInventory
|
||||||
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
|
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t)) noexcept;
|
||||||
VIRTUAL(bool) ISteamInventory_GetResultItems(
|
VIRTUAL(bool) ISteamInventory_GetResultItems(
|
||||||
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*) // @formatter:off
|
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*) // @formatter:off
|
||||||
); // @formatter:on
|
) noexcept; // @formatter:on
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
||||||
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*) // @formatter:off
|
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*) // @formatter:off
|
||||||
); // @formatter:on
|
) noexcept; // @formatter:on
|
||||||
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t*));
|
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t*)) noexcept;
|
||||||
VIRTUAL(bool) ISteamInventory_GetItemsByID(
|
VIRTUAL(bool) ISteamInventory_GetItemsByID(
|
||||||
PARAMS(SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t)
|
PARAMS(SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t)
|
||||||
);
|
) noexcept;
|
||||||
VIRTUAL(bool) ISteamInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t*));
|
VIRTUAL(bool) ISteamInventory_SerializeResult(
|
||||||
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t*));
|
PARAMS(SteamInventoryResult_t, void*, uint32_t*)
|
||||||
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID));
|
|
||||||
|
|
||||||
|
) noexcept;
|
||||||
|
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t*)) noexcept;
|
||||||
|
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID)) noexcept;
|
||||||
|
|
||||||
// ISteamUser
|
// ISteamUser
|
||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(
|
||||||
|
PARAMS(CSteamID, AppId_t)
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
// ISteamGameServer
|
// ISteamGameServer
|
||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(
|
||||||
PARAMS(CSteamID, AppId_t)
|
PARAMS(CSteamID, AppId_t)
|
||||||
);
|
) noexcept;
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#include "smoke_api/steamclient/steamclient.hpp"
|
|
||||||
#include "smoke_api.hpp"
|
|
||||||
#include "smoke_api/types.hpp"
|
|
||||||
|
|
||||||
#include "steam_api/steam_client.hpp"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SmokeAPI implementation
|
|
||||||
*/
|
|
||||||
C_DECL(void*) CreateInterface(const char* interface_version, int* out_result) {
|
|
||||||
return steam_client::GetGenericInterface(
|
|
||||||
__func__,
|
|
||||||
interface_version,
|
|
||||||
HOOKED_CALL_CLOSURE(CreateInterface, interface_version, out_result)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
27
src/steamclient/steamclient.cpp
Normal file
27
src/steamclient/steamclient.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <koalabox/hook.hpp>
|
||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api/steamclient/steamclient.hpp"
|
||||||
|
#include "smoke_api/types.hpp"
|
||||||
|
|
||||||
|
#include "steam_api/steam_client.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SmokeAPI implementation
|
||||||
|
*/
|
||||||
|
C_DECL(void*) CreateInterface(const char* interface_version, create_interface_result* out_result) {
|
||||||
|
// Mutex here helps us detect unintended recursion early on by throwing an exception.
|
||||||
|
static std::mutex section;
|
||||||
|
const std::lock_guard lock(section);
|
||||||
|
|
||||||
|
return steam_client::GetGenericInterface(
|
||||||
|
__func__,
|
||||||
|
interface_version,
|
||||||
|
[&] {
|
||||||
|
static const auto CreateInterface$ = KB_HOOK_GET_HOOKED_FN(CreateInterface);
|
||||||
|
return CreateInterface$(interface_version, out_result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -10,21 +10,18 @@ namespace smoke_api::config {
|
|||||||
LOCKED,
|
LOCKED,
|
||||||
};
|
};
|
||||||
|
|
||||||
NLOHMANN_JSON_SERIALIZE_ENUM(
|
// @formatter:off
|
||||||
AppStatus,
|
NLOHMANN_JSON_SERIALIZE_ENUM(AppStatus, {
|
||||||
// @formatter:off
|
{ AppStatus::UNDEFINED, nullptr },
|
||||||
{
|
{ AppStatus::ORIGINAL, "original" },
|
||||||
{ AppStatus::UNDEFINED, nullptr },
|
{ AppStatus::UNLOCKED, "unlocked" },
|
||||||
{ AppStatus::ORIGINAL, "original" },
|
{ AppStatus::LOCKED, "locked" },
|
||||||
{ AppStatus::UNLOCKED, "unlocked" },
|
}) // @formatter:on
|
||||||
{ AppStatus::LOCKED, "locked" },
|
|
||||||
}
|
|
||||||
// @formatter:on
|
|
||||||
)
|
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
uint32_t $version = 3;
|
uint32_t $version = 4;
|
||||||
bool logging = false;
|
bool logging = false;
|
||||||
|
bool log_steam_http = false;
|
||||||
AppStatus default_app_status = AppStatus::UNLOCKED;
|
AppStatus default_app_status = AppStatus::UNLOCKED;
|
||||||
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;
|
||||||
@@ -32,10 +29,11 @@ namespace smoke_api::config {
|
|||||||
bool auto_inject_inventory = true;
|
bool auto_inject_inventory = true;
|
||||||
std::vector<uint32_t> extra_inventory_items;
|
std::vector<uint32_t> extra_inventory_items;
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||||
Config,
|
Config,
|
||||||
$version,
|
$version,
|
||||||
logging,
|
logging,
|
||||||
|
log_steam_http,
|
||||||
default_app_status,
|
default_app_status,
|
||||||
override_app_status,
|
override_app_status,
|
||||||
override_dlc_status,
|
override_dlc_status,
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace smoke_api::steam_apps {
|
|||||||
const AppId_t app_id,
|
const AppId_t app_id,
|
||||||
const AppId_t dlc_id,
|
const AppId_t dlc_id,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
try {
|
||||||
const auto unlocked = config::is_dlc_unlocked(
|
const auto unlocked = config::is_dlc_unlocked(
|
||||||
app_id,
|
app_id,
|
||||||
@@ -103,7 +103,7 @@ namespace smoke_api::steam_apps {
|
|||||||
|
|
||||||
return unlocked;
|
return unlocked;
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
LOG_ERROR("Uncaught exception: {}", e.what());
|
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ namespace smoke_api::steam_apps {
|
|||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const AppId_t app_id,
|
const AppId_t app_id,
|
||||||
const std::function<int()>& original_function
|
const std::function<int()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
try {
|
||||||
const auto total_count = [&](int count) {
|
const auto total_count = [&](int count) {
|
||||||
LOG_INFO("{} -> Responding with DLC count: {}", function_name, count);
|
LOG_INFO("{} -> Responding with DLC count: {}", function_name, count);
|
||||||
@@ -139,7 +139,7 @@ namespace smoke_api::steam_apps {
|
|||||||
|
|
||||||
return total_count(static_cast<int>(app_dlcs[app_id].size()));
|
return total_count(static_cast<int>(app_dlcs[app_id].size()));
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
LOG_ERROR("Uncaught exception: {}", function_name, e.what());
|
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,8 +153,8 @@ namespace smoke_api::steam_apps {
|
|||||||
char* pchName,
|
char* pchName,
|
||||||
const int cchNameBufferSize,
|
const int cchNameBufferSize,
|
||||||
const std::function<bool()>& original_function,
|
const std::function<bool()>& original_function,
|
||||||
const std::function<bool(AppId_t)>& is_originally_unlocked
|
const std::function<bool()>& is_originally_unlocked
|
||||||
) {
|
) noexcept {
|
||||||
try {
|
try {
|
||||||
LOG_DEBUG("{} -> {}index: {:>3}", function_name, get_app_id_log(app_id), iDLC);
|
LOG_DEBUG("{} -> {}index: {:>3}", function_name, get_app_id_log(app_id), iDLC);
|
||||||
|
|
||||||
@@ -174,13 +174,7 @@ namespace smoke_api::steam_apps {
|
|||||||
const auto output_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 = config::is_dlc_unlocked(
|
*pbAvailable = config::is_dlc_unlocked(app_id, *pDlcId, is_originally_unlocked);
|
||||||
app_id,
|
|
||||||
*pDlcId,
|
|
||||||
[&] {
|
|
||||||
return is_originally_unlocked(*pDlcId);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
auto name = dlc.get_name();
|
auto name = dlc.get_name();
|
||||||
name = name.substr(0, cchNameBufferSize + 1);
|
name = name.substr(0, cchNameBufferSize + 1);
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ namespace smoke_api::steam_apps {
|
|||||||
AppId_t app_id,
|
AppId_t app_id,
|
||||||
AppId_t dlc_id,
|
AppId_t dlc_id,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
int GetDLCCount(
|
int GetDLCCount(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
AppId_t app_id,
|
AppId_t app_id,
|
||||||
const std::function<int()>& original_function
|
const std::function<int()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool GetDLCDataByIndex(
|
bool GetDLCDataByIndex(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
@@ -25,6 +25,6 @@ namespace smoke_api::steam_apps {
|
|||||||
char* pchName,
|
char* pchName,
|
||||||
int cchNameBufferSize,
|
int cchNameBufferSize,
|
||||||
const std::function<bool()>& original_function,
|
const std::function<bool()>& original_function,
|
||||||
const std::function<bool(AppId_t)>& is_originally_unlocked
|
const std::function<bool()>& is_originally_unlocked
|
||||||
);
|
) noexcept;
|
||||||
}
|
}
|
||||||
|
|||||||
115
static/smoke_api/interfaces/steam_http.cpp
Normal file
115
static/smoke_api/interfaces/steam_http.cpp
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
|
#include "smoke_api/interfaces/steam_http.hpp"
|
||||||
|
#include "smoke_api/config.hpp"
|
||||||
|
|
||||||
|
namespace smoke_api::steam_http {
|
||||||
|
bool GetHTTPResponseBodyData(
|
||||||
|
const std::string& function_name,
|
||||||
|
const HTTPRequestHandle hRequest,
|
||||||
|
const uint8_t* pBodyDataBuffer,
|
||||||
|
const uint32_t unBufferSize,
|
||||||
|
const std::function<bool()>& original_function
|
||||||
|
) noexcept {
|
||||||
|
try {
|
||||||
|
const auto result = original_function();
|
||||||
|
|
||||||
|
if(config::instance.log_steam_http) {
|
||||||
|
const std::string_view buffer =
|
||||||
|
pBodyDataBuffer && unBufferSize
|
||||||
|
? std::string_view(
|
||||||
|
reinterpret_cast<const char*>(pBodyDataBuffer),
|
||||||
|
unBufferSize
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
LOG_INFO(
|
||||||
|
"{} -> handle: {}, size: {}, buffer:\n{}",
|
||||||
|
function_name,
|
||||||
|
hRequest,
|
||||||
|
unBufferSize,
|
||||||
|
buffer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetHTTPStreamingResponseBodyData(
|
||||||
|
const std::string& function_name,
|
||||||
|
const HTTPRequestHandle hRequest,
|
||||||
|
const uint32_t cOffset,
|
||||||
|
const uint8_t* pBodyDataBuffer,
|
||||||
|
const uint32_t unBufferSize,
|
||||||
|
const std::function<bool()>& original_function
|
||||||
|
) noexcept {
|
||||||
|
try {
|
||||||
|
const auto result = original_function();
|
||||||
|
|
||||||
|
if(config::instance.log_steam_http) {
|
||||||
|
const std::string_view buffer =
|
||||||
|
pBodyDataBuffer && unBufferSize
|
||||||
|
? std::string_view(
|
||||||
|
reinterpret_cast<const char*>(pBodyDataBuffer),
|
||||||
|
unBufferSize
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
LOG_INFO(
|
||||||
|
"{} -> handle: {}, offset: {}, size: {}, buffer:\n{}",
|
||||||
|
function_name,
|
||||||
|
hRequest,
|
||||||
|
cOffset,
|
||||||
|
unBufferSize,
|
||||||
|
buffer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetHTTPRequestRawPostBody(
|
||||||
|
const std::string& function_name,
|
||||||
|
const HTTPRequestHandle hRequest,
|
||||||
|
const char* pchContentType,
|
||||||
|
const uint8_t* pubBody,
|
||||||
|
const uint32_t unBodyLen,
|
||||||
|
const std::function<bool()>& original_function
|
||||||
|
) noexcept {
|
||||||
|
try {
|
||||||
|
const auto result = original_function();
|
||||||
|
|
||||||
|
if(config::instance.log_steam_http) {
|
||||||
|
const std::string_view content_type =
|
||||||
|
pchContentType ? pchContentType : "smoke_api::N/A";
|
||||||
|
|
||||||
|
const std::string_view buffer =
|
||||||
|
pubBody && unBodyLen
|
||||||
|
? std::string_view(reinterpret_cast<const char*>(pubBody), unBodyLen)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
LOG_INFO(
|
||||||
|
"{} -> handle: {}, content-type: {}, size: {}, buffer:\n{}",
|
||||||
|
function_name,
|
||||||
|
hRequest,
|
||||||
|
content_type,
|
||||||
|
unBodyLen,
|
||||||
|
buffer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
static/smoke_api/interfaces/steam_http.hpp
Normal file
31
static/smoke_api/interfaces/steam_http.hpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "smoke_api/types.hpp"
|
||||||
|
|
||||||
|
namespace smoke_api::steam_http {
|
||||||
|
bool GetHTTPResponseBodyData(
|
||||||
|
const std::string& function_name,
|
||||||
|
HTTPRequestHandle hRequest,
|
||||||
|
const uint8_t* pBodyDataBuffer,
|
||||||
|
uint32_t unBufferSize,
|
||||||
|
const std::function<bool()>& original_function
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
bool GetHTTPStreamingResponseBodyData(
|
||||||
|
const std::string& function_name,
|
||||||
|
HTTPRequestHandle hRequest,
|
||||||
|
uint32_t cOffset,
|
||||||
|
const uint8_t* pBodyDataBuffer,
|
||||||
|
uint32_t unBufferSize,
|
||||||
|
const std::function<bool()>& original_function
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
bool SetHTTPRequestRawPostBody(
|
||||||
|
const std::string& function_name,
|
||||||
|
HTTPRequestHandle hRequest,
|
||||||
|
const char* pchContentType,
|
||||||
|
const uint8_t* pubBody,
|
||||||
|
uint32_t unBodyLen,
|
||||||
|
const std::function<bool()>& original_function
|
||||||
|
) noexcept;
|
||||||
|
}
|
||||||
@@ -8,17 +8,22 @@ namespace smoke_api::steam_inventory {
|
|||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const SteamInventoryResult_t resultHandle,
|
const SteamInventoryResult_t resultHandle,
|
||||||
const std::function<EResult()>& original_function
|
const std::function<EResult()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto status = original_function();
|
try {
|
||||||
|
const auto status = original_function();
|
||||||
|
|
||||||
LOG_DEBUG(
|
LOG_DEBUG(
|
||||||
"{} -> handle: {}, status: {}",
|
"{} -> handle: {}, status: {}",
|
||||||
function_name,
|
function_name,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
static_cast<int>(status)
|
static_cast<int>(status)
|
||||||
);
|
);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return EResult::k_EResultFail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetResultItems(
|
bool GetResultItems(
|
||||||
@@ -28,107 +33,112 @@ namespace smoke_api::steam_inventory {
|
|||||||
uint32_t* punOutItemsArraySize,
|
uint32_t* punOutItemsArraySize,
|
||||||
const std::function<bool()>& original_function,
|
const std::function<bool()>& original_function,
|
||||||
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
|
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
|
||||||
) {
|
) noexcept {
|
||||||
static std::mutex section;
|
try {
|
||||||
const std::lock_guard guard(section);
|
static std::mutex section;
|
||||||
|
const std::lock_guard guard(section);
|
||||||
|
|
||||||
const auto success = original_function();
|
const auto success = original_function();
|
||||||
|
|
||||||
auto print_item = [](const std::string& tag, const SteamItemDetails_t& item) {
|
auto print_item = [](const std::string& tag, const SteamItemDetails_t& item) {
|
||||||
LOG_DEBUG(
|
LOG_DEBUG(
|
||||||
" [{}] definitionId: {}, itemId: {}, quantity: {}, flags: {}",
|
" [{}] definitionId: {}, itemId: {}, quantity: {}, flags: {}",
|
||||||
tag,
|
tag,
|
||||||
item.m_iDefinition,
|
item.m_iDefinition,
|
||||||
item.m_itemId,
|
item.m_itemId,
|
||||||
item.m_unQuantity,
|
item.m_unQuantity,
|
||||||
item.m_unFlags
|
item.m_unFlags
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
if(not success) {
|
|
||||||
LOG_DEBUG("{} -> original result is false", function_name);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(punOutItemsArraySize == nullptr) {
|
|
||||||
LOG_ERROR("{} -> arraySize pointer is null", function_name);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(
|
|
||||||
"{} -> handle: {}, pOutItemsArray: {}, arraySize: {}",
|
|
||||||
function_name,
|
|
||||||
resultHandle,
|
|
||||||
reinterpret_cast<void*>(pOutItemsArray),
|
|
||||||
*punOutItemsArraySize
|
|
||||||
);
|
|
||||||
|
|
||||||
static uint32_t original_count = 0;
|
|
||||||
const auto injected_count = config::instance.extra_inventory_items.size();
|
|
||||||
|
|
||||||
// Automatically get inventory items from steam
|
|
||||||
static std::vector<SteamItemDef_t> auto_inventory_items;
|
|
||||||
if(config::instance.auto_inject_inventory) {
|
|
||||||
static std::once_flag inventory_inject_flag;
|
|
||||||
std::call_once(
|
|
||||||
inventory_inject_flag,
|
|
||||||
[&] {
|
|
||||||
uint32_t count = 0;
|
|
||||||
if(get_item_definition_ids(nullptr, &count)) {
|
|
||||||
auto_inventory_items.resize(count);
|
|
||||||
get_item_definition_ids(auto_inventory_items.data(), &count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto auto_injected_count = auto_inventory_items.size();
|
|
||||||
|
|
||||||
if(not pOutItemsArray) {
|
|
||||||
// If pOutItemsArray is NULL then we must set the array size.
|
|
||||||
original_count = *punOutItemsArraySize;
|
|
||||||
*punOutItemsArraySize += auto_injected_count + injected_count;
|
|
||||||
LOG_DEBUG(
|
|
||||||
"{} -> Original count: {}, Total count: {}",
|
|
||||||
function_name,
|
|
||||||
original_count,
|
|
||||||
*punOutItemsArraySize
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Otherwise, we modify the array
|
|
||||||
for(int i = 0; i < original_count; i++) {
|
|
||||||
print_item("original", pOutItemsArray[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto new_item = [](SteamItemDef_t id) {
|
|
||||||
return SteamItemDetails_t{
|
|
||||||
.m_itemId = id,
|
|
||||||
.m_iDefinition = id,
|
|
||||||
.m_unQuantity = 1,
|
|
||||||
.m_unFlags = 0,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for(int i = 0; i < auto_injected_count; i++) {
|
if(not success) {
|
||||||
auto& item = pOutItemsArray[original_count + i];
|
LOG_DEBUG("{} -> original result is false", function_name);
|
||||||
const auto item_def_id = auto_inventory_items[i];
|
return success;
|
||||||
|
|
||||||
item = new_item(item_def_id);
|
|
||||||
|
|
||||||
print_item("auto-injected", item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < injected_count; i++) {
|
if(punOutItemsArraySize == nullptr) {
|
||||||
auto& item = pOutItemsArray[original_count + auto_injected_count + i];
|
LOG_ERROR("{} -> arraySize pointer is null", function_name);
|
||||||
const auto item_def_id = config::instance.extra_inventory_items[i];
|
return success;
|
||||||
|
|
||||||
item = new_item(item_def_id);
|
|
||||||
|
|
||||||
print_item("injected", item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(
|
||||||
|
"{} -> handle: {}, pOutItemsArray: {}, arraySize: {}",
|
||||||
|
function_name,
|
||||||
|
resultHandle,
|
||||||
|
reinterpret_cast<void*>(pOutItemsArray),
|
||||||
|
*punOutItemsArraySize
|
||||||
|
);
|
||||||
|
|
||||||
|
static uint32_t original_count = 0;
|
||||||
|
const auto injected_count = config::instance.extra_inventory_items.size();
|
||||||
|
|
||||||
|
// Automatically get inventory items from steam
|
||||||
|
static std::vector<SteamItemDef_t> auto_inventory_items;
|
||||||
|
if(config::instance.auto_inject_inventory) {
|
||||||
|
static std::once_flag inventory_inject_flag;
|
||||||
|
std::call_once(
|
||||||
|
inventory_inject_flag,
|
||||||
|
[&] {
|
||||||
|
uint32_t count = 0;
|
||||||
|
if(get_item_definition_ids(nullptr, &count)) {
|
||||||
|
auto_inventory_items.resize(count);
|
||||||
|
get_item_definition_ids(auto_inventory_items.data(), &count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto auto_injected_count = auto_inventory_items.size();
|
||||||
|
|
||||||
|
if(not pOutItemsArray) {
|
||||||
|
// If pOutItemsArray is NULL then we must set the array size.
|
||||||
|
original_count = *punOutItemsArraySize;
|
||||||
|
*punOutItemsArraySize += auto_injected_count + injected_count;
|
||||||
|
LOG_DEBUG(
|
||||||
|
"{} -> Original count: {}, Total count: {}",
|
||||||
|
function_name,
|
||||||
|
original_count,
|
||||||
|
*punOutItemsArraySize
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Otherwise, we modify the array
|
||||||
|
for(int i = 0; i < original_count; i++) {
|
||||||
|
print_item("original", pOutItemsArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto new_item = [](SteamItemDef_t id) {
|
||||||
|
return SteamItemDetails_t{
|
||||||
|
.m_itemId = id,
|
||||||
|
.m_iDefinition = id,
|
||||||
|
.m_unQuantity = 1,
|
||||||
|
.m_unFlags = 0,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i = 0; i < auto_injected_count; i++) {
|
||||||
|
auto& item = pOutItemsArray[original_count + i];
|
||||||
|
const auto item_def_id = auto_inventory_items[i];
|
||||||
|
|
||||||
|
item = new_item(item_def_id);
|
||||||
|
|
||||||
|
print_item("auto-injected", item);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < injected_count; i++) {
|
||||||
|
auto& item = pOutItemsArray[original_count + auto_injected_count + i];
|
||||||
|
const auto item_def_id = config::instance.extra_inventory_items[i];
|
||||||
|
|
||||||
|
item = new_item(item_def_id);
|
||||||
|
|
||||||
|
print_item("injected", item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetResultItemProperty(
|
bool GetResultItemProperty(
|
||||||
@@ -139,47 +149,61 @@ namespace smoke_api::steam_inventory {
|
|||||||
const char* pchValueBuffer,
|
const char* pchValueBuffer,
|
||||||
const uint32_t* punValueBufferSizeOut,
|
const uint32_t* punValueBufferSizeOut,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
LOG_DEBUG(
|
try {
|
||||||
"{} -> Handle: {}, Index: {}, Name: '{}'",
|
LOG_DEBUG(
|
||||||
function_name,
|
"{} -> Handle: {}, Index: {}, Name: '{}'",
|
||||||
resultHandle,
|
function_name,
|
||||||
unItemIndex,
|
resultHandle,
|
||||||
// can be empty, in which case steam responds with property list in csv format
|
unItemIndex,
|
||||||
pchPropertyName ? pchPropertyName : "nullptr"
|
// 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", function_name);
|
LOG_WARN("{} -> Result is false", function_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(
|
||||||
|
pchValueBuffer && *pchValueBuffer &&
|
||||||
|
punValueBufferSizeOut && *punValueBufferSizeOut > 0
|
||||||
|
) {
|
||||||
|
LOG_DEBUG(
|
||||||
|
R"('{}' -> Buffer: "{}")",
|
||||||
|
function_name,
|
||||||
|
std::string(pchValueBuffer, *punValueBufferSizeOut - 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
|
||||||
pchValueBuffer && *pchValueBuffer &&
|
|
||||||
punValueBufferSizeOut && *punValueBufferSizeOut > 0
|
|
||||||
) {
|
|
||||||
LOG_DEBUG(
|
|
||||||
R"({} -> Buffer: "{}")",
|
|
||||||
function_name,
|
|
||||||
std::string(pchValueBuffer, *punValueBufferSizeOut - 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetAllItems(
|
bool GetAllItems(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const SteamInventoryResult_t* pResultHandle,
|
const SteamInventoryResult_t* pResultHandle,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto success = original_function();
|
try {
|
||||||
|
const auto success = original_function();
|
||||||
|
|
||||||
LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle));
|
LOG_DEBUG(
|
||||||
|
"{} -> Handle: {}",
|
||||||
|
function_name,
|
||||||
|
reinterpret_cast<const void*>(pResultHandle)
|
||||||
|
);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetItemsByID(
|
bool GetItemsByID(
|
||||||
@@ -188,18 +212,23 @@ namespace smoke_api::steam_inventory {
|
|||||||
const SteamItemInstanceID_t* pInstanceIDs,
|
const SteamItemInstanceID_t* pInstanceIDs,
|
||||||
const uint32_t unCountInstanceIDs,
|
const uint32_t unCountInstanceIDs,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto success = original_function();
|
try {
|
||||||
|
const auto success = original_function();
|
||||||
|
|
||||||
LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle));
|
LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle));
|
||||||
|
|
||||||
if(success && pInstanceIDs != nullptr) {
|
if(success && pInstanceIDs != nullptr) {
|
||||||
for(int i = 0; i < unCountInstanceIDs; i++) {
|
for(int i = 0; i < unCountInstanceIDs; i++) {
|
||||||
LOG_DEBUG(" Index: {}, ItemId: {}", i, pInstanceIDs[i]);
|
LOG_DEBUG(" Index: {}, ItemId: {}", i, pInstanceIDs[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerializeResult(
|
bool SerializeResult(
|
||||||
@@ -208,22 +237,27 @@ namespace smoke_api::steam_inventory {
|
|||||||
void* pOutBuffer,
|
void* pOutBuffer,
|
||||||
uint32_t* punOutBufferSize,
|
uint32_t* punOutBufferSize,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto success = original_function();
|
try {
|
||||||
|
const auto success = original_function();
|
||||||
|
|
||||||
if(pOutBuffer != nullptr) {
|
if(pOutBuffer != nullptr) {
|
||||||
std::string buffer(static_cast<char*>(pOutBuffer), *punOutBufferSize);
|
std::string buffer(static_cast<char*>(pOutBuffer), *punOutBufferSize);
|
||||||
LOG_DEBUG("{} -> Handle: {}, Buffer: '{}'", function_name, resultHandle, buffer);
|
LOG_DEBUG("{} -> Handle: {}, Buffer: '{}'", function_name, resultHandle, buffer);
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(
|
LOG_DEBUG(
|
||||||
"{} -> Handle: {}, Size: '{}'",
|
"{} -> Handle: {}, Size: '{}'",
|
||||||
function_name,
|
function_name,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
*punOutBufferSize
|
*punOutBufferSize
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetItemDefinitionIDs(
|
bool GetItemDefinitionIDs(
|
||||||
@@ -231,28 +265,33 @@ namespace smoke_api::steam_inventory {
|
|||||||
const SteamItemDef_t* pItemDefIDs,
|
const SteamItemDef_t* pItemDefIDs,
|
||||||
uint32_t* punItemDefIDsArraySize,
|
uint32_t* punItemDefIDsArraySize,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto success = original_function();
|
try {
|
||||||
|
const auto success = original_function();
|
||||||
|
|
||||||
if(!success) {
|
if(!success) {
|
||||||
LOG_WARN("{} -> Result is false", function_name);
|
LOG_WARN("{} -> Result is false", function_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(punItemDefIDsArraySize) {
|
||||||
|
LOG_DEBUG("{} -> Size: {}", function_name, *punItemDefIDsArraySize);
|
||||||
|
} else {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pItemDefIDs) { // Definitions were copied
|
||||||
|
for(int i = 0; i < *punItemDefIDsArraySize; i++) {
|
||||||
|
const auto& def = pItemDefIDs[i];
|
||||||
|
LOG_DEBUG(" Index: {}, ID: {}", i, def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(punItemDefIDsArraySize) {
|
|
||||||
LOG_DEBUG("{} -> Size: {}", function_name, *punItemDefIDsArraySize);
|
|
||||||
} else {
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pItemDefIDs) { // Definitions were copied
|
|
||||||
for(int i = 0; i < *punItemDefIDsArraySize; i++) {
|
|
||||||
const auto& def = pItemDefIDs[i];
|
|
||||||
LOG_DEBUG(" Index: {}, ID: {}", i, def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckResultSteamID(
|
bool CheckResultSteamID(
|
||||||
@@ -260,17 +299,22 @@ namespace smoke_api::steam_inventory {
|
|||||||
SteamInventoryResult_t resultHandle,
|
SteamInventoryResult_t resultHandle,
|
||||||
CSteamID steamIDExpected,
|
CSteamID steamIDExpected,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto result = original_function();
|
try {
|
||||||
|
const auto result = original_function();
|
||||||
|
|
||||||
LOG_DEBUG(
|
LOG_DEBUG(
|
||||||
"{} -> handle: {}, steamID: {}, original result: {}",
|
"{} -> handle: {}, steamID: {}, original result: {}",
|
||||||
function_name,
|
function_name,
|
||||||
resultHandle,
|
resultHandle,
|
||||||
steamIDExpected,
|
steamIDExpected,
|
||||||
result
|
result
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace smoke_api::steam_inventory {
|
|||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
SteamInventoryResult_t resultHandle,
|
SteamInventoryResult_t resultHandle,
|
||||||
const std::function<EResult()>& original_function
|
const std::function<EResult()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool GetResultItems(
|
bool GetResultItems(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
@@ -16,7 +16,7 @@ namespace smoke_api::steam_inventory {
|
|||||||
uint32_t* punOutItemsArraySize,
|
uint32_t* punOutItemsArraySize,
|
||||||
const std::function<bool()>& original_function,
|
const std::function<bool()>& original_function,
|
||||||
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
|
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool GetResultItemProperty(
|
bool GetResultItemProperty(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
@@ -26,13 +26,13 @@ namespace smoke_api::steam_inventory {
|
|||||||
const char* pchValueBuffer,
|
const char* pchValueBuffer,
|
||||||
const uint32_t* punValueBufferSizeOut,
|
const uint32_t* punValueBufferSizeOut,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool GetAllItems(
|
bool GetAllItems(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const SteamInventoryResult_t* pResultHandle,
|
const SteamInventoryResult_t* pResultHandle,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool GetItemsByID(
|
bool GetItemsByID(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
@@ -40,7 +40,7 @@ namespace smoke_api::steam_inventory {
|
|||||||
const SteamItemInstanceID_t* pInstanceIDs,
|
const SteamItemInstanceID_t* pInstanceIDs,
|
||||||
uint32_t unCountInstanceIDs,
|
uint32_t unCountInstanceIDs,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool SerializeResult(
|
bool SerializeResult(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
@@ -48,19 +48,19 @@ namespace smoke_api::steam_inventory {
|
|||||||
void* pOutBuffer,
|
void* pOutBuffer,
|
||||||
uint32_t* punOutBufferSize,
|
uint32_t* punOutBufferSize,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool GetItemDefinitionIDs(
|
bool GetItemDefinitionIDs(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
const SteamItemDef_t* pItemDefIDs,
|
const SteamItemDef_t* pItemDefIDs,
|
||||||
uint32_t* punItemDefIDsArraySize,
|
uint32_t* punItemDefIDsArraySize,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
|
|
||||||
bool CheckResultSteamID(
|
bool CheckResultSteamID(
|
||||||
const std::string& function_name,
|
const std::string& function_name,
|
||||||
SteamInventoryResult_t resultHandle,
|
SteamInventoryResult_t resultHandle,
|
||||||
CSteamID steamIDExpected,
|
CSteamID steamIDExpected,
|
||||||
const std::function<bool()>& original_function
|
const std::function<bool()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,26 +9,31 @@ namespace smoke_api::steam_user {
|
|||||||
const AppId_t appId,
|
const AppId_t appId,
|
||||||
const AppId_t dlcId,
|
const AppId_t dlcId,
|
||||||
const std::function<EUserHasLicenseForAppResult()>& original_function
|
const std::function<EUserHasLicenseForAppResult()>& original_function
|
||||||
) {
|
) noexcept {
|
||||||
const auto result = original_function();
|
try {
|
||||||
|
const auto result = original_function();
|
||||||
|
|
||||||
if(result == k_EUserHasLicenseResultNoAuth) {
|
if(result == k_EUserHasLicenseResultNoAuth) {
|
||||||
LOG_WARN("{} -> App ID: {:>8}, Result: NoAuth", function_name, dlcId);
|
LOG_WARN("{} -> App ID: {:>8}, Result: NoAuth", function_name, dlcId);
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
const auto has_license = config::is_dlc_unlocked(
|
|
||||||
appId,
|
|
||||||
dlcId,
|
|
||||||
[&] {
|
|
||||||
return result == k_EUserHasLicenseResultHasLicense;
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
LOG_INFO("{} -> App ID: {:>8}, HasLicense: {}", function_name, dlcId, has_license);
|
const auto has_license = config::is_dlc_unlocked(
|
||||||
|
appId,
|
||||||
|
dlcId,
|
||||||
|
[&] {
|
||||||
|
return result == k_EUserHasLicenseResultHasLicense;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return has_license
|
LOG_INFO("{} -> App ID: {:>8}, HasLicense: {}", function_name, dlcId, has_license);
|
||||||
? k_EUserHasLicenseResultHasLicense
|
|
||||||
: k_EUserHasLicenseResultDoesNotHaveLicense;
|
return has_license
|
||||||
|
? k_EUserHasLicenseResultHasLicense
|
||||||
|
: k_EUserHasLicenseResultDoesNotHaveLicense;
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error: {}", function_name, e.what());
|
||||||
|
return k_EUserHasLicenseResultDoesNotHaveLicense;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ namespace smoke_api::steam_user {
|
|||||||
AppId_t appId,
|
AppId_t appId,
|
||||||
AppId_t dlcId,
|
AppId_t dlcId,
|
||||||
const std::function<EUserHasLicenseForAppResult()>& original_function
|
const std::function<EUserHasLicenseForAppResult()>& original_function
|
||||||
);
|
) noexcept;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,13 @@
|
|||||||
|
|
||||||
#include "smoke_api/types.hpp"
|
#include "smoke_api/types.hpp"
|
||||||
|
|
||||||
C_DECL(void*) CreateInterface(const char* interface_version, int* out_result);
|
enum class create_interface_result {
|
||||||
|
Success = 0,
|
||||||
|
Error = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param interface_version Example: STEAMAPPS_INTERFACE_VERSION008
|
||||||
|
* @param out_result Pointer to the result enum that will be written to. Can be nullptr.
|
||||||
|
*/
|
||||||
|
C_DECL(void*) CreateInterface(const char* interface_version, create_interface_result* out_result);
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ std::vector<DLC> DLC::get_dlcs_from_apps(const AppDlcNameMap& apps, const AppId_
|
|||||||
std::vector<DLC> dlcs;
|
std::vector<DLC> dlcs;
|
||||||
|
|
||||||
if(const auto app_id_str = std::to_string(app_id); apps.contains(app_id_str)) {
|
if(const auto app_id_str = std::to_string(app_id); apps.contains(app_id_str)) {
|
||||||
const auto& app = apps.at(app_id_str);
|
const auto& [app_dlcs] = apps.at(app_id_str);
|
||||||
|
|
||||||
for(auto const& [id, name] : app.dlcs) {
|
for(auto const& [id, name] : app_dlcs) {
|
||||||
dlcs.emplace_back(id, name);
|
dlcs.emplace_back(id, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
|
|
||||||
// These macros are meant to be used for callbacks that should return original result
|
// These macros are meant to be used for callbacks that should return original result
|
||||||
|
|
||||||
#define HOOKED_CALL(FUNC, ...) \
|
#define SWAPPED_CALL(CLASS, FUNC, ...) \
|
||||||
static const auto _##FUNC = KB_HOOK_GET_HOOKED_FN(FUNC); \
|
const auto _##FUNC = KB_HOOK_GET_SWAPPED_FN(CLASS, FUNC); \
|
||||||
return _##FUNC(__VA_ARGS__)
|
return _##FUNC(__VA_ARGS__)
|
||||||
|
|
||||||
#define HOOKED_CALL_CLOSURE(FUNC, ...) \
|
#define SWAPPED_CALL_CLOSURE(FUNC, ...) \
|
||||||
[&] { HOOKED_CALL(FUNC, __VA_ARGS__); }
|
[&] { SWAPPED_CALL(THIS, FUNC, __VA_ARGS__); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default, virtual functions are declared with __thiscall
|
* By default, virtual functions are declared with __thiscall
|
||||||
@@ -44,23 +44,32 @@ return _##FUNC(__VA_ARGS__)
|
|||||||
* The macros below implement the above-mentioned considerations.
|
* The macros below implement the above-mentioned considerations.
|
||||||
*/
|
*/
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#define PARAMS(...) const void *RCX, __VA_ARGS__
|
#define PARAMS(...) const void* RCX, __VA_ARGS__
|
||||||
#define ARGS(...) RCX, __VA_ARGS__
|
#define ARGS(...) RCX, __VA_ARGS__
|
||||||
#define THIS RCX
|
#define THIS RCX
|
||||||
|
#define DECLARE_EDX()
|
||||||
#else
|
#else
|
||||||
#define PARAMS(...) const void *ECX, const void *EDX, __VA_ARGS__
|
#define PARAMS(...) const void* ECX, const void* EDX, __VA_ARGS__
|
||||||
#define ARGS(...) ECX, EDX, __VA_ARGS__
|
#define ARGS(...) ECX, EDX, __VA_ARGS__
|
||||||
#define THIS ECX
|
#define THIS ECX
|
||||||
|
#define DECLARE_EDX() const void* EDX = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using AppId_t = uint32_t;
|
using AppId_t = uint32_t;
|
||||||
using HSteamPipe = uint32_t;
|
using HSteamPipe = uint32_t;
|
||||||
using EResult = uint32_t;
|
|
||||||
using HSteamUser = uint32_t;
|
using HSteamUser = uint32_t;
|
||||||
using SteamInventoryResult_t = uint32_t;
|
using SteamInventoryResult_t = uint32_t;
|
||||||
using SteamItemInstanceID_t = uint64_t;
|
using SteamItemInstanceID_t = uint64_t;
|
||||||
using SteamItemDef_t = uint32_t;
|
using SteamItemDef_t = uint32_t;
|
||||||
using CSteamID = uint64_t;
|
using CSteamID = uint64_t;
|
||||||
|
using HTTPRequestHandle = uint32_t;
|
||||||
|
|
||||||
|
enum class EResult {
|
||||||
|
k_EResultNone = 0,
|
||||||
|
k_EResultOK = 1,
|
||||||
|
k_EResultFail = 2,
|
||||||
|
// See all at steamclientpublic.h
|
||||||
|
};
|
||||||
|
|
||||||
struct SteamItemDetails_t {
|
struct SteamItemDetails_t {
|
||||||
SteamItemInstanceID_t m_itemId;
|
SteamItemInstanceID_t m_itemId;
|
||||||
@@ -71,10 +80,12 @@ struct SteamItemDetails_t {
|
|||||||
|
|
||||||
// results from UserHasLicenseForApp
|
// results from UserHasLicenseForApp
|
||||||
enum EUserHasLicenseForAppResult {
|
enum EUserHasLicenseForAppResult {
|
||||||
k_EUserHasLicenseResultHasLicense = 0, // User has a license for specified app
|
// User has a license for specified app
|
||||||
k_EUserHasLicenseResultDoesNotHaveLicense = 1,
|
k_EUserHasLicenseResultHasLicense = 0,
|
||||||
// User does not have a license for the specified app
|
// User does not have a license for the specified app
|
||||||
k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated
|
k_EUserHasLicenseResultDoesNotHaveLicense = 1,
|
||||||
|
// User has not been authenticated
|
||||||
|
k_EUserHasLicenseResultNoAuth = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
// These aliases exist solely to increase code readability
|
// These aliases exist solely to increase code readability
|
||||||
@@ -87,7 +98,7 @@ using DlcNameMap = std::map<DlcIdKey, DlcNameValue>;
|
|||||||
struct App {
|
struct App {
|
||||||
DlcNameMap dlcs;
|
DlcNameMap dlcs;
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(App, dlcs) // NOLINT(misc-const-correctness)
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(App, dlcs)
|
||||||
};
|
};
|
||||||
|
|
||||||
using AppDlcNameMap = std::map<AppIdKey, App>;
|
using AppDlcNameMap = std::map<AppIdKey, App>;
|
||||||
@@ -98,6 +109,8 @@ class DLC {
|
|||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(DLC, appid, name)
|
||||||
|
|
||||||
explicit DLC() = default;
|
explicit DLC() = default;
|
||||||
|
|
||||||
explicit DLC(std::string appid, std::string name) : appid{std::move(appid)},
|
explicit DLC(std::string appid, std::string name) : appid{std::move(appid)},
|
||||||
@@ -115,8 +128,6 @@ public:
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(DLC, appid, name)
|
|
||||||
|
|
||||||
static std::vector<DLC> get_dlcs_from_apps(const AppDlcNameMap& apps, AppId_t app_id);
|
static std::vector<DLC> get_dlcs_from_apps(const AppDlcNameMap& apps, AppId_t app_id);
|
||||||
|
|
||||||
static DlcNameMap get_dlc_map_from_vector(const std::vector<DLC>& dlcs);
|
static DlcNameMap get_dlc_map_from_vector(const std::vector<DLC>& dlcs);
|
||||||
|
|||||||
Reference in New Issue
Block a user