mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2025-12-05 21:15:39 -05:00
Reworked tools
This commit is contained in:
@@ -13,4 +13,10 @@ UseTab: Never
|
|||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
SortIncludes: true
|
SortIncludes: true
|
||||||
AllowShortFunctionsOnASingleLine: Empty
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
FixNamespaceComments: false
|
FixNamespaceComments: false
|
||||||
|
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
BinPackParameters: OnePerLine
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
BinPackArguments: false
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# Generated from CLion Inspection settings
|
|
||||||
---
|
---
|
||||||
Checks: '-*,
|
Checks: '-*,
|
||||||
cppcoreguidelines-interfaces-global-init,
|
cppcoreguidelines-interfaces-global-init,
|
||||||
@@ -69,4 +68,5 @@ misc-*,
|
|||||||
-readability-identifier-length,
|
-readability-identifier-length,
|
||||||
-readability-named-parameter,
|
-readability-named-parameter,
|
||||||
-readability-function-cognitive-complexity,
|
-readability-function-cognitive-complexity,
|
||||||
-misc-include-cleaner'
|
-*-include-cleaner,
|
||||||
|
-*-lambda-function-name'
|
||||||
1
.idea/dictionaries/project.xml
generated
1
.idea/dictionaries/project.xml
generated
@@ -2,6 +2,7 @@
|
|||||||
<dictionary name="project">
|
<dictionary name="project">
|
||||||
<words>
|
<words>
|
||||||
<w>abcdefghijklmnopqrstuvwxyz</w>
|
<w>abcdefghijklmnopqrstuvwxyz</w>
|
||||||
|
<w>indicies</w>
|
||||||
<w>koalabox</w>
|
<w>koalabox</w>
|
||||||
<w>koaloader</w>
|
<w>koaloader</w>
|
||||||
</words>
|
</words>
|
||||||
|
|||||||
7
.idea/runConfigurations/SmokeAPI.xml
generated
7
.idea/runConfigurations/SmokeAPI.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="SmokeAPI" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="SmokeAPI" CONFIG_NAME="Debug [64]">
|
|
||||||
<method v="2">
|
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
7
.idea/runConfigurations/exports_generator__64_.xml
generated
Normal file
7
.idea/runConfigurations/exports_generator__64_.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="exports_generator [64]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="FALSE steam_api64_o $ProjectFileDir$/res/steamworks/*/binaries/steam_api64.dll $ProjectFileDir$/build/64/linker_exports.h $ProjectFileDir$/src/game_mode/exports" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="exports_generator" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="exports_generator">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="steamworks_downloader [prompt]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="$Prompt$" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/res" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="steamworks_downloader" CONFIG_NAME="Debug [64]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_downloader">
|
<configuration default="false" name="steamworks_downloader [prompt]" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="$Prompt$" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/res" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="steamworks_downloader" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_downloader">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
2
.idea/runConfigurations/steamworks_parser.xml
generated
2
.idea/runConfigurations/steamworks_parser.xml
generated
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="steamworks_parser" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/res/" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="steamworks_parser" CONFIG_NAME="Debug [64]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_parser">
|
<configuration default="false" name="steamworks_parser" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/res/" PASS_PARENT_ENVS_2="true" PROJECT_NAME="SmokeAPI" TARGET_NAME="steamworks_parser" CONFIG_NAME="Debug [32]" RUN_TARGET_PROJECT_NAME="SmokeAPI" RUN_TARGET_NAME="steamworks_parser">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ set(
|
|||||||
src/game_mode/exports/steam_api_unversioned.cpp
|
src/game_mode/exports/steam_api_unversioned.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
configure_build_config(extra_build_config)
|
configure_build_config(extra_build_config)
|
||||||
|
|
||||||
set(
|
set(
|
||||||
@@ -70,6 +69,7 @@ set(
|
|||||||
|
|
||||||
# Include store_mode mode sources only in 32-bit builds
|
# Include store_mode mode sources only in 32-bit builds
|
||||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
|
# TODO: Use list(APPEND ...) ?
|
||||||
set(
|
set(
|
||||||
SMOKE_API_SOURCES ${SMOKE_API_SOURCES}
|
SMOKE_API_SOURCES ${SMOKE_API_SOURCES}
|
||||||
src/store_mode/steamclient/client_app_manager.cpp
|
src/store_mode/steamclient/client_app_manager.cpp
|
||||||
|
|||||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: f08d46d4c4...afb09983ca
@@ -1,2 +1,3 @@
|
|||||||
- Rework Koalabox integration: Remove submodule, add conditional include (local filesystem and CPM)
|
# Building from source
|
||||||
- Write up documentation
|
|
||||||
|
TODO
|
||||||
@@ -1 +0,0 @@
|
|||||||
#
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Tools
|
||||||
|
|
||||||
|
TODO: describe steamworks_downloader and steamworks_parser tools
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <core/globals.hpp>
|
#include <core/globals.hpp>
|
||||||
#include <koalabox/core.hpp>
|
#include <koalabox/core.hpp>
|
||||||
#include <koalabox/hook.hpp>
|
#include <koalabox/hook.hpp>
|
||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default, virtual functions are declared with __thiscall
|
* By default, virtual functions are declared with __thiscall
|
||||||
@@ -30,35 +30,39 @@
|
|||||||
* The macros below implement the above-mentioned considerations.
|
* The macros below implement the above-mentioned considerations.
|
||||||
*/
|
*/
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#define PARAMS(...) void* RCX, __VA_ARGS__
|
#define PARAMS(...) void *RCX, __VA_ARGS__
|
||||||
#define ARGS(...) RCX, __VA_ARGS__
|
#define ARGS(...) RCX, __VA_ARGS__
|
||||||
#define THIS RCX
|
#define THIS RCX
|
||||||
#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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Names beginning with $ designate macros that are not meant to be used directly by the sources consuming this file
|
// Names beginning with $ designate macros that are not meant to be used directly by the sources
|
||||||
|
// consuming this file
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl
|
|
||||||
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall
|
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall
|
||||||
|
|
||||||
// TODO: Replace with direct call
|
// TODO: Replace with direct call
|
||||||
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
|
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
|
||||||
static const auto FUNC##_o = koalabox::hook::get_original_hooked_function(#FUNC, FUNC);
|
static const auto FUNC##_o = koalabox::hook::get_original_hooked_function(#FUNC, FUNC);
|
||||||
|
|
||||||
#define ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
|
#define ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
|
||||||
koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC)
|
koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC)
|
||||||
|
|
||||||
// TODO: Rename to DEFINE_ORIGINAL_FUNCTION_STEAMAPI
|
// TODO: Rename to DEFINE_ORIGINAL_FUNCTION_STEAMAPI
|
||||||
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
|
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
|
||||||
static const auto FUNC##_o = ORIGINAL_FUNCTION_STEAMAPI(FUNC);
|
static const auto FUNC##_o = ORIGINAL_FUNCTION_STEAMAPI(FUNC);
|
||||||
|
|
||||||
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
|
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
|
||||||
koalabox::hook::detour_or_warn(ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
|
koalabox::hook::detour_or_warn(ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
|
||||||
|
|
||||||
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
|
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
|
||||||
koalabox::hook::detour_or_warn(MODULE_HANDLE, NAME, reinterpret_cast<uintptr_t>(FUNC));
|
koalabox::hook::detour_or_warn(MODULE_HANDLE, NAME, reinterpret_cast<uintptr_t>(FUNC));
|
||||||
|
|
||||||
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, #FUNC, globals::steamclient_module)
|
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, #FUNC, globals::steamclient_module)
|
||||||
@@ -116,16 +120,15 @@ struct App {
|
|||||||
using AppDlcNameMap = Map<AppIdKey, App>;
|
using AppDlcNameMap = Map<AppIdKey, App>;
|
||||||
|
|
||||||
class DLC {
|
class DLC {
|
||||||
private:
|
private:
|
||||||
// These 2 names must match the property names from Steam API
|
// These 2 names must match the property names from Steam API
|
||||||
String appid;
|
String appid;
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DLC() = default;
|
explicit DLC() = default;
|
||||||
|
|
||||||
explicit DLC(String appid, String name) : appid{std::move(appid)}, name{std::move(name)} {
|
explicit DLC(String appid, String name) : appid{std::move(appid)}, name{std::move(name)} {}
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] String get_id_str() const {
|
[[nodiscard]] String get_id_str() const {
|
||||||
return appid;
|
return appid;
|
||||||
@@ -141,7 +144,7 @@ public:
|
|||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(DLC, appid, name)
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE(DLC, appid, name)
|
||||||
|
|
||||||
static Vector<DLC> get_dlcs_from_apps(const AppDlcNameMap &apps, AppId_t app_id);
|
static Vector<DLC> get_dlcs_from_apps(const AppDlcNameMap& apps, AppId_t app_id);
|
||||||
|
|
||||||
static DlcNameMap get_dlc_map_from_vector(const Vector<DLC> &vector);
|
static DlcNameMap get_dlc_map_from_vector(const Vector<DLC>& vector);
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,18 @@
|
|||||||
#include <smoke_api/config.hpp>
|
#include <smoke_api/config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
// DLL_EXPORT(void) SteamAPI_Shutdown1() {
|
||||||
|
// LOG_INFO("{} -> Game requested shutdown", __func__);
|
||||||
|
//
|
||||||
|
// ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_Shutdown)();
|
||||||
|
// }
|
||||||
|
|
||||||
|
/*DLL_EXPORT(void) SteamAPI_Shutdown2() {
|
||||||
|
LOG_INFO("{} -> Game requested shutdown", __func__);
|
||||||
|
|
||||||
|
ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_Shutdown)();
|
||||||
|
}*/
|
||||||
|
|
||||||
// TODO: Detour in hook mode
|
// TODO: Detour in hook mode
|
||||||
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(
|
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(
|
||||||
[[maybe_unused]] const uint32_t unOwnAppID
|
[[maybe_unused]] const uint32_t unOwnAppID
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <koalabox/hook.hpp>
|
#include <koalabox/hook.hpp>
|
||||||
#include <koalabox/loader.hpp>
|
#include <koalabox/loader.hpp>
|
||||||
#include <koalabox/logger.hpp>
|
#include <koalabox/logger.hpp>
|
||||||
|
#include <koalabox/str.hpp>
|
||||||
#include <koalabox/util.hpp>
|
#include <koalabox/util.hpp>
|
||||||
#include <koalabox/win_util.hpp>
|
#include <koalabox/win_util.hpp>
|
||||||
|
|
||||||
@@ -40,8 +41,9 @@
|
|||||||
namespace {
|
namespace {
|
||||||
void override_app_id() {
|
void override_app_id() {
|
||||||
const auto override_app_id = smoke_api::config::instance.override_app_id;
|
const auto override_app_id = smoke_api::config::instance.override_app_id;
|
||||||
if (override_app_id == 0)
|
if (override_app_id == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
spdlog::default_logger_raw();
|
spdlog::default_logger_raw();
|
||||||
LOG_DEBUG("Overriding app id to {}", override_app_id);
|
LOG_DEBUG("Overriding app id to {}", override_app_id);
|
||||||
@@ -74,7 +76,7 @@ namespace {
|
|||||||
|
|
||||||
bool is_valve_steam(const String& exe_name) noexcept {
|
bool is_valve_steam(const String& exe_name) noexcept {
|
||||||
try {
|
try {
|
||||||
if (exe_name < not_equals > "steam.exe") {
|
if (not koalabox::str::eq(exe_name, "steam.exe")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ namespace {
|
|||||||
const auto manifest = koalabox::win_util::get_module_manifest(steam_handle);
|
const auto manifest = koalabox::win_util::get_module_manifest(steam_handle);
|
||||||
|
|
||||||
// Steam.exe manifest is expected to contain this string
|
// Steam.exe manifest is expected to contain this string
|
||||||
return manifest < contains > "valvesoftware.steam.steam";
|
return manifest.contains("valvesoftware.steam.steam");
|
||||||
} catch (const Exception& e) {
|
} catch (const Exception& e) {
|
||||||
LOG_ERROR("{} -> {}", __func__, e.what());
|
LOG_ERROR("{} -> {}", __func__, e.what());
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
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)) {
|
||||||
try {
|
try {
|
||||||
return steam_apps::IsDlcUnlocked(
|
return steam_apps::IsDlcUnlocked(
|
||||||
__func__, app_id, dlc_id, [&]() {
|
__func__, app_id, dlc_id, [&] {
|
||||||
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_IsAppDlcInstalled)
|
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_IsAppDlcInstalled)
|
||||||
|
|
||||||
return IClientAppManager_IsAppDlcInstalled_o(ARGS(app_id, dlc_id));
|
return IClientAppManager_IsAppDlcInstalled_o(ARGS(app_id, dlc_id));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (const Exception& e) {
|
} catch (const Exception& e) {
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what())
|
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (const Exception& e) {
|
} catch (const Exception& e) {
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what())
|
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
|
|||||||
ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize)
|
ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[&](AppId_t dlc_id) {
|
[&](const AppId_t dlc_id) {
|
||||||
const auto* app_manager_interface = store::steamclient::interface_name_to_address_map["IClientAppManager"];
|
const auto* app_manager_interface = store::steamclient::interface_name_to_address_map["IClientAppManager"];
|
||||||
if (app_manager_interface) {
|
if (app_manager_interface) {
|
||||||
IClientAppManager_IsAppDlcInstalled(app_manager_interface, EDX, appID, dlc_id);
|
IClientAppManager_IsAppDlcInstalled(app_manager_interface, EDX, appID, dlc_id);
|
||||||
@@ -48,7 +48,7 @@ VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (const Exception& e) {
|
} catch (const Exception& e) {
|
||||||
LOG_ERROR("{} -> Error: {}", __func__, e.what())
|
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ namespace store::steamclient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void detour_interface_selector(const String& interface_name, uintptr_t function_selector_address) {
|
void detour_interface_selector(const String& interface_name, uintptr_t function_selector_address) {
|
||||||
LOG_DEBUG("Detected interface: '{}'", interface_name)
|
LOG_DEBUG("Detected interface: '{}'", interface_name);
|
||||||
|
|
||||||
DETOUR_SELECTOR(IClientAppManager)
|
DETOUR_SELECTOR(IClientAppManager)
|
||||||
DETOUR_SELECTOR(IClientApps)
|
DETOUR_SELECTOR(IClientApps)
|
||||||
@@ -198,10 +198,10 @@ namespace store::steamclient {
|
|||||||
const std::list<ZydisDecodedInstruction>& instruction_list
|
const std::list<ZydisDecodedInstruction>& instruction_list
|
||||||
)>& callback
|
)>& callback
|
||||||
) {
|
) {
|
||||||
LOG_TRACE("{} -> start_address: {}", __func__, (void*) start_address)
|
LOG_TRACE("{} -> start_address: {}", __func__, (void*) start_address);
|
||||||
|
|
||||||
if (visited_addresses.contains(start_address)) {
|
if (visited_addresses.contains(start_address)) {
|
||||||
LOG_TRACE("Breaking recursion due to visited address")
|
LOG_TRACE("Breaking recursion due to visited address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@ namespace store::steamclient {
|
|||||||
LOG_TRACE(
|
LOG_TRACE(
|
||||||
"{} -> visiting {} │ {}",
|
"{} -> visiting {} │ {}",
|
||||||
__func__, (void*) current_address, *get_instruction_string(instruction, current_address)
|
__func__, (void*) current_address, *get_instruction_string(instruction, current_address)
|
||||||
)
|
);
|
||||||
|
|
||||||
const auto operand = instruction.operands[0];
|
const auto operand = instruction.operands[0];
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ namespace store::steamclient {
|
|||||||
visit_code(visited_addresses, jump_taken_destination, context, callback);
|
visit_code(visited_addresses, jump_taken_destination, context, callback);
|
||||||
visit_code(visited_addresses, jump_not_taken_destination, context, callback);
|
visit_code(visited_addresses, jump_not_taken_destination, context, callback);
|
||||||
|
|
||||||
LOG_TRACE("{} -> Breaking recursion due to a conditional branch", __func__)
|
LOG_TRACE("{} -> Breaking recursion due to a conditional branch", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,12 +266,12 @@ namespace store::steamclient {
|
|||||||
table_entry++;
|
table_entry++;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_TRACE("{} -> Breaking recursion due to a jump table", __func__)
|
LOG_TRACE("{} -> Breaking recursion due to a jump table", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instruction.mnemonic == ZYDIS_MNEMONIC_RET) {
|
if (instruction.mnemonic == ZYDIS_MNEMONIC_RET) {
|
||||||
LOG_TRACE("{} -> Breaking recursion due to return instruction", __func__)
|
LOG_TRACE("{} -> Breaking recursion due to return instruction", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ namespace store::steamclient {
|
|||||||
if (offset && is_derived_from_base_reg) {
|
if (offset && is_derived_from_base_reg) {
|
||||||
const auto ordinal = *offset / sizeof(uintptr_t);
|
const auto ordinal = *offset / sizeof(uintptr_t);
|
||||||
|
|
||||||
LOG_DEBUG("Found function ordinal {}::{}@{}", target_interface, function_name, ordinal)
|
LOG_DEBUG("Found function ordinal {}::{}@{}", target_interface, function_name, ordinal);
|
||||||
|
|
||||||
function_name_to_ordinal_map[function_name] = ordinal;
|
function_name_to_ordinal_map[function_name] = ordinal;
|
||||||
return true;
|
return true;
|
||||||
@@ -410,7 +410,7 @@ namespace store::steamclient {
|
|||||||
const auto&
|
const auto&
|
||||||
) {
|
) {
|
||||||
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
|
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
|
||||||
LOG_TRACE("Found call instruction at {}", (void*) current_address)
|
LOG_TRACE("Found call instruction at {}", (void*) current_address);
|
||||||
|
|
||||||
const auto function_selector_address = get_absolute_address(instruction, current_address);
|
const auto function_selector_address = get_absolute_address(instruction, current_address);
|
||||||
|
|
||||||
@@ -436,15 +436,15 @@ namespace store::steamclient {
|
|||||||
store::config.steam_client_internal_interface_selector_ordinal
|
store::config.steam_client_internal_interface_selector_ordinal
|
||||||
];
|
];
|
||||||
|
|
||||||
LOG_DEBUG("Found interface selector at: {}", (void*) interface_selector_address)
|
LOG_DEBUG("Found interface selector at: {}", (void*) interface_selector_address);
|
||||||
|
|
||||||
if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32))) {
|
if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32))) {
|
||||||
LOG_ERROR("Failed to initialize zydis decoder")
|
LOG_ERROR("Failed to initialize zydis decoder");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ZYAN_FAILED(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) {
|
if (ZYAN_FAILED(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) {
|
||||||
LOG_ERROR("Failed to initialize zydis formatter")
|
LOG_ERROR("Failed to initialize zydis formatter");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#include <store_mode/store.hpp>
|
#include "koalabox/str.hpp"
|
||||||
#include <store_mode/vstdlib/vstdlib.hpp>
|
|
||||||
#include <store_mode/store_cache.hpp>
|
|
||||||
#include <store_mode/store_api.hpp>
|
|
||||||
#include <smoke_api/config.hpp>
|
|
||||||
#include <build_config.h>
|
#include <build_config.h>
|
||||||
#include <koalabox/dll_monitor.hpp>
|
|
||||||
#include <koalabox/logger.hpp>
|
|
||||||
#include <koalabox/ipc.hpp>
|
|
||||||
#include <common/steamclient_exports.hpp>
|
#include <common/steamclient_exports.hpp>
|
||||||
|
#include <koalabox/dll_monitor.hpp>
|
||||||
|
#include <koalabox/ipc.hpp>
|
||||||
|
#include <koalabox/logger.hpp>
|
||||||
|
#include <smoke_api/config.hpp>
|
||||||
|
#include <store_mode/store.hpp>
|
||||||
|
#include <store_mode/store_api.hpp>
|
||||||
|
#include <store_mode/store_cache.hpp>
|
||||||
|
#include <store_mode/vstdlib/vstdlib.hpp>
|
||||||
|
|
||||||
namespace store {
|
namespace store {
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ namespace store {
|
|||||||
*/
|
*/
|
||||||
void init_store_config() {
|
void init_store_config() {
|
||||||
const auto print_source = [](const String& source) {
|
const auto print_source = [](const String& source) {
|
||||||
LOG_INFO("Loaded Store config from the {}", source)
|
LOG_INFO("Loaded Store config from the {}", source);
|
||||||
};
|
};
|
||||||
|
|
||||||
// First try to read a local config override
|
// First try to read a local config override
|
||||||
@@ -30,7 +32,7 @@ namespace store {
|
|||||||
print_source("local config override");
|
print_source("local config override");
|
||||||
return;
|
return;
|
||||||
} catch (const Exception& ex) {
|
} catch (const Exception& ex) {
|
||||||
LOG_ERROR("Failed to get local store_mode config: {}", ex.what())
|
LOG_ERROR("Failed to get local store_mode config: {}", ex.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ namespace store {
|
|||||||
|
|
||||||
print_source("disk cache");
|
print_source("disk cache");
|
||||||
} catch (const Exception& ex) {
|
} catch (const Exception& ex) {
|
||||||
LOG_ERROR("Failed to get cached store_mode config: {}", ex.what())
|
LOG_ERROR("Failed to get cached store_mode config: {}", ex.what());
|
||||||
|
|
||||||
print_source("default config bundled in the binary");
|
print_source("default config bundled in the binary");
|
||||||
|
|
||||||
@@ -62,7 +64,7 @@ namespace store {
|
|||||||
store_cache::save_store_config(github_config);
|
store_cache::save_store_config(github_config);
|
||||||
|
|
||||||
if (github_config == config) {
|
if (github_config == config) {
|
||||||
LOG_DEBUG("Fetched Store config is equal to existing config")
|
LOG_DEBUG("Fetched Store config is equal to existing config");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -79,7 +81,7 @@ namespace store {
|
|||||||
MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK
|
MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK
|
||||||
);
|
);
|
||||||
} catch (const Exception& ex) {
|
} catch (const Exception& ex) {
|
||||||
LOG_ERROR("Failed to get remote store_mode config: {}", ex.what())
|
LOG_ERROR("Failed to get remote store_mode config: {}", ex.what());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -90,7 +92,7 @@ namespace store {
|
|||||||
koalabox::dll_monitor::init_listener(
|
koalabox::dll_monitor::init_listener(
|
||||||
{VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
|
{VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
|
||||||
try {
|
try {
|
||||||
if (name < equals > VSTDLIB_DLL) {
|
if (koalabox::str::eq(name, VSTDLIB_DLL)) {
|
||||||
// VStdLib DLL handles Family Sharing functions
|
// VStdLib DLL handles Family Sharing functions
|
||||||
|
|
||||||
globals::vstdlib_module = module_handle;
|
globals::vstdlib_module = module_handle;
|
||||||
@@ -98,7 +100,7 @@ namespace store {
|
|||||||
if (smoke_api::config::instance.unlock_family_sharing) {
|
if (smoke_api::config::instance.unlock_family_sharing) {
|
||||||
DETOUR_VSTDLIB(Coroutine_Create)
|
DETOUR_VSTDLIB(Coroutine_Create)
|
||||||
}
|
}
|
||||||
} else if (name < equals > STEAMCLIENT_DLL) {
|
} else if (koalabox::str::eq(name, STEAMCLIENT_DLL)) {
|
||||||
// SteamClient DLL handles unlocking functions
|
// SteamClient DLL handles unlocking functions
|
||||||
|
|
||||||
globals::steamclient_module = module_handle;
|
globals::steamclient_module = module_handle;
|
||||||
@@ -113,7 +115,7 @@ namespace store {
|
|||||||
LOG_ERROR(
|
LOG_ERROR(
|
||||||
"Error listening to DLL load events. Module: '{}', Message: {}",
|
"Error listening to DLL load events. Module: '{}', Message: {}",
|
||||||
name, ex.what()
|
name, ex.what()
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,10 +2,6 @@ cmake_minimum_required(VERSION 3.24)
|
|||||||
|
|
||||||
project(smoke-api-tools LANGUAGES CXX)
|
project(smoke-api-tools LANGUAGES CXX)
|
||||||
|
|
||||||
### Install CPM package manager
|
|
||||||
|
|
||||||
#include(../KoalaBox/cmake/get_cpm.cmake)
|
|
||||||
|
|
||||||
### Install parser library
|
### Install parser library
|
||||||
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
@@ -24,11 +20,11 @@ add_grammar_from_repo(tree-sitter-cpp # Library name
|
|||||||
|
|
||||||
### Install JSON library
|
### Install JSON library
|
||||||
|
|
||||||
CPMAddPackage(
|
#CPMAddPackage(
|
||||||
NAME nlohmann_json
|
# NAME nlohmann_json
|
||||||
GIT_REPOSITORY https://github.com/nlohmann/json.git
|
# GIT_REPOSITORY https://github.com/nlohmann/json.git
|
||||||
GIT_TAG v3.12.0
|
# GIT_TAG v3.12.0
|
||||||
)
|
#)
|
||||||
|
|
||||||
### Install HTTP client library
|
### Install HTTP client library
|
||||||
|
|
||||||
@@ -43,12 +39,15 @@ CPMAddPackage(
|
|||||||
GIT_TAG 1.12.0
|
GIT_TAG 1.12.0
|
||||||
)
|
)
|
||||||
|
|
||||||
### Install ZIP library https://github.com/richgel999/miniz
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME miniz
|
NAME BS_thread_pool
|
||||||
GIT_REPOSITORY https://github.com/richgel999/miniz.git
|
GITHUB_REPOSITORY bshoshany/thread-pool
|
||||||
GIT_TAG c883286f1a6443720e7705450f59e579a4bbb8e2
|
VERSION 5.0.0
|
||||||
|
EXCLUDE_FROM_ALL
|
||||||
|
SYSTEM
|
||||||
)
|
)
|
||||||
|
add_library(BS_thread_pool INTERFACE)
|
||||||
|
target_include_directories(BS_thread_pool INTERFACE ${BS_thread_pool_SOURCE_DIR}/include)
|
||||||
|
|
||||||
### Steamworks Downloader executable
|
### Steamworks Downloader executable
|
||||||
|
|
||||||
@@ -56,14 +55,16 @@ add_executable(steamworks_downloader steamworks_downloader.cpp)
|
|||||||
target_link_libraries(steamworks_downloader PRIVATE
|
target_link_libraries(steamworks_downloader PRIVATE
|
||||||
KoalaBox
|
KoalaBox
|
||||||
cpr # HTTP client
|
cpr # HTTP client
|
||||||
miniz # ZIP library
|
miniz # ZIP library TODO: Use koalabox instead
|
||||||
)
|
)
|
||||||
|
|
||||||
### Steamworks Parser executable
|
### Steamworks Parser executable
|
||||||
|
|
||||||
add_executable(steamworks_parser steamworks_parser.cpp)
|
add_executable(steamworks_parser steamworks_parser.cpp)
|
||||||
target_link_libraries(steamworks_parser PRIVATE
|
target_link_libraries(steamworks_parser PRIVATE
|
||||||
nlohmann_json # JSON parser
|
KoalaBox
|
||||||
tree-sitter-cpp # C++ grammar
|
BS_thread_pool
|
||||||
cpp-tree-sitter # C++ bindings for tree-sitter
|
# nlohmann_json # JSON parser
|
||||||
|
# tree-sitter-cpp # C++ grammar
|
||||||
|
# cpp-tree-sitter # C++ bindings for tree-sitter
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
#include <cpr/cpr.h>
|
#include <cpr/cpr.h>
|
||||||
|
|
||||||
@@ -11,8 +12,7 @@ namespace {
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
namespace zip = koalabox::zip;
|
namespace zip = koalabox::zip;
|
||||||
|
|
||||||
// ReSharper disable once CppDFAConstantParameter
|
std::string generate_random_string() {
|
||||||
std::string generate_random_string(const size_t length) {
|
|
||||||
static constexpr char charset[] = "0123456789"
|
static constexpr char charset[] = "0123456789"
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"abcdefghijklmnopqrstuvwxyz";
|
"abcdefghijklmnopqrstuvwxyz";
|
||||||
@@ -20,6 +20,7 @@ namespace {
|
|||||||
thread_local std::mt19937_64 rng{std::random_device{}()};
|
thread_local std::mt19937_64 rng{std::random_device{}()};
|
||||||
thread_local std::uniform_int_distribution<std::size_t> dist(0, sizeof(charset) - 2);
|
thread_local std::uniform_int_distribution<std::size_t> dist(0, sizeof(charset) - 2);
|
||||||
|
|
||||||
|
constexpr auto length = 16;
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(length);
|
result.reserve(length);
|
||||||
for (std::size_t i = 0; i < length; ++i) {
|
for (std::size_t i = 0; i < length; ++i) {
|
||||||
@@ -59,7 +60,7 @@ namespace {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const auto zip_file_path =
|
const auto zip_file_path =
|
||||||
fs::temp_directory_path() / (generate_random_string(16) + ".zip");
|
fs::temp_directory_path() / (generate_random_string() + ".zip");
|
||||||
|
|
||||||
std::cout << "Downloading " << download_url << " to " << zip_file_path << std::endl;
|
std::cout << "Downloading " << download_url << " to " << zip_file_path << std::endl;
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ namespace {
|
|||||||
* A tool for downloading Steamworks SDK and unpacking its headers and binaries
|
* A tool for downloading Steamworks SDK and unpacking its headers and binaries
|
||||||
* for further processing by other tools.
|
* for further processing by other tools.
|
||||||
*/
|
*/
|
||||||
int main(const int argc, const char** argv) {
|
int main(const int argc, const char** argv) { // NOLINT(*-exception-escape)
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
print_help();
|
print_help();
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,31 +1,28 @@
|
|||||||
#include <iostream>
|
#include "koalabox/crypto.hpp"
|
||||||
#include <functional>
|
#include "koalabox/io.hpp"
|
||||||
#include <filesystem>
|
#include "koalabox/util.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <BS_thread_pool.hpp>
|
||||||
#include <cpp-tree-sitter.h>
|
#include <cpp-tree-sitter.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
extern "C" const TSLanguage* tree_sitter_cpp();
|
#include <koalabox/logger.hpp>
|
||||||
|
#include <koalabox/parser.hpp>
|
||||||
|
#include <koalabox/str.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
namespace fs = std::filesystem;
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
std::string_view trim(const std::string_view& s) {
|
namespace parser = koalabox::parser;
|
||||||
const auto start =
|
|
||||||
std::ranges::find_if_not(s, [](const unsigned char ch) { return std::isspace(ch); });
|
|
||||||
const auto end =
|
|
||||||
std::find_if_not(
|
|
||||||
s.rbegin(), s.rend(),
|
|
||||||
[](const unsigned char ch) { return std::isspace(ch); }
|
|
||||||
).base();
|
|
||||||
return start < end ? std::string_view(start, end) : std::string_view();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view unquote_if_quoted(const std::string_view& s) {
|
std::string_view unquote_if_quoted(const std::string_view& s) {
|
||||||
if (s.size() >= 2 && ((s.front() == '"' && s.back() == '"'))) {
|
if (s.size() >= 2 && s.front() == '"' && s.back() == '"') {
|
||||||
return s.substr(1, s.size() - 2);
|
return s.substr(1, s.size() - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,145 +30,109 @@ namespace {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class VisitResult {
|
|
||||||
Continue,
|
|
||||||
SkipChildren,
|
|
||||||
Stop
|
|
||||||
};
|
|
||||||
|
|
||||||
void walk(
|
|
||||||
const ts::Node& root,
|
|
||||||
const std::function<VisitResult(ts::Node)>& visit
|
|
||||||
) {
|
|
||||||
// DFS traversal
|
|
||||||
std::deque<ts::Node> queue;
|
|
||||||
queue.push_back(root);
|
|
||||||
auto first_visit = true;
|
|
||||||
|
|
||||||
while (not queue.empty()) {
|
|
||||||
const auto node = queue.front();
|
|
||||||
queue.pop_front();
|
|
||||||
|
|
||||||
switch (first_visit ? VisitResult::Continue : visit(node)) {
|
|
||||||
case VisitResult::Continue:
|
|
||||||
break;
|
|
||||||
case VisitResult::SkipChildren:
|
|
||||||
continue;
|
|
||||||
case VisitResult::Stop:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0, count = node.getNumNamedChildren(); i < count; ++i) {
|
|
||||||
if (const auto child = node.getNamedChild(i); not child.isNull()) {
|
|
||||||
queue.push_back(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
first_visit = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_header(const std::string_view& source, json& lookup) {
|
void parse_header(const std::string_view& source, json& lookup) {
|
||||||
const auto language = ts::Language(tree_sitter_cpp());
|
const auto tree = parser::parse_source(source);
|
||||||
auto parser = ts::Parser(language);
|
|
||||||
const auto tree = parser.parseString(source);
|
|
||||||
const auto root = tree.getRootNode();
|
const auto root = tree.getRootNode();
|
||||||
|
|
||||||
json current_lookup = {};
|
json current_lookup = {};
|
||||||
std::string interface_version;
|
std::string interface_version;
|
||||||
|
|
||||||
walk(root, [&](const auto& current_node) {
|
parser::walk(root, [&](const auto& current_node) {
|
||||||
const auto current_type = current_node.getType();
|
const auto current_type = current_node.getType();
|
||||||
if (current_type == "class_specifier") {
|
if (current_type == "class_specifier") {
|
||||||
|
|
||||||
std::string interface_name;
|
std::string interface_name;
|
||||||
[[maybe_unused]] int vt_idx = 0;
|
[[maybe_unused]] int vt_idx = 0;
|
||||||
|
|
||||||
walk(current_node, [&](const ts::Node& class_node) {
|
koalabox::parser::walk(current_node, [&](const ts::Node& class_node) {
|
||||||
const auto type = class_node.getType();
|
const auto type = class_node.getType();
|
||||||
const auto value = class_node.getSourceRange(source);
|
const auto value = class_node.getSourceRange(source);
|
||||||
|
|
||||||
if (type == "type_identifier" && interface_name.empty()) {
|
if (type == "type_identifier" && interface_name.empty()) {
|
||||||
interface_name = value;
|
interface_name = value;
|
||||||
std::cout << " Parsing interface: " << interface_name << std::endl;
|
LOG_DEBUG("Found interface: {}", interface_name);
|
||||||
|
|
||||||
return VisitResult::Continue;
|
return parser::visit_result::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "field_declaration" && value.starts_with("virtual ")) {
|
if (type == "field_declaration" && value.starts_with("virtual ")) {
|
||||||
if (value.starts_with("virtual ")) {
|
if (value.starts_with("virtual ")) {
|
||||||
walk(class_node, [&](const ts::Node& decl_node) {
|
koalabox::parser::walk(class_node, [&](const ts::Node& decl_node) {
|
||||||
if (decl_node.getType() == "field_identifier") {
|
if (decl_node.getType() == "field_identifier") {
|
||||||
const auto function_name =
|
const auto function_name = decl_node.getSourceRange(source);
|
||||||
decl_node.getSourceRange(source);
|
|
||||||
|
|
||||||
current_lookup[function_name]["vt_idx"] = vt_idx++;
|
current_lookup[function_name] = vt_idx++;
|
||||||
return VisitResult::Stop;
|
return parser::visit_result::Stop;
|
||||||
}
|
}
|
||||||
return VisitResult::Continue;
|
return parser::visit_result::Continue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return VisitResult::SkipChildren;
|
return parser::visit_result::SkipChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
return VisitResult::Continue;
|
return parser::visit_result::Continue;
|
||||||
});
|
});
|
||||||
} else if (current_type == "preproc_def") {
|
} else if (current_type == "preproc_def") {
|
||||||
walk(current_node, [&](const ts::Node& preproc_node) {
|
koalabox::parser::walk(current_node, [&](const ts::Node& preproc_node) {
|
||||||
if (preproc_node.getType() == "identifier") {
|
if (preproc_node.getType() == "identifier") {
|
||||||
const auto identifier = preproc_node.getSourceRange(source);
|
const auto identifier = preproc_node.getSourceRange(source);
|
||||||
|
|
||||||
return identifier.ends_with("INTERFACE_VERSION")
|
return identifier.ends_with("INTERFACE_VERSION")
|
||||||
? VisitResult::Continue
|
? parser::visit_result::Continue
|
||||||
: VisitResult::Stop;
|
: parser::visit_result::Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preproc_node.getType() == "preproc_arg") {
|
if (preproc_node.getType() == "preproc_arg") {
|
||||||
const auto quoted_version = preproc_node.getSourceRange(source);
|
const auto quoted_version = preproc_node.getSourceRange(source);
|
||||||
interface_version = unquote_if_quoted(trim(quoted_version));
|
const auto trimmed_version = koalabox::str::trim(quoted_version);
|
||||||
std::cout << " Interface version: " << interface_version << std::endl;
|
interface_version = unquote_if_quoted(trimmed_version);
|
||||||
|
LOG_DEBUG("Interface version: {}", interface_version);
|
||||||
|
|
||||||
return VisitResult::Stop;
|
return parser::visit_result::Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
return VisitResult::Continue;
|
return parser::visit_result::Continue;
|
||||||
});
|
});
|
||||||
} else if (current_type == "translation_unit" || current_type == "preproc_ifdef") {
|
} else if (current_type == "translation_unit" || current_type == "preproc_ifdef") {
|
||||||
return VisitResult::Continue;
|
return parser::visit_result::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return VisitResult::SkipChildren;
|
return parser::visit_result::SkipChildren;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save the findings
|
// Save the findings
|
||||||
|
static std::mutex mutex;
|
||||||
if (not interface_version.empty()) {
|
if (not interface_version.empty()) {
|
||||||
|
const std::lock_guard lock(mutex);
|
||||||
lookup[interface_version] = current_lookup;
|
lookup[interface_version] = current_lookup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_sdk(const fs::path& sdk_path, json& lookup) {
|
void parse_sdk(const fs::path& sdk_path, json& lookup, BS::thread_pool<>& pool) {
|
||||||
const auto headers_dir = sdk_path / "headers";
|
const auto headers_dir = sdk_path / "headers";
|
||||||
|
|
||||||
if (not fs::exists(headers_dir)) {
|
if (not fs::exists(headers_dir)) {
|
||||||
std::cout << "Warning: SDK missing 'headers' directory: " << headers_dir << std::endl;
|
LOG_WARN("Warning: SDK missing 'headers' directory: {}", headers_dir.string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Parsing SDK: {}", headers_dir.string());
|
||||||
|
|
||||||
// Go over each file in headers directory
|
// Go over each file in headers directory
|
||||||
for (const auto& entry : fs::directory_iterator(headers_dir)) {
|
for (const auto& entry : fs::directory_iterator(headers_dir)) {
|
||||||
if (
|
if (const auto& header_path = entry.path(); header_path.extension() == ".h") {
|
||||||
const auto& header_path = entry.path();
|
const auto task = pool.submit_task([&, header_path] {
|
||||||
header_path.extension() == ".h"
|
try {
|
||||||
) {
|
LOG_DEBUG("Parsing header: {}", header_path.string());
|
||||||
std::cout << "Parsing header: " << header_path << std::endl;
|
|
||||||
|
|
||||||
// Read file as text
|
// Read file as text
|
||||||
std::ifstream in(header_path, std::ios::binary);
|
const auto header_contents = koalabox::io::read_file(header_path);
|
||||||
const std::string header_contents(std::istreambuf_iterator{in}, {});
|
|
||||||
|
|
||||||
// Parse it
|
parse_header(header_contents, lookup);
|
||||||
parse_header(header_contents, lookup);
|
} catch (std::exception& e) {
|
||||||
|
koalabox::util::panic(std::format("Error parsing header: {}", e.what()));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,15 +140,23 @@ namespace {
|
|||||||
void generate_lookup_json(const fs::path& steamworks_dir) {
|
void generate_lookup_json(const fs::path& steamworks_dir) {
|
||||||
json lookup;
|
json lookup;
|
||||||
|
|
||||||
|
// Create the thread pool
|
||||||
|
const auto thread_count = std::max(2U, std::thread::hardware_concurrency() / 2);
|
||||||
|
LOG_INFO("Creating task pool with {} threads", thread_count);
|
||||||
|
BS::thread_pool pool(thread_count);
|
||||||
|
|
||||||
// Go over each steamworks sdk version
|
// Go over each steamworks sdk version
|
||||||
for (const auto& entry : fs::directory_iterator(steamworks_dir)) {
|
for (const auto& entry : fs::directory_iterator(steamworks_dir)) {
|
||||||
if (not entry.is_directory()) {
|
if (not entry.is_directory()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_sdk(entry.path(), lookup);
|
parse_sdk(entry.path(), lookup, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for all tasks to finish
|
||||||
|
pool.wait();
|
||||||
|
|
||||||
std::ofstream lookup_output("interface_lookup.json");
|
std::ofstream lookup_output("interface_lookup.json");
|
||||||
lookup_output << std::setw(4) << lookup << std::endl;
|
lookup_output << std::setw(4) << lookup << std::endl;
|
||||||
}
|
}
|
||||||
@@ -198,15 +167,22 @@ namespace {
|
|||||||
*/
|
*/
|
||||||
int main() {
|
int main() {
|
||||||
try {
|
try {
|
||||||
|
koalabox::logger::init_console_logger();
|
||||||
|
|
||||||
const auto steamworks_dir = fs::path("steamworks");
|
const auto steamworks_dir = fs::path("steamworks");
|
||||||
|
|
||||||
if (!fs::exists(steamworks_dir)) {
|
if (!fs::exists(steamworks_dir)) {
|
||||||
throw std::exception("Expected to find 'steamworks' in current working directory.");
|
throw std::exception("Expected to find 'steamworks' in current working directory.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto start = std::chrono::steady_clock::now();
|
||||||
generate_lookup_json(steamworks_dir);
|
generate_lookup_json(steamworks_dir);
|
||||||
|
const auto end = std::chrono::steady_clock::now();
|
||||||
|
const auto elapsed = duration_cast<std::chrono::seconds>(end - start);
|
||||||
|
|
||||||
|
LOG_INFO("Finished parsing steamworks in {} seconds", elapsed.count());
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
LOG_CRITICAL("Error: {}", e.what());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user