You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SmokeAPI/src/koalageddon/vstdlib.cpp

100 lines
3.3 KiB
C++

#include <smoke_api/smoke_api.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalageddon/koalageddon.hpp>
#include <koalabox/hook.hpp>
using namespace smoke_api;
typedef uint32_t HCoroutine;
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data);
namespace koalageddon {
void init_vstdlib_hooks() {
DETOUR_ORIGINAL(Coroutine_Create)
}
}
VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters)
logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg));
return true;
}
VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters)
logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg));
return true;
}
struct CallbackData {
FunctionAddress get_callback_intercept_address() {
return reinterpret_cast<FunctionAddress*>(this)[koalageddon::config.vstdlib_callback_interceptor_address_offset];
}
FunctionAddress get_callback_address() {
return reinterpret_cast<FunctionAddress*>(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];
}
};
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** p_name)) {
GET_ORIGINAL_FUNCTION(VStdLib_Callback_Interceptor)
VStdLib_Callback_Interceptor_o(ARGS(p_name));
static auto hooked_functions = 0;
if (hooked_functions == 2) {
return;
}
auto* const data = (CoroutineData*) THIS;
if (data && data->get_callback_name()) {
const auto name = String(data->get_callback_name());
// logger->trace("{} -> instance: {}, name: '{}'", __func__, fmt::ptr(THIS), name);
if (name == "SharedLicensesLockStatus") {
static std::once_flag flag;
std::call_once(flag, [&]() {
DETOUR(SharedLicensesLockStatus, data->get_callback_data()->get_callback_address())
hooked_functions++;
});
} else if (name == "SharedLibraryStopPlaying") {
static std::once_flag flag;
std::call_once(flag, [&]() {
DETOUR(SharedLibraryStopPlaying, data->get_callback_data()->get_callback_address())
hooked_functions++;
});
}
}
}
/**
* Initially, callback data passed into this function is not complete,
* hence we must hook an interface method that sets the callback name.
*/
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) {
GET_ORIGINAL_FUNCTION(Coroutine_Create)
const auto result = Coroutine_Create_o(callback_address, data);
// Coroutine callback appears to be always the same
static std::once_flag flag;
std::call_once(flag, [&]() {
logger->debug("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data));
DETOUR(VStdLib_Callback_Interceptor, data->get_callback_data()->get_callback_intercept_address())
});
return result;
}