make mods work without getting tuliphook link errors

This commit is contained in:
HJfod 2023-01-23 21:58:50 +02:00
parent 53296bbb5e
commit b9dfd1b115
8 changed files with 75 additions and 19 deletions

View file

@ -123,7 +123,7 @@ CPMAddPackage("gh:fmtlib/fmt#9.1.0")
CPMAddPackage("gh:gulrak/filesystem#3e5b930")
# Tulip hook (hooking)
CPMAddPackage("gh:geode-sdk/TulipHook#9980bcf")
CPMAddPackage("gh:geode-sdk/TulipHook#b67c3d4")
target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt TulipHookInclude GeodeCodegenSources)

View file

@ -132,7 +132,7 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single
fmt::arg("pure_index", bank.getPure(*begin, c.name)),
fmt::arg("class_name", c.name),
fmt::arg("function_name", begin->name),
fmt::arg("function_convention", codegen::getModifyConvention(f)),
fmt::arg("function_convention", codegen::getModifyConventionName(f)),
fmt::arg("parameter_types", fmt::join(func.parameter_types, ", "))
);
}

View file

@ -187,6 +187,27 @@ namespace codegen {
else throw codegen::error("Tried to get convention of non-function");
}
inline std::string getModifyConventionName(Field& f) {
if (codegen::platform != Platform::Windows) return "Default";
if (auto fn = f.get_fn()) {
auto status = getStatus(f);
if (fn->is_static) {
if (status == BindStatus::Binded) return "Cdecl";
else return "Optcall";
}
else if (fn->is_virtual) {
return "Thiscall";
}
else {
if (status == BindStatus::Binded) return "Thiscall";
else return "Membercall";
}
}
else throw codegen::error("Tried to get convention of non-function");
}
inline std::string getUnqualifiedClassName(std::string const& s) {
auto index = s.rfind("::");
if (index == std::string::npos) return s;

View file

@ -8,7 +8,7 @@ namespace { namespace format_strings {
#include <Geode/utils/addresser.hpp>
#include <Geode/modify/Addresses.hpp>
#include <Geode/modify/Traits.hpp>
#include <tulip/TulipHook.hpp>
#include <Geode/loader/Loader.hpp>
using namespace geode;
using namespace geode::modifier;
@ -30,7 +30,7 @@ CCDestructor::~CCDestructor() {{
}}
auto wrapFunction(uintptr_t address, tulip::hook::WrapperMetadata const& metadata) {
auto wrapped = tulip::hook::createWrapper(reinterpret_cast<void*>(address), metadata);
auto wrapped = Loader::get()->createWrapper(reinterpret_cast<void*>(address), metadata);
if (wrapped.isErr()) {{
throw std::runtime_error(wrapped.unwrapErr());
}}
@ -42,7 +42,7 @@ auto wrapFunction(uintptr_t address, tulip::hook::WrapperMetadata const& metadat
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
using FunctionType = decltype({function_name}({arguments}))(*)({class_name}{const}*{parameter_comma}{parameter_types});
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
.m_convention = std::make_shared<{convention}>(),
.m_convention = Loader::get()->createConvention(tulip::hook::TulipConvention::{convention}),
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
}});
return reinterpret_cast<FunctionType>(func)(this{parameter_comma}{arguments});
@ -54,7 +54,7 @@ auto {class_name}::{function_name}({parameters}){const} -> decltype({function_na
auto self = addresser::thunkAdjust(Resolve<{parameter_types}>::func(&{class_name}::{function_name}), this);
using FunctionType = decltype({function_name}({arguments}))(*)({class_name}{const}*{parameter_comma}{parameter_types});
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
.m_convention = std::make_shared<{convention}>(),
.m_convention = Loader::get()->createConvention(tulip::hook::TulipConvention::{convention}),
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
}});
return reinterpret_cast<FunctionType>(func)(self{parameter_comma}{arguments});
@ -65,7 +65,7 @@ auto {class_name}::{function_name}({parameters}){const} -> decltype({function_na
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
using FunctionType = decltype({function_name}({arguments}))(*)({parameter_types});
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
.m_convention = std::make_shared<{convention}>(),
.m_convention = Loader::get()->createConvention(tulip::hook::TulipConvention::{convention}),
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
}});
return reinterpret_cast<FunctionType>(func)({arguments});
@ -79,7 +79,7 @@ auto {class_name}::{function_name}({parameters}){const} -> decltype({function_na
if (CCDestructor::lock(this)) return;
using FunctionType = void(*)({class_name}*{parameter_comma}{parameter_types});
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
.m_convention = std::make_shared<{convention}>(),
.m_convention = Loader::get()->createConvention(tulip::hook::TulipConvention::{convention}),
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
}});
reinterpret_cast<FunctionType>(func)(this{parameter_comma}{arguments});
@ -99,7 +99,7 @@ auto {class_name}::{function_name}({parameters}){const} -> decltype({function_na
{class_name}::~{unqualified_class_name}();
using FunctionType = void(*)({class_name}*{parameter_comma}{parameter_types});
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
.m_convention = std::make_shared<{convention}>(),
.m_convention = Loader::get()->createConvention(tulip::hook::TulipConvention::{convention}),
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
}});
reinterpret_cast<FunctionType>(func)(this{parameter_comma}{arguments});
@ -190,7 +190,7 @@ std::string generateBindingSource(Root& root) {
fmt::arg("class_name", c.name),
fmt::arg("unqualified_class_name", codegen::getUnqualifiedClassName(c.name)),
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
fmt::arg("convention", codegen::getModifyConvention(f)),
fmt::arg("convention", codegen::getModifyConventionName(f)),
fmt::arg("function_name", fn->beginning.name),
fmt::arg("meta_index", ids.meta),
fmt::arg("member_index", ids.member),

View file

@ -50,16 +50,17 @@ namespace geode {
tulip::hook::HookMetadata const& hookMetadata
);
template <class Convention, class DetourType>
template <class DetourType>
static Hook* create(
Mod* owner,
void* address,
DetourType detour,
std::string const& displayName,
tulip::hook::TulipConvention convention,
tulip::hook::HookMetadata const& hookMetadata = tulip::hook::HookMetadata()
) {
auto handlerMetadata = tulip::hook::HandlerMetadata{
.m_convention = std::make_shared<Convention>(),
.m_convention = Loader::get()->createConvention(convention),
.m_abstract = tulip::hook::AbstractFunction::from(detour)
};
return Hook::create(

View file

@ -5,6 +5,7 @@
#include "Log.hpp"
#include "ModInfo.hpp"
#include "Types.hpp"
#include <tulip/TulipHook.hpp>
#include <atomic>
#include <mutex>
@ -79,6 +80,20 @@ namespace geode {
bool didLastLaunchCrash() const;
/**
* Create a calling convention wrapper for a function.
*/
Result<void*> createWrapper(
void* address,
tulip::hook::WrapperMetadata const& metadata
) noexcept;
/**
* Create an abstract calling convention handler for TulipHook
*/
std::shared_ptr<tulip::hook::CallingConvention> createConvention(
tulip::hook::TulipConvention convention
) noexcept;
friend class LoaderImpl;
friend Mod* takeNextLoaderMod();

View file

@ -14,11 +14,12 @@
constexpr auto b = Resolve<__VA_ARGS__>::func(&Base::FunctionName_); \
constexpr auto d = Resolve<__VA_ARGS__>::func(&Derived::FunctionName_); \
if constexpr (Unique::different<b, d>()) { \
auto hook = Hook::create<Convention_>( \
auto hook = Hook::create( \
Mod::get(), \
reinterpret_cast<void*>(address<AddressIndex_>()), \
AsStaticFunction_##FunctionName_<Derived, d>::value, \
#ClassName_ "::" #FunctionName_ \
#ClassName_ "::" #FunctionName_, \
tulip::hook::TulipConvention::Convention_ \
); \
this->m_hooks[#ClassName_ "::" #FunctionName_] = hook; \
} \
@ -28,11 +29,12 @@
do { \
if constexpr (HasConstructor<Derived>) { \
constexpr auto d = Resolve<__VA_ARGS__>::func(&Derived::constructor); \
auto hook = Hook::create<Convention_>( \
auto hook = Hook::create( \
Mod::get(), \
reinterpret_cast<void*>(address<AddressIndex_>()), \
AsStaticFunction_##constructor<Derived, d>::value, \
#ClassName_ "::" #ClassName_ \
#ClassName_ "::" #ClassName_, \
tulip::hook::TulipConvention::Convention_ \
); \
this->m_hooks[#ClassName_ "::" #ClassName_] = hook; \
} \
@ -42,11 +44,12 @@
do { \
if constexpr (HasDestructor<Derived>) { \
constexpr auto d = Resolve<>::func(&Derived::destructor); \
auto hook = Hook::create<Convention_>( \
auto hook = Hook::create( \
Mod::get(), \
reinterpret_cast<void*>(address<AddressIndex_>()), \
AsStaticFunction_##destructor<Derived, d>::value, \
#ClassName_ "::" #ClassName_ \
#ClassName_ "::" #ClassName_, \
tulip::hook::TulipConvention::Convention_ \
); \
this->m_hooks[#ClassName_ "::" #ClassName_] = hook; \
} \

View file

@ -121,4 +121,20 @@ bool Loader::didLastLaunchCrash() const {
Mod* Loader::takeNextMod() {
return m_impl->takeNextMod();
}
}
Result<void*> Loader::createWrapper(void* address, tulip::hook::WrapperMetadata const& metadata) noexcept {
auto res = tulip::hook::createWrapper(address, metadata);
if (res) {
return Ok(res.unwrap());
}
else {
return Err(res.unwrapErr());
}
}
std::shared_ptr<tulip::hook::CallingConvention> Loader::createConvention(
tulip::hook::TulipConvention convention
) noexcept {
return tulip::hook::createConvention(convention);
}