mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2025-12-05 21:15:39 -05:00
Refactored types
This commit is contained in:
@@ -28,6 +28,7 @@ set(SMOKE_API_STATIC_SOURCES
|
||||
static/smoke_api/config.cpp
|
||||
static/smoke_api/types.hpp
|
||||
static/smoke_api/types.cpp
|
||||
static/smoke_api/steamclient/steamclient.hpp
|
||||
)
|
||||
|
||||
set(SMOKE_API_SOURCES
|
||||
@@ -45,8 +46,7 @@ set(SMOKE_API_SOURCES
|
||||
src/steam_api/steam_client.cpp
|
||||
src/steam_api/steam_interface.cpp
|
||||
src/steam_api/steam_interface.hpp
|
||||
src/steamclient/steamclient.cpp
|
||||
src/steamclient/steamclient.hpp
|
||||
src/steamclient.cpp
|
||||
src/main.cpp
|
||||
src/smoke_api.cpp
|
||||
src/smoke_api.hpp
|
||||
@@ -62,7 +62,7 @@ add_library(SmokeAPI_interface INTERFACE)
|
||||
#target_compile_options(SmokeAPI_interface PUBLIC /std:c++latest)
|
||||
|
||||
target_include_directories(SmokeAPI_interface INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/static>"
|
||||
)
|
||||
target_link_libraries(SmokeAPI_interface INTERFACE KoalaBox $<TARGET_OBJECTS:KoalaBox>)
|
||||
|
||||
@@ -71,7 +71,7 @@ target_link_libraries(SmokeAPI_interface INTERFACE KoalaBox $<TARGET_OBJECTS:Koa
|
||||
|
||||
add_library(SmokeAPI_static STATIC ${SMOKE_API_STATIC_SOURCES})
|
||||
target_link_libraries(SmokeAPI_static PUBLIC SmokeAPI_interface)
|
||||
target_include_directories(SmokeAPI_static PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/static")
|
||||
#target_include_directories(SmokeAPI_static PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/static")
|
||||
|
||||
### Shared SmokeAPI
|
||||
|
||||
@@ -81,11 +81,13 @@ set_target_properties(SmokeAPI PROPERTIES RUNTIME_OUTPUT_NAME ${STEAMAPI_DLL})
|
||||
configure_version_resource(SmokeAPI "Free DLC for everyone ʕ ᵔᴥᵔʔ")
|
||||
target_include_directories(SmokeAPI PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/static"
|
||||
# "${CMAKE_CURRENT_SOURCE_DIR}/static"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
set(B_PRODUCTION_MODE ON)
|
||||
CPMAddPackage("gh:batterycenter/embed@1.2.19")
|
||||
CPMAddPackage(
|
||||
URI "gh:batterycenter/embed@1.2.19"
|
||||
OPTIONS "B_PRODUCTION_MODE ON"
|
||||
)
|
||||
b_embed(SmokeAPI "res/interface_lookup.json")
|
||||
|
||||
configure_linker_exports(
|
||||
|
||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: 06fa5304b3...4f842f27a2
@@ -113,7 +113,7 @@ In this case you can use a configuration file link:res/SmokeAPI.config.json[Smok
|
||||
To use it, simply place it next to the SmokeAPI DLL.
|
||||
It will be read upon each launch of the game.
|
||||
In the absence of the config file, default values specified below will be used.
|
||||
The configuration file is expected to conform to the Json standard.
|
||||
The configuration file is expected to conform to the JSON standard.
|
||||
|
||||
`logging`:: Toggles generation of a `SmokeAPI.log.log` file.
|
||||
+
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Building from source
|
||||
|
||||
TODO
|
||||
@@ -1,3 +0,0 @@
|
||||
# Tools
|
||||
|
||||
TODO: describe steamworks_downloader and steamworks_parser tools
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/heads/master/res/SmokeAPI.schema.json",
|
||||
"$version": 3,
|
||||
"logging": true,
|
||||
"default_app_status": "unlocked",
|
||||
|
||||
145
res/SmokeAPI.schema.json
Normal file
145
res/SmokeAPI.schema.json
Normal file
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://example.com/smokeapi-config.schema.json",
|
||||
"title": "SmokeAPI configuration",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$version": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 3,
|
||||
"description": "A technical field reserved for tools like GUI config editors. Do not modify this value."
|
||||
},
|
||||
"logging": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Toggles generation of a SmokeAPI.log.log file."
|
||||
},
|
||||
"default_app_status": {
|
||||
"description": "Sets the default DLC unlocking behaviour.",
|
||||
"default": "unlocked",
|
||||
"$ref": "#/$defs/AppStatus"
|
||||
},
|
||||
"override_app_id": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"description": "Overrides the current app ID (0 means no override)."
|
||||
},
|
||||
"override_app_status": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"description": "Overrides the status of all DLCs that belong to a specified app ID. Keys are app IDs (as strings).",
|
||||
"patternProperties": {
|
||||
"^\\d{1,10}$": {
|
||||
"$ref": "#/$defs/AppStatus"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"override_dlc_status": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"description": "Overrides the status of individual DLCs, regardless of the corresponding app status. Keys are DLC IDs (as strings).",
|
||||
"patternProperties": {
|
||||
"^\\d{1,10}$": {
|
||||
"$ref": "#/$defs/AppStatus"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"extra_dlcs": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"description": "Map of app IDs to objects containing DLC IDs with their display names.",
|
||||
"patternProperties": {
|
||||
"^\\d{1,10}$": {
|
||||
"$ref": "#/$defs/App"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"auto_inject_inventory": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether SmokeAPI should automatically inject a list of all registered inventory items when a game queries user inventory."
|
||||
},
|
||||
"extra_inventory_items": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"description": "A list of inventory item IDs that will be added in addition to the automatically injected items.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"AppStatus": {
|
||||
"description": "Unlock status for apps or DLCs.",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"original",
|
||||
"unlocked",
|
||||
"locked"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"description": "Represents UNDEFINED in the enum."
|
||||
}
|
||||
]
|
||||
},
|
||||
"App": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"dlcs": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"description": "Map of DLC IDs to human-readable DLC names.",
|
||||
"patternProperties": {
|
||||
"^\\d{1,10}$": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"$version": 3,
|
||||
"logging": true,
|
||||
"default_app_status": "unlocked",
|
||||
"override_app_status": {
|
||||
"1234": "original",
|
||||
"4321": "unlocked"
|
||||
},
|
||||
"override_dlc_status": {
|
||||
"1234": "original",
|
||||
"4321": "unlocked",
|
||||
"5678": "locked"
|
||||
},
|
||||
"auto_inject_inventory": true,
|
||||
"extra_inventory_items": [],
|
||||
"extra_dlcs": {
|
||||
"1234": {
|
||||
"dlcs": {
|
||||
"56789": "Example DLC 1"
|
||||
}
|
||||
},
|
||||
"4321": {
|
||||
"dlcs": {
|
||||
"98765": "Example DLC 2",
|
||||
"98766": "Example DLC 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/config.hpp"
|
||||
#include "steamclient/steamclient.hpp"
|
||||
#include "smoke_api/steamclient/steamclient.hpp"
|
||||
|
||||
// Hooking steam_api has shown itself to be less desirable than steamclient
|
||||
// for the reasons outlined below:
|
||||
|
||||
@@ -20,13 +20,6 @@ constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
|
||||
#define MODULE_CALL_CLOSURE(FUNC, ...) \
|
||||
[&] { MODULE_CALL(FUNC, __VA_ARGS__); }
|
||||
|
||||
#define HOOKED_CALL(FUNC, ...) \
|
||||
static const auto _##FUNC = KB_HOOK_GET_HOOKED_FN(smoke_api::steamapi_module, FUNC); \
|
||||
return _##FUNC(__VA_ARGS__)
|
||||
|
||||
#define HOOKED_CALL_CLOSURE(FUNC, ...) \
|
||||
[&] { HOOKED_CALL(FUNC, __VA_ARGS__); }
|
||||
|
||||
namespace smoke_api {
|
||||
extern HMODULE steamapi_module;
|
||||
|
||||
|
||||
@@ -2,41 +2,6 @@
|
||||
|
||||
#include "smoke_api/types.hpp"
|
||||
|
||||
/**
|
||||
* By default, virtual functions are declared with __thiscall
|
||||
* convention, which is normal since they are class members.
|
||||
* But it presents an issue for us, since we cannot pass *this
|
||||
* pointer as a function argument. This is because *this
|
||||
* pointer is passed via register ECX in __thiscall
|
||||
* convention. Hence, to resolve this issue we declare our
|
||||
* hooked functions with __fastcall convention, to trick
|
||||
* the compiler into reading ECX & EDX registers as 1st
|
||||
* and 2nd function arguments respectively. Similarly, __fastcall
|
||||
* makes the compiler push the first argument into the ECX register,
|
||||
* which mimics the __thiscall calling convention. Register EDX
|
||||
* is not used anywhere in this case, but we still pass it along
|
||||
* to conform to the __fastcall convention. This all applies
|
||||
* to the x86 architecture.
|
||||
*
|
||||
* In x86-64 however, there is only one calling convention,
|
||||
* so __fastcall is simply ignored. However, RDX in this case
|
||||
* will store the 1st actual argument to the function, so we
|
||||
* have to omit it from the function signature.
|
||||
*
|
||||
* The macros below implement the above-mentioned considerations.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
#define PARAMS(...) void *RCX, __VA_ARGS__
|
||||
#define ARGS(...) RCX, __VA_ARGS__
|
||||
#define THIS RCX
|
||||
#else
|
||||
#define PARAMS(...) const void *ECX, const void *EDX, __VA_ARGS__
|
||||
#define ARGS(...) ECX, EDX, __VA_ARGS__
|
||||
#define THIS ECX
|
||||
#endif
|
||||
|
||||
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall // NOLINT(*-macro-parentheses)
|
||||
|
||||
// ISteamApps
|
||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t));
|
||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t));
|
||||
|
||||
16
src/steamclient.cpp
Normal file
16
src/steamclient.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "smoke_api/steamclient/steamclient.hpp"
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/types.hpp"
|
||||
|
||||
#include "steam_api/steam_client.hpp"
|
||||
|
||||
/**
|
||||
* SmokeAPI implementation
|
||||
*/
|
||||
C_DECL(void*) CreateInterface(const char* interface_version, int* out_result) {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
interface_version,
|
||||
HOOKED_CALL_CLOSURE(CreateInterface, interface_version, out_result)
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#include <koalabox/hook.hpp>
|
||||
|
||||
#include "steamclient.hpp"
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/types.hpp"
|
||||
#include "steam_api/steam_client.hpp"
|
||||
|
||||
C_DECL(void*) CreateInterface(const char* interface_string, int* out_result) {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
interface_string,
|
||||
HOOKED_CALL_CLOSURE(CreateInterface, interface_string, out_result)
|
||||
);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define C_DECL(TYPE) extern "C" __declspec(noinline) TYPE __cdecl
|
||||
|
||||
C_DECL(void*) CreateInterface(const char* interface_string, int* out_result);
|
||||
@@ -23,7 +23,7 @@ namespace smoke_api::config {
|
||||
)
|
||||
|
||||
struct Config {
|
||||
uint32_t $version = 2;
|
||||
uint32_t $version = 3;
|
||||
bool logging = false;
|
||||
AppStatus default_app_status = AppStatus::UNLOCKED;
|
||||
uint32_t override_app_id = 0;
|
||||
|
||||
@@ -64,11 +64,11 @@ namespace smoke_api::steam_inventory {
|
||||
);
|
||||
|
||||
static uint32_t original_count = 0;
|
||||
const auto injected_count = smoke_api::config::instance.extra_inventory_items.size();
|
||||
const auto injected_count = config::instance.extra_inventory_items.size();
|
||||
|
||||
// Automatically get inventory items from steam
|
||||
static std::vector<SteamItemDef_t> auto_inventory_items;
|
||||
if(smoke_api::config::instance.auto_inject_inventory) {
|
||||
if(config::instance.auto_inject_inventory) {
|
||||
static std::once_flag inventory_inject_flag;
|
||||
std::call_once(
|
||||
inventory_inject_flag,
|
||||
@@ -120,7 +120,7 @@ namespace smoke_api::steam_inventory {
|
||||
|
||||
for(int i = 0; i < injected_count; i++) {
|
||||
auto& item = pOutItemsArray[original_count + auto_injected_count + i];
|
||||
const auto item_def_id = smoke_api::config::instance.extra_inventory_items[i];
|
||||
const auto item_def_id = config::instance.extra_inventory_items[i];
|
||||
|
||||
item = new_item(item_def_id);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace smoke_api::steam_user {
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto has_license = smoke_api::config::is_dlc_unlocked(
|
||||
const auto has_license = config::is_dlc_unlocked(
|
||||
appId,
|
||||
dlcId,
|
||||
[&] {
|
||||
|
||||
5
static/smoke_api/steamclient/steamclient.hpp
Normal file
5
static/smoke_api/steamclient/steamclient.hpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "smoke_api/types.hpp"
|
||||
|
||||
C_DECL(void*) CreateInterface(const char* interface_version, int* out_result);
|
||||
@@ -6,12 +6,52 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
// TODO: Replace with direct call
|
||||
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
|
||||
static const auto FUNC##_o = koalabox::hook::get_original_hooked_function(#FUNC, FUNC);
|
||||
#include <koalabox/hook.hpp>
|
||||
|
||||
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
|
||||
koalabox::hook::detour_or_warn(ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
|
||||
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall // NOLINT(*-macro-parentheses)
|
||||
#define C_DECL(TYPE) extern "C" __declspec(noinline) TYPE __cdecl
|
||||
|
||||
// These macros are meant to be used for callbacks that should return original result
|
||||
|
||||
#define HOOKED_CALL(FUNC, ...) \
|
||||
static const auto _##FUNC = KB_HOOK_GET_HOOKED_FN(FUNC); \
|
||||
return _##FUNC(__VA_ARGS__)
|
||||
|
||||
#define HOOKED_CALL_CLOSURE(FUNC, ...) \
|
||||
[&] { HOOKED_CALL(FUNC, __VA_ARGS__); }
|
||||
|
||||
/**
|
||||
* By default, virtual functions are declared with __thiscall
|
||||
* convention, which is normal since they are class members.
|
||||
* But it presents an issue for us, since we cannot pass *this
|
||||
* pointer as a function argument. This is because *this
|
||||
* pointer is passed via register ECX in __thiscall
|
||||
* convention. Hence, to resolve this issue we declare virtual
|
||||
* hooked functions with __fastcall convention, to trick
|
||||
* the compiler into reading ECX & EDX registers as 1st
|
||||
* and 2nd function arguments respectively. Similarly, __fastcall
|
||||
* makes the compiler push the first argument into the ECX register,
|
||||
* which mimics the __thiscall calling convention. Register EDX
|
||||
* is not used anywhere in this case, but we still pass it along
|
||||
* to conform to the __fastcall convention. This all applies
|
||||
* to the x86 architecture.
|
||||
*
|
||||
* In x86-64 however, there is only one calling convention,
|
||||
* so __fastcall is simply ignored. However, RDX in this case
|
||||
* will store the 1st actual argument to the function, so we
|
||||
* have to omit it from the function signature.
|
||||
*
|
||||
* The macros below implement the above-mentioned considerations.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
#define PARAMS(...) const void *RCX, __VA_ARGS__
|
||||
#define ARGS(...) RCX, __VA_ARGS__
|
||||
#define THIS RCX
|
||||
#else
|
||||
#define PARAMS(...) const void *ECX, const void *EDX, __VA_ARGS__
|
||||
#define ARGS(...) ECX, EDX, __VA_ARGS__
|
||||
#define THIS ECX
|
||||
#endif
|
||||
|
||||
using AppId_t = uint32_t;
|
||||
using HSteamPipe = uint32_t;
|
||||
@@ -80,4 +120,4 @@ public:
|
||||
static std::vector<DLC> get_dlcs_from_apps(const AppDlcNameMap& apps, AppId_t app_id);
|
||||
|
||||
static DlcNameMap get_dlc_map_from_vector(const std::vector<DLC>& dlcs);
|
||||
};
|
||||
};
|
||||
|
||||
13
tools/README.md
Normal file
13
tools/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# SmokeAPI tools
|
||||
|
||||
## Steamworks Downloader
|
||||
|
||||
A simple tool for downloading Steamworks SDK archive from the public GitHub repository
|
||||
[cdn](https://github.com/acidicoala/cdn/tree/main/valve)
|
||||
and unzipping headers and binaries into the main project for subsequent processing.
|
||||
|
||||
## Steamworks Parser
|
||||
|
||||
A more sophisticated tool that parses Steamworks SDK C++ headers
|
||||
in order to build an [interface lookup map](../res/interface_lookup.json),
|
||||
which is used by SmokeAPI to lookup function ordinals for specific interface versions.
|
||||
Reference in New Issue
Block a user