= SmokeAPI

_Legit DLC Unlocker for Steamworks_

== ✨ Features

* 🔓 Legit DLC Unlocking
* 🛅 Inventory emulation
* 📝 Config-less operation
* 2️⃣ installation methods:
** 🪝 Hook mode
** 🔀 Proxy mode

== 🔗 Links

:forum-topic: https://cs.rin.ru/forum/viewtopic.php?p=2597932#p2597932[SmokeAPI forum topic]

* 📥 https://github.com/acidicoala/SmokeAPI/releases/latest[Download the latest release]

* 💬 {forum-topic}

== 📖 Introduction

=== What is SmokeAPI?

SmokeAPI is a DLC unlocker for the games that are legitimately owned in your Steam account.
It attempts to fool games that use Steamworks SDK into believing that you own desired DLCs.
However, SmokeAPI does not modify the rest of the Steamworks SDK, hence features like multiplayer, achievements, etc. remain fully functional.

IMPORTANT: DLC unlocking is possible only in games that specifically use Steamworks SDK for ownership verification.
But games may implement additional ownership checks, which may require custom solutions.
If the check is server-side, as is the case in online-only games, then SmokeAPI cannot help in any way.
Finally, even if you unlock the DLCs, games might still require additional DLC files, which would have to be downloaded from somewhere else.
Check corresponding game topic in the forum for possible download links.

.Supported versions
[%collapsible]
====
SmokeAPI aims to support all released SteamAPI versions.
When it encountered a new, unsupported interface version, it will fall back on the latest supported version.
Below is a list of supported interface versions:

* ISteamClient v6 — v21. (Versions before 6 did not contain any DLC related interfaces)
* ISteamApps v2 — v8. (Version 1 did not contain any DLC related functions)
* ISteamUser v12 — v23. (Versions before 12 did not contain any DLC related functions)
* ISteamInventory v1 — v3.

Steam inventory does not work in all games with steam inventory because of custom implementation, and online checks.

====

== 🛠 Installation Instructions

WARNING: Please proceed with installation at your own risk.
Usage of this unlocker entails breaking one or more terms of service, which might result in a permanent ban/deactivation of your account.

:koaloader: https://github.com/acidicoala/Koaloader[Koaloader]
:smokeapi_release: https://github.com/acidicoala/SmokeAPI/releases/latest[SmokeAPI Releases]

SmokeAPI is loaded into a game process, which limits it to that particular game only.
SmokeAPI supports 2 installation modes: hook mode and proxy mode.

|===
|Mode |Advantages |Disadvantages

|🪝 Hook mode
|Persists after game updates; Can be loaded by other injectors.
|Might need an additional DLL (Koaloader)

|🔀 Proxy mode
|Guaranteed to load
|Might need reinstallation if Steam updates affected DLL files

|===

Try installing the unlocker in hook mode first.
If it doesn't work, try installing it in proxy mode.

=== 🪝 Hook mode

. Download the latest SmokeAPI release zip from {smokeapi_release}.
. 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 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.
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].
. 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}.
. 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

. 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}.
. 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}.

== ⚙ Configuration

NOTE: This document describes configuration for version 4 of SmokeAPI.
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.]

SmokeAPI does not require any manual configuration.
By default, it uses the most reasonable options and tries to unlock all DLCs that it can.
However, there might be circumstances in which you need more custom-tailored behaviour, such as disabling certain DLCs, or selectively enabling just a few of them.
In this case you can use a configuration file link:res/SmokeAPI.config.json[SmokeAPI.config.json] that you can find here in this repository or in the release zip.
To use it, simply place it next to the SmokeAPI DLL.
It will be read upon each launch of the game.
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.
All options within the config file are optional.

`logging`:: Toggles generation of a `SmokeAPI.log.log` file.
+
[horizontal]
Type::: Boolean
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.
+
[horizontal]
Possible values:::
+
[horizontal]
`original`:::: Leaves DLC unlock status unmodified, unless specified otherwise.
`unlocked`:::: Unlocks all DLCs in all games, unless specified otherwise.
Type::: String
Default::: `unlocked`

`override_app_status`:: This option overrides the status of all DLCs that belong to a specified app ID{fn-app-id}.
+
[horizontal]
Possible values::: An object with key-value pairs, where the key corresponds to the app ID, and value to the app status.
Possible app status values are defined in the `default_app_status` option.
Type::: Object
Default::: `{}`

`override_dlc_status`:: This option overrides the status of individual DLCs, regardless of the corresponding app status.
+
[horizontal]
Possible values::: An object with key-value pairs, where the key corresponds to the app ID, and value to the app status.
Possible app status values are defined in the `default_app_status` option.
Furthermore, it is possible to lock even the legitimately locked DLCs by setting the corresponding app status value to `locked`.
Type::: Object
Default::: `{}`

`auto_inject_inventory`:: Toggles whether SmokeAPI should automatically inject a list of all registered inventory items, when a game queries user inventory
+
[horizontal]
Type::: Boolean
Default::: `true`

`extra_inventory_items`:: A list of inventory items IDs{fn-app-id} that will be added in addition to the automatically injected items.
+
[horizontal]
Type::: Array (of Integers)
Default::: `[]`

=== Advanced options

`$version`:: A technical field reserved for use by tools like GUI config editors.
Do not modify this value.
+
[horizontal]
Type::: Integer
Default::: `3`

`extra_dlcs`:: See <<How SmokeAPI works in games with large number of DLCs>> to understand the use case for this option.
+
[horizontal]
Possible values::: An object with key-value pairs, where the key corresponds to the app ID, and value to the object that contains DLC IDs.
The format is the same as in the aforementioned GitHub config.
Type::: Object
Default::: `{}`

.Complete example
[%collapsible]
====
[source,json]
----
{
  "$version": 4,
  "logging": true,
  "log_steam_http": true,
  "default_app_status": "unlocked",
  "override_app_status": {
    "1234": "original",
    "4321": "unlocked"
  },
  "override_dlc_status": {
    "1234": "original",
    "4321": "unlocked",
    "5678": "locked"
  },
  "auto_inject_inventory": true,
  "extra_inventory_items": [],
  "extra_dlcs": {
    "1234": {
      "dlcs": {
        "56789": "Example DLC 1"
      }
    },
    "4321": {
      "dlcs": {
        "98765": "Example DLC 2",
        "98766": "Example DLC 3"
      }
    }
  }
}
----
====

== Extra info

=== How SmokeAPI works in games with large number of DLCs

Some games that have a large number of DLCs begin ownership verification by querying the Steamworks API for a list of all available DLCs.
Once the game receives the list, it will go over each item and check the ownership.
The issue arises from the fact that response from Steamworks SDK may max out at 64, depending on how much unowned DLCs the user has.
To alleviate this issue, SmokeAPI will make a web request to Steam API for a full list of DLCs, which works well most of the time.
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.
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.
However, this introduces the need for manual configuration, which goes against the ideals of this project.
To remedy this issue SmokeAPI will also fetch a https://github.com/acidicoala/public-entitlements/blob/main/steam/v2/dlc.json[manually maintained list of extra DLCs] stored in a GitHub repository.
The purpose of this document is to contain all the DLC IDs that are lacking a Steam store page.
This enables SmokeAPI to unlock all DLCs without any config file at all.
Feel free to report in the {forum-topic} games that have more than 64 DLCs,
_and_ have DLCs without a dedicated store page.
They will be added to the list of missing DLC IDs to facilitate config-less operation.

== 🏗️ Building from source

=== 🚦 Requirements

:vs-bt-2022: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022[Visual Studio Build Tools 2022]

* CMake v3.24 (Make sure that cmake is available from powershell)
* {vs-bt-2022} with `Desktop Development for C++` workload installed
** Tested on Windows 11 SDK (10.0.26100.4188)

=== 👨‍💻 Commands

Build the project

----
.\build.ps1 <arch> <config>
----

where

[horizontal]
arch::: `32` or `64`
config::: `Debug` or `Release`

For example:

----
.\build.ps1 64 Release
----

== 🐞 Known issues

* Crashes on startup in Project Winter in hook mode (proxy mode works fine).

== 📚 Open-Source libraries

* https://github.com/batterycenter/embed[batterycenter/embed]
* https://github.com/bshoshany/thread-pool[bshoshany/thread-pool]
* + https://github.com/acidicoala/Koalabox?tab=readme-ov-file#-open-source-libraries[libraries used by KoalaBox]

== 📄 License

This software is licensed under the https://unlicense.org/[Unlicense], terms of which are available in link:UNLICENSE.txt[UNLICENSE.txt]
