mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2025-12-05 21:15:39 -05:00
Improved koalageddon config init
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -14,6 +14,6 @@ jobs:
|
||||
zip_command: >
|
||||
zip -j $ZIP_NAME
|
||||
artifacts/*/*.dll
|
||||
res/SmokeAPI.json
|
||||
res/SmokeAPI.config.json
|
||||
|
||||
config: Release
|
||||
|
||||
@@ -77,10 +77,10 @@ set(
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(
|
||||
SMOKE_API_SOURCES ${SMOKE_API_SOURCES}
|
||||
src/koalageddon/kg_cache.hpp
|
||||
src/koalageddon/kg_cache.cpp
|
||||
src/koalageddon/koalageddon.hpp
|
||||
src/koalageddon/kg_cache.hpp
|
||||
src/koalageddon/koalageddon.cpp
|
||||
src/koalageddon/koalageddon.hpp
|
||||
src/koalageddon/vstdlib.cpp
|
||||
src/koalageddon/vstdlib.hpp
|
||||
src/koalageddon/steamclient/client_app_manager.cpp
|
||||
|
||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: 17c39229db...41649fd55c
@@ -68,12 +68,12 @@ If the unlocker is not working as expected, then please fully read the [Generic
|
||||
|
||||
## ⚙ Configuration
|
||||
|
||||
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. In this case you can use a configuration file [SmokeAPI.json] that you can find here in this repository. To use it, simply place it next to the SmokeAPI DLL. It will be read upon each launch of a game. In the absence of the config file, default value specified below will be used.
|
||||
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 [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. In the absence of the config file, default value specified below will be used.
|
||||
|
||||
| Option | Description | Type | Default |
|
||||
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|:-------:|
|
||||
| `$version` | A technical field reserved for future use by tools like GUI config editors | Integer | `1` |
|
||||
| `logging` | Toggles generation of `*.log` file | Boolean | `false` |
|
||||
| `$version` | A technical field reserved for use by tools like GUI config editors. Do not modify this value. | Integer | `2` |
|
||||
| `logging` | Toggles generation of `SmokeAPI.log.log` file | Boolean | `false` |
|
||||
| `unlock_all` | Toggles whether all DLCs should be unlocked by default | Boolean | `true` |
|
||||
| `override` | When `unlock_all` is `true`, this option serves as a blacklist of DLC IDs, which should remain locked. When `unlock_all` is `false`, this option serves as a whitelist of DLC IDs, which should become unlocked | List of Integers | `[]` |
|
||||
| `extra_dlcs` | When a game requests number of all DLCs from Steam and gets a response that is equal to or greater than 64, it means that we need to get extra DLCs because Steam returns maximum 64 values this way. In this case, SmokeAPI will fetch extra DLCs from several online source, such as Steam API and a [manually maintained list of DLC IDs] from GitHub. However, in some cases these sources doesn't return all possible DLCs. To address this issue, you can specify the missing DLC IDs¹ in this option. | Object | `{}` |
|
||||
@@ -83,7 +83,7 @@ SmokeAPI does not require any manual configuration. By default, it uses the most
|
||||
|
||||
¹ DLC/Item IDs can be obtained from https://steamdb.info. You need to be logged in with your steam account in order to see accurate inventory item IDs.
|
||||
|
||||
[SmokeAPI.json]: res/SmokeAPI.config.json
|
||||
[SmokeAPI.config.json]: res/SmokeAPI.config.json
|
||||
|
||||
[manually maintained list of DLC IDs]: https://github.com/acidicoala/public-entitlements/blob/main/steam/v1/dlc.json
|
||||
|
||||
|
||||
@@ -30,8 +30,6 @@ namespace api {
|
||||
const auto url = fmt::format("https://store.steampowered.com/dlc/{}/ajaxgetdlclist", app_id);
|
||||
const auto json = koalabox::http_client::fetch_json(url);
|
||||
|
||||
LOG_TRACE("Steam response: \n{}", json.dump(2))
|
||||
|
||||
const auto response = json.get<SteamResponse>();
|
||||
|
||||
if (response.success != 1) {
|
||||
@@ -45,4 +43,17 @@ namespace api {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<koalageddon::KoalageddonConfig> fetch_koalageddon_config() noexcept {
|
||||
try {
|
||||
const String url =
|
||||
"https://raw.githubusercontent.com/acidicoala/public-entitlements/main/koalageddon/v2/steam.json";
|
||||
const auto kg_config_json = koalabox::http_client::fetch_json(url);
|
||||
|
||||
return kg_config_json.get<koalageddon::KoalageddonConfig>();
|
||||
} catch (const Exception& e) {
|
||||
LOG_ERROR("Failed to fetch Koalageddon config from GitHub: {}", e.what())
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/types.hpp>
|
||||
#include <koalageddon/koalageddon.hpp>
|
||||
|
||||
namespace api {
|
||||
|
||||
@@ -8,4 +8,6 @@ namespace api {
|
||||
|
||||
std::optional<Vector<DLC>> fetch_dlcs_from_steam(AppId_t app_id) noexcept;
|
||||
|
||||
std::optional<koalageddon::KoalageddonConfig> fetch_koalageddon_config() noexcept;
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace koalageddon::kg_cache {
|
||||
|
||||
std::optional<KoalageddonConfig> get_koalageddon_config() {
|
||||
try {
|
||||
const auto cache = koalabox::cache::read_from_cache(KEY_KG_CONFIG);
|
||||
const auto config_json = koalabox::cache::read_from_cache(KEY_KG_CONFIG);
|
||||
|
||||
return cache[KEY_KG_CONFIG].get<KoalageddonConfig>();
|
||||
return config_json.get<KoalageddonConfig>();
|
||||
} catch (const Exception& e) {
|
||||
LOG_ERROR("Failed to get cached koalageddon config: {}", e.what())
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
#include <build_config.h>
|
||||
#include <smoke_api/config.hpp>
|
||||
#include <steam_api_exports/steam_api_exports.hpp>
|
||||
#include <core/api.hpp>
|
||||
#include <koalabox/dll_monitor.hpp>
|
||||
#include <koalabox/http_client.hpp>
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/win_util.hpp>
|
||||
|
||||
namespace koalageddon {
|
||||
|
||||
@@ -15,54 +16,76 @@ namespace koalageddon {
|
||||
/**
|
||||
* @return A string representing the source of the config.
|
||||
*/
|
||||
String init_koalageddon_config() {
|
||||
if (!smoke_api::config::instance.koalageddon_config.is_null()) {
|
||||
try {
|
||||
// First try to read a local config override
|
||||
config = smoke_api::config::instance.koalageddon_config.get<decltype(config)>();
|
||||
void init_koalageddon_config() {
|
||||
const auto print_source = [](const String& source) {
|
||||
LOG_INFO("Loaded Koalageddon config from the {}", source)
|
||||
};
|
||||
|
||||
return "local config override";
|
||||
// First try to read a local config override
|
||||
const auto& kg_config = smoke_api::config::instance.koalageddon_config;
|
||||
if (!kg_config.is_null()) {
|
||||
try {
|
||||
config = kg_config.get<decltype(config)>();
|
||||
|
||||
print_source("local config override");
|
||||
return;
|
||||
} catch (const Exception& ex) {
|
||||
LOG_ERROR("Failed to get local koalageddon config: {}", ex.what())
|
||||
}
|
||||
}
|
||||
|
||||
// Then try to get a cached copy of a previously fetched config.
|
||||
try {
|
||||
// Then try to fetch config from GitHub
|
||||
const String url = "https://raw.githubusercontent.com/acidicoala/public-entitlements/main/koalageddon/v2/steam.json";
|
||||
config = koalabox::http_client::fetch_json(url).get<decltype(config)>();
|
||||
config = kg_cache::get_koalageddon_config().value();
|
||||
|
||||
kg_cache::save_koalageddon_config(config);
|
||||
print_source("disk cache");
|
||||
} catch (const Exception& ex) {
|
||||
LOG_ERROR("Failed to get cached koalageddon config: {}", ex.what())
|
||||
|
||||
return "GitHub repository";
|
||||
print_source("default config bundled in the binary");
|
||||
|
||||
// Fallback on the default config, to continue execution immediately.
|
||||
config = {};
|
||||
}
|
||||
|
||||
// Finally, fetch the remote config from GitHub, and inform user about the need to restart Steam,
|
||||
// if a new config has been fetched
|
||||
NEW_THREAD({
|
||||
try {
|
||||
const auto github_config_opt = api::fetch_koalageddon_config();
|
||||
if (!github_config_opt) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto github_config = *github_config_opt;
|
||||
|
||||
kg_cache::save_koalageddon_config(github_config);
|
||||
|
||||
if (github_config == config) {
|
||||
LOG_DEBUG("Fetched Koalageddon config is equal to existing config")
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Fetched a new Koalageddon config")
|
||||
|
||||
::MessageBox(
|
||||
nullptr,
|
||||
TEXT(
|
||||
"SmokeAPI has downloaded an updated config for Koalageddon mode. "
|
||||
"Please restart Steam in order to apply the new Koalageddon config. "
|
||||
),
|
||||
TEXT("SmokeAPI - Koalageddon"),
|
||||
MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK
|
||||
);
|
||||
} catch (const Exception& ex) {
|
||||
LOG_ERROR("Failed to get remote koalageddon config: {}", ex.what())
|
||||
}
|
||||
|
||||
try {
|
||||
// Then try to get a cached copy of a previously fetched config.
|
||||
// We expect this unboxing to throw exception if no koalageddon config is present.
|
||||
config = kg_cache::get_koalageddon_config().value();
|
||||
|
||||
return "disk cache";
|
||||
} catch (const Exception& ex) {
|
||||
LOG_ERROR("Failed to get cached koalageddon config: {}", ex.what())
|
||||
}
|
||||
|
||||
// Finally, fallback on the default config
|
||||
config = {};
|
||||
return "default config bundled in the binary";
|
||||
})
|
||||
}
|
||||
|
||||
void init() {
|
||||
// TODO: Load cached koalageddon config by default
|
||||
|
||||
std::thread(
|
||||
[]() {
|
||||
const auto kg_config_source = init_koalageddon_config();
|
||||
LOG_INFO("Loaded Koalageddon config from the {}", kg_config_source)
|
||||
}
|
||||
).detach();
|
||||
init_koalageddon_config();
|
||||
|
||||
koalabox::dll_monitor::init_listener(
|
||||
{VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
namespace koalageddon {
|
||||
// Offset values are interpreted according to pointer arithmetic rules, i.e.
|
||||
// 1 unit offset represents 4 and 8 bytes in 32-bit and 64-bit architectures respectively.
|
||||
struct KoalageddonConfig {
|
||||
class KoalageddonConfig {
|
||||
public:
|
||||
uint32_t client_engine_steam_client_internal_ordinal = 12;
|
||||
uint32_t steam_client_internal_interface_selector_ordinal = 18;
|
||||
uint32_t vstdlib_callback_address_offset = 20;
|
||||
@@ -24,6 +25,8 @@ namespace koalageddon {
|
||||
vstdlib_callback_interceptor_address_offset,
|
||||
vstdlib_callback_name_offset
|
||||
)
|
||||
|
||||
bool operator==(const KoalageddonConfig& other) const = default;
|
||||
};
|
||||
|
||||
extern KoalageddonConfig config;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
namespace smoke_api::config {
|
||||
Config instance; // NOLINT(cert-err58-cpp)
|
||||
|
||||
// TODO: Reloading via export
|
||||
void init() {
|
||||
const auto path = paths::get_config_path();
|
||||
|
||||
@@ -15,10 +14,9 @@ namespace smoke_api::config {
|
||||
try {
|
||||
const auto config_str = koalabox::io::read_file(path);
|
||||
|
||||
LOG_DEBUG("Parsing config:\n{}", config_str)
|
||||
|
||||
instance = Json::parse(config_str).get<Config>();
|
||||
|
||||
LOG_DEBUG("Parsed config:\n{}", Json(instance))
|
||||
} catch (const Exception& e) {
|
||||
const auto message = fmt::format("Error parsing config file: {}", e.what());
|
||||
koalabox::util::error_box("SmokeAPI Error", message);
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace smoke_api::config {
|
||||
// We have to use general json type here since the library doesn't support std::optional
|
||||
Json koalageddon_config;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
|
||||
Config, // NOLINT(misc-const-correctness)
|
||||
$version,
|
||||
logging,
|
||||
|
||||
@@ -54,23 +54,24 @@ void init_hook_mode() {
|
||||
// the support for it has been dropped from this project.
|
||||
}
|
||||
|
||||
bool is_valve_steam(const String& exe_name) {
|
||||
bool is_valve_steam(const String& exe_name) noexcept {
|
||||
try {
|
||||
if (exe_name < not_equals > "steam.exe") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that it's steam from valve, and not some other executable coincidentally named steam
|
||||
|
||||
const HMODULE steam_handle = koalabox::win_util::get_module_handle_or_throw(nullptr);
|
||||
const auto manifest = koalabox::win_util::get_module_manifest(steam_handle);
|
||||
|
||||
// Verify that it's steam from valve, and not some other executable coincidentally named steam
|
||||
// Steam.exe manifest is expected to contain this string
|
||||
return manifest < contains > "valvesoftware.steam.steam";
|
||||
} catch (const Exception& e) {
|
||||
LOG_ERROR("{} -> {}", __func__, e.what())
|
||||
|
||||
if (!manifest) {
|
||||
// Steam.exe is expected to have a manifest
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steam.exe manifest is expected to contain this string
|
||||
return *manifest < contains > "valvesoftware.steam.steam";
|
||||
}
|
||||
|
||||
namespace smoke_api {
|
||||
@@ -87,7 +88,8 @@ namespace smoke_api {
|
||||
koalabox::logger::init_file_logger(paths::get_log_path());
|
||||
}
|
||||
|
||||
// FIXME: Dynamic timestamp resolution: https://stackoverflow.com/q/17212518
|
||||
// This kind of timestamp is reliable on 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__)
|
||||
|
||||
koalabox::cache::init_cache(paths::get_cache_path());
|
||||
|
||||
Reference in New Issue
Block a user