mirror of https://github.com/acidicoala/SmokeAPI
Renamed koalageddon mode to store mode
parent
dfbce391a7
commit
4f93515bac
@ -1 +1 @@
|
|||||||
Subproject commit c1e97c8101fe0369985aad85298b1b6b3e3c9ca6
|
Subproject commit 44b0553105af8a7352def9e879f59e1da26bcba6
|
@ -1,12 +0,0 @@
|
|||||||
Copyright (c) 2022 by acidicoala
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
||||||
with or without fee is hereby granted.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
||||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
||||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
||||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
||||||
THIS SOFTWARE.
|
|
@ -0,0 +1,275 @@
|
|||||||
|
= 🐨 SmokeAPI ♨
|
||||||
|
|
||||||
|
_Legit DLC Unlocker for Steamworks_
|
||||||
|
|
||||||
|
image::https://www.gstatic.com/android/keyboard/emojikitchen/20201001/u1f428/u1f428_u2615.png[,256,align="center"]
|
||||||
|
|
||||||
|
== ✨ Features
|
||||||
|
|
||||||
|
* 🔓 Legit DLC Unlocking
|
||||||
|
* 🛅 Inventory emulation
|
||||||
|
* 📝 Config-less operation
|
||||||
|
* Multiple installation methods:
|
||||||
|
** 🛍️ Store mode
|
||||||
|
** 🎮 Game mode
|
||||||
|
*** 🪝 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 spoof 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.
|
||||||
|
|
||||||
|
.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 — v20. (Versions before 6 did not contain any DLC related interfaces)
|
||||||
|
* ISteamApps v2 — v8. (Version 1 did not contain any DLC related functions)
|
||||||
|
* ISteamUser v12 — v21. (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.
|
||||||
|
A list of games where inventory emulation has been shown to work is as follows:
|
||||||
|
|
||||||
|
* Project Winter
|
||||||
|
* Euro Truck Simulator 2
|
||||||
|
* Hero Siege (if you bypass EAC)
|
||||||
|
====
|
||||||
|
|
||||||
|
== 🛠 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 loss of your account.
|
||||||
|
|
||||||
|
:smokeapi_release: https://github.com/acidicoala/SmokeAPI/releases/latest[SmokeAPI Releases]
|
||||||
|
|
||||||
|
SmokeAPI supports 2 main modes of installation: *Store* mode and *Game* mode, which are described in the next section.
|
||||||
|
|
||||||
|
NOTE: It is worth noting that the following instructions describe a _manual_ installation method.
|
||||||
|
You can benefit from _automatic_ installation and GUI configuration from Koalageddon v2 (Coming soon).
|
||||||
|
|
||||||
|
=== 🛍️ Store mode
|
||||||
|
|
||||||
|
In this installation mode, SmokeAPI is loaded into the Steam process, which makes it able to affect all Steam games.
|
||||||
|
|
||||||
|
:steam-dir: the Steam directoryfootnote:fn-steam-dir[The root directory where Steam is installed]
|
||||||
|
|
||||||
|
. Download the latest Koaloader release zip from https://github.com/acidicoala/Koaloader/releases/latest[Koaloader Releases].
|
||||||
|
. From Koaloader archive unpack `version.dll` from `version-32`, and place it in {steam-dir}.
|
||||||
|
. In {steam-dir} create the following Koaloader configuration file:
|
||||||
|
+
|
||||||
|
.`Koaloader.json`
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
[source,json]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"auto_load": false,
|
||||||
|
"targets": [
|
||||||
|
"Steam.exe"
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"path": "SmokeAPI.dll",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
. Download the latest SmokeAPI release zip from {smokeapi_release}.
|
||||||
|
. From SmokeAPI archive unpack `steam_api.dll`, rename it to `SmokeAPI.dll`, and place it in {steam-dir}.
|
||||||
|
|
||||||
|
=== 🎮 Game mode
|
||||||
|
|
||||||
|
In this installation mode, SmokeAPI is loaded into a game process, which makes limits it to that particular game only.
|
||||||
|
This mode itself supports 2 modes: hook mode and proxy mode.
|
||||||
|
Try installing the unlocker in hook mode first.
|
||||||
|
If it doesn't work, try installing it in proxy mode.
|
||||||
|
|
||||||
|
==== 🪝 Hook mode
|
||||||
|
|
||||||
|
. Download the latest Koaloader release zip from https://github.com/acidicoala/Koaloader/releases/latest[Koaloader Releases].
|
||||||
|
. From Koaloader archive unpack `version.dll` from version-32/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 `steam_api.dll`/`steam_api64.dll`, depending on the game bitness, rename it to `SmokeAPI.dll`, and place it next to the game exe file.
|
||||||
|
|
||||||
|
==== 🔀 Proxy mode
|
||||||
|
|
||||||
|
. Find `steam_api.dll`/`steam_api64.dll` file in game directory, and add `_o` to its name, e.g. `steam_api64_o.dll`.
|
||||||
|
. 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.
|
||||||
|
|
||||||
|
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 2 of SmokeAPI.
|
||||||
|
You can find the version 1 documentation https://github.com/acidicoala/SmokeAPI/blob/v1.0.3/README.md#-configuration[here].
|
||||||
|
|
||||||
|
:steam_config: https://github.com/acidicoala/public-entitlements/blob/main/steam/v2/store_config.json
|
||||||
|
:fn-app-id: footnote:fn-app-id[App/DLC IDs can be obtained from https://steamdb.info. 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 a game or the store.
|
||||||
|
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.
|
||||||
|
|
||||||
|
`logging`:: Toggles generation of a `SmokeAPI.log.log` file.
|
||||||
|
+
|
||||||
|
[horizontal]
|
||||||
|
Type::: Boolean
|
||||||
|
Default::: `false`
|
||||||
|
|
||||||
|
`unlock_family_sharing`:: Toggles Family Sharing bypass, which enables the borrower of a shared library to start and continue playing games when library owner is playing as well.
|
||||||
|
+
|
||||||
|
[horizontal]
|
||||||
|
Type::: Boolean
|
||||||
|
Default::: `true`
|
||||||
|
|
||||||
|
`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 (Map of String to String)
|
||||||
|
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::: `2`
|
||||||
|
|
||||||
|
`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 (Map of String to Object)
|
||||||
|
Default::: `{}`
|
||||||
|
|
||||||
|
`store_config`:: An object that specifies offsets required for store mode operation.
|
||||||
|
It will override the config fetched from {steam_config}[remote source] or local cache.
|
||||||
|
Do not modify this value.
|
||||||
|
+
|
||||||
|
[horizontal]
|
||||||
|
Type::: Object (Map of String to Integer)
|
||||||
|
Default::: See {steam_config}[online config]
|
||||||
|
|
||||||
|
== 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 only return 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
|
||||||
|
|
||||||
|
:fn-lower-ver: footnote:lower-versions[Older versions may be supported as well.]
|
||||||
|
|
||||||
|
* CMake v3.24 (Make sure that cmake is available from powershell)
|
||||||
|
* Visual Studio 2022{fn-lower-ver}.
|
||||||
|
* Tested on Windows 11 SDK (10.0.22621.0){fn-lower-ver}.
|
||||||
|
|
||||||
|
=== 👨💻 Commands
|
||||||
|
|
||||||
|
Build the project
|
||||||
|
|
||||||
|
----
|
||||||
|
.\build.ps1 <arch> <config>
|
||||||
|
----
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
arch::: `32` or `64`
|
||||||
|
config::: `Debug` or `Release`
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
----
|
||||||
|
.\build.ps1 32 Debug
|
||||||
|
----
|
||||||
|
|
||||||
|
== 👋 Acknowledgements
|
||||||
|
|
||||||
|
SmokeAPI makes use of the following open source projects:
|
||||||
|
|
||||||
|
- https://github.com/libcpr/cpr[C++ Requests]
|
||||||
|
- https://github.com/nlohmann/json[JSON for Modern C++]
|
||||||
|
- https://github.com/stevemk14ebr/PolyHook_2_0[PolyHook 2]
|
||||||
|
- https://github.com/gabime/spdlog[spdlog]
|
||||||
|
|
||||||
|
== 📄 License
|
||||||
|
|
||||||
|
This software is licensed under the https://unlicense.org/[Unlicense], terms of which are available in link:UNLICENSE.txt[UNLICENSE.txt]
|
@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
@ -1,4 +1,4 @@
|
|||||||
#include <smoke_api/app_cache.hpp>
|
#include <common/app_cache.hpp>
|
||||||
#include <core/paths.hpp>
|
#include <core/paths.hpp>
|
||||||
#include <koalabox/cache.hpp>
|
#include <koalabox/cache.hpp>
|
||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <common/steamclient_exports.hpp>
|
||||||
#include <steam_impl/steam_client.hpp>
|
#include <steam_impl/steam_client.hpp>
|
||||||
|
|
||||||
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) {
|
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) {
|
@ -0,0 +1,3 @@
|
|||||||
|
#include <core/types.hpp>
|
||||||
|
|
||||||
|
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result);
|
@ -1,4 +1,3 @@
|
|||||||
#include <steam_api_exports/steam_api_exports.hpp>
|
|
||||||
#include <steam_impl/steam_client.hpp>
|
#include <steam_impl/steam_client.hpp>
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) {
|
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) {
|
@ -1,4 +1,3 @@
|
|||||||
#include <steam_api_exports/steam_api_exports.hpp>
|
|
||||||
#include <steam_impl/steam_client.hpp>
|
#include <steam_impl/steam_client.hpp>
|
||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
#include <koalabox/win_util.hpp>
|
#include <koalabox/win_util.hpp>
|
@ -1,4 +1,4 @@
|
|||||||
#include <steam_api_virtuals/steam_api_virtuals.hpp>
|
#include <game_mode/virtuals/steam_api_virtuals.hpp>
|
||||||
#include <steam_impl/steam_apps.hpp>
|
#include <steam_impl/steam_apps.hpp>
|
||||||
|
|
||||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) {
|
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) {
|
@ -1,4 +1,4 @@
|
|||||||
#include <steam_api_virtuals/steam_api_virtuals.hpp>
|
#include <game_mode/virtuals/steam_api_virtuals.hpp>
|
||||||
#include <steam_impl/steam_client.hpp>
|
#include <steam_impl/steam_client.hpp>
|
||||||
|
|
||||||
VIRTUAL(void*) ISteamClient_GetISteamApps(
|
VIRTUAL(void*) ISteamClient_GetISteamApps(
|
@ -1,4 +1,4 @@
|
|||||||
#include <steam_api_virtuals/steam_api_virtuals.hpp>
|
#include <game_mode/virtuals/steam_api_virtuals.hpp>
|
||||||
#include <steam_impl/steam_inventory.hpp>
|
#include <steam_impl/steam_inventory.hpp>
|
||||||
|
|
||||||
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
|
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
|
@ -1,10 +1,18 @@
|
|||||||
#include <steam_api_virtuals/steam_api_virtuals.hpp>
|
#include <game_mode/virtuals/steam_api_virtuals.hpp>
|
||||||
#include <steam_impl/steam_user.hpp>
|
#include <steam_impl/steam_user.hpp>
|
||||||
#include <steam_impl/steam_impl.hpp>
|
#include <steam_impl/steam_impl.hpp>
|
||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
|
||||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID steamID, AppId_t dlcID)) {
|
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID steamID, AppId_t dlcID)) {
|
||||||
|
AppId_t app_id = 0;
|
||||||
|
try {
|
||||||
|
app_id = steam_impl::get_app_id_or_throw();
|
||||||
|
} catch (const Exception& e) {
|
||||||
|
LOG_ERROR("{} -> Error getting app id: {}", __func__, e.what())
|
||||||
|
}
|
||||||
|
|
||||||
return steam_user::UserHasLicenseForApp(
|
return steam_user::UserHasLicenseForApp(
|
||||||
__func__, steam_impl::get_app_id_or_throw(), dlcID, [&]() {
|
__func__, app_id, dlcID, [&]() {
|
||||||
GET_ORIGINAL_HOOKED_FUNCTION(ISteamUser_UserHasLicenseForApp)
|
GET_ORIGINAL_HOOKED_FUNCTION(ISteamUser_UserHasLicenseForApp)
|
||||||
|
|
||||||
return ISteamUser_UserHasLicenseForApp_o(ARGS(steamID, dlcID));
|
return ISteamUser_UserHasLicenseForApp_o(ARGS(steamID, dlcID));
|
@ -1,33 +0,0 @@
|
|||||||
#include <koalageddon/kg_cache.hpp>
|
|
||||||
#include <koalabox/cache.hpp>
|
|
||||||
#include <koalabox/logger.hpp>
|
|
||||||
|
|
||||||
constexpr auto KEY_KG_CONFIG = "koalageddon_config";
|
|
||||||
|
|
||||||
namespace koalageddon::kg_cache {
|
|
||||||
|
|
||||||
std::optional<KoalageddonConfig> get_koalageddon_config() {
|
|
||||||
try {
|
|
||||||
const auto config_json = koalabox::cache::read_from_cache(KEY_KG_CONFIG);
|
|
||||||
|
|
||||||
return config_json.get<KoalageddonConfig>();
|
|
||||||
} catch (const Exception& e) {
|
|
||||||
LOG_ERROR("Failed to get cached koalageddon config: {}", e.what())
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool save_koalageddon_config(const KoalageddonConfig& config) {
|
|
||||||
try {
|
|
||||||
LOG_DEBUG("Caching koalageddon config")
|
|
||||||
|
|
||||||
return koalabox::cache::save_to_cache(KEY_KG_CONFIG, Json(config));
|
|
||||||
} catch (const Exception& e) {
|
|
||||||
LOG_ERROR("Failed to cache koalageddon config: {}", e.what())
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <koalageddon/koalageddon.hpp>
|
|
||||||
|
|
||||||
namespace koalageddon::kg_cache {
|
|
||||||
|
|
||||||
std::optional<KoalageddonConfig> get_koalageddon_config();
|
|
||||||
|
|
||||||
bool save_koalageddon_config(const KoalageddonConfig& config);
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#include <koalageddon/koalageddon.hpp>
|
|
||||||
|
|
||||||
namespace koalageddon::vstdlib {
|
|
||||||
|
|
||||||
struct CallbackData {
|
|
||||||
uintptr_t get_callback_intercept_address() {
|
|
||||||
return reinterpret_cast<uintptr_t*>(this)[koalageddon::config.vstdlib_callback_interceptor_address_offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t get_callback_address() {
|
|
||||||
return reinterpret_cast<uintptr_t*>(this)[koalageddon::config.vstdlib_callback_address_offset];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CoroutineData {
|
|
||||||
CallbackData* get_callback_data() {
|
|
||||||
return reinterpret_cast<CallbackData**>(this)[koalageddon::config.vstdlib_callback_data_offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* get_callback_name() {
|
|
||||||
return reinterpret_cast<const char**>(this)[koalageddon::config.vstdlib_callback_name_offset];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef uint32_t HCoroutine;
|
|
||||||
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <core/types.hpp>
|
|
||||||
|
|
||||||
// Flat
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void*, AppId_t);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(void*, AppId_t);
|
|
||||||
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(void*);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(void*, int, AppId_t*, bool*, char*, int);
|
|
||||||
|
|
||||||
DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(void*, HSteamUser, HSteamPipe, const char*);
|
|
||||||
|
|
||||||
DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(void*, SteamInventoryResult_t);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(void*, SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
|
|
||||||
void*, SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*
|
|
||||||
);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(void*, SteamInventoryResult_t, CSteamID);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(void*, SteamInventoryResult_t*);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
|
|
||||||
void*, SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t
|
|
||||||
);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(void*, SteamInventoryResult_t, void*, uint32_t*);
|
|
||||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(void*, SteamItemDef_t*, uint32_t*);
|
|
||||||
|
|
||||||
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp(void*, CSteamID, AppId_t);
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser, const char*);
|
|
||||||
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char*);
|
|
||||||
|
|
||||||
// Unversioned
|
|
||||||
DLL_EXPORT(void*) CreateInterface(const char*, int*);
|
|
||||||
DLL_EXPORT(void*) SteamApps();
|
|
||||||
DLL_EXPORT(void*) SteamClient();
|
|
||||||
DLL_EXPORT(void*) SteamUser();
|
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <store_mode/steamclient/steamclient.hpp>
|
||||||
#include <steam_impl/steam_apps.hpp>
|
#include <steam_impl/steam_apps.hpp>
|
||||||
|
|
||||||
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) {
|
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) {
|
@ -1,4 +1,4 @@
|
|||||||
#include <koalageddon/steamclient/steamclient.hpp>
|
#include <store_mode/steamclient/steamclient.hpp>
|
||||||
#include <steam_impl/steam_inventory.hpp>
|
#include <steam_impl/steam_inventory.hpp>
|
||||||
|
|
||||||
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
|
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
|
@ -1,8 +1,8 @@
|
|||||||
#include <koalageddon/steamclient/steamclient.hpp>
|
#include <store_mode/steamclient/steamclient.hpp>
|
||||||
#include <steam_impl/steam_apps.hpp>
|
#include <steam_impl/steam_apps.hpp>
|
||||||
|
|
||||||
VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t dlc_id)) {
|
VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t dlc_id)) {
|
||||||
const auto* utils_interface = koalageddon::steamclient::interface_name_to_address_map["IClientUtils"];
|
const auto* utils_interface = store::steamclient::interface_name_to_address_map["IClientUtils"];
|
||||||
|
|
||||||
const auto app_id = utils_interface ? IClientUtils_GetAppID(utils_interface, EDX) : 0;
|
const auto app_id = utils_interface ? IClientUtils_GetAppID(utils_interface, EDX) : 0;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
#include <koalageddon/steamclient/steamclient.hpp>
|
#include <store_mode/steamclient/steamclient.hpp>
|
||||||
|
|
||||||
VIRTUAL(AppId_t) IClientUtils_GetAppID(PARAMS()) {
|
VIRTUAL(AppId_t) IClientUtils_GetAppID(PARAMS()) {
|
||||||
GET_ORIGINAL_HOOKED_FUNCTION(IClientUtils_GetAppID)
|
GET_ORIGINAL_HOOKED_FUNCTION(IClientUtils_GetAppID)
|
@ -0,0 +1,19 @@
|
|||||||
|
#include <store_mode/store_api.hpp>
|
||||||
|
#include <koalabox/http_client.hpp>
|
||||||
|
|
||||||
|
namespace store::api {
|
||||||
|
|
||||||
|
std::optional<StoreConfig> fetch_store_config() noexcept {
|
||||||
|
try {
|
||||||
|
const String url =
|
||||||
|
"https://raw.githubusercontent.com/acidicoala/public-entitlements/main/steam/v2/store_config.json";
|
||||||
|
const auto kg_config_json = koalabox::http_client::fetch_json(url);
|
||||||
|
|
||||||
|
return kg_config_json.get<StoreConfig>();
|
||||||
|
} catch (const Exception& e) {
|
||||||
|
LOG_ERROR("Failed to fetch Store config from GitHub: {}", e.what())
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <core/types.hpp>
|
||||||
|
#include <store_mode/store.hpp>
|
||||||
|
|
||||||
|
namespace store::api {
|
||||||
|
|
||||||
|
std::optional<store::StoreConfig> fetch_store_config() noexcept;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
#include <store_mode/store_cache.hpp>
|
||||||
|
#include <koalabox/cache.hpp>
|
||||||
|
|
||||||
|
constexpr auto KEY_KG_CONFIG = "store_config";
|
||||||
|
|
||||||
|
namespace store::store_cache {
|
||||||
|
|
||||||
|
std::optional<StoreConfig> get_store_config() {
|
||||||
|
try {
|
||||||
|
const auto config_json = koalabox::cache::read_from_cache(KEY_KG_CONFIG);
|
||||||
|
|
||||||
|
return config_json.get<StoreConfig>();
|
||||||
|
} catch (const Exception& e) {
|
||||||
|
LOG_ERROR("Failed to get cached store_mode config: {}", e.what())
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool save_store_config(const StoreConfig& config) {
|
||||||
|
try {
|
||||||
|
LOG_DEBUG("Caching store_mode config")
|
||||||
|
|
||||||
|
return koalabox::cache::save_to_cache(KEY_KG_CONFIG, Json(config));
|
||||||
|
} catch (const Exception& e) {
|
||||||
|
LOG_ERROR("Failed to cache store_mode config: {}", e.what())
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <store_mode/store.hpp>
|
||||||
|
|
||||||
|
namespace store::store_cache {
|
||||||
|
|
||||||
|
std::optional<StoreConfig> get_store_config();
|
||||||
|
|
||||||
|
bool save_store_config(const StoreConfig& config);
|
||||||
|
|
||||||
|
}
|
@ -1,47 +1,32 @@
|
|||||||
#include <koalageddon/vstdlib.hpp>
|
#include <store_mode/vstdlib/vstdlib.hpp>
|
||||||
#include <koalabox/hook.hpp>
|
|
||||||
#include <koalabox/logger.hpp>
|
|
||||||
|
|
||||||
using namespace koalageddon;
|
namespace store::vstdlib {
|
||||||
|
VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) {
|
||||||
namespace koalageddon::vstdlib {
|
|
||||||
using namespace koalabox;
|
|
||||||
|
|
||||||
VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)
|
|
||||||
) {
|
|
||||||
LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg)
|
LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg)
|
||||||
ARGS();
|
ARGS();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)
|
VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) {
|
||||||
) {
|
|
||||||
LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg)
|
LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg)
|
||||||
ARGS();
|
ARGS();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** name_ptr)
|
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** name_ptr)) {
|
||||||
) {
|
|
||||||
GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor)
|
GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor)
|
||||||
VStdLib_Callback_Interceptor_o(ARGS(name_ptr));
|
VStdLib_Callback_Interceptor_o(ARGS(name_ptr));
|
||||||
|
|
||||||
static auto lock_status_hooked = false;
|
static auto lock_status_hooked = false;
|
||||||
static auto stop_playing_hooked = false;
|
static auto stop_playing_hooked = false;
|
||||||
|
|
||||||
if (
|
if (lock_status_hooked && stop_playing_hooked) {
|
||||||
lock_status_hooked && stop_playing_hooked
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* const data = (CoroutineData*) THIS;
|
auto* const data = (CoroutineData*) THIS;
|
||||||
|
|
||||||
if (
|
if (data && data->get_callback_name()) {
|
||||||
data && data
|
|
||||||
->
|
|
||||||
get_callback_name()
|
|
||||||
) {
|
|
||||||
const auto name = String(data->get_callback_name());
|
const auto name = String(data->get_callback_name());
|
||||||
LOG_TRACE("{}(ecx={}, edx={}, name='{}')", __func__, ARGS(), name)
|
LOG_TRACE("{}(ecx={}, edx={}, name='{}')", __func__, ARGS(), name)
|
||||||
if (name == "SharedLicensesLockStatus" && !lock_status_hooked) {
|
if (name == "SharedLicensesLockStatus" && !lock_status_hooked) {
|
@ -0,0 +1,27 @@
|
|||||||
|
#include <store_mode/store.hpp>
|
||||||
|
|
||||||
|
namespace store::vstdlib {
|
||||||
|
|
||||||
|
struct CallbackData {
|
||||||
|
uintptr_t get_callback_intercept_address() {
|
||||||
|
return reinterpret_cast<uintptr_t*>(this)[store::config.vstdlib_callback_interceptor_address_offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t get_callback_address() {
|
||||||
|
return reinterpret_cast<uintptr_t*>(this)[store::config.vstdlib_callback_address_offset];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CoroutineData {
|
||||||
|
CallbackData* get_callback_data() {
|
||||||
|
return reinterpret_cast<CallbackData**>(this)[store::config.vstdlib_callback_data_offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_callback_name() {
|
||||||
|
return reinterpret_cast<const char**>(this)[store::config.vstdlib_callback_name_offset];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint32_t HCoroutine;
|
||||||
|
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data);
|
||||||
|
}
|
Loading…
Reference in New Issue