enderalse/source/fs.dll/skse64/skse64_common/Utilities.h

203 lines
10 KiB
C
Raw Normal View History

2021-10-06 00:45:46 +00:00
#pragma once
#include "skse64_common/Relocation.h"
// this has been tested to work for non-varargs functions
// varargs functions end up with 'this' passed as the last parameter (ie. probably broken)
// do NOT use with classes that have multiple inheritance
// if many member functions are to be declared, use MEMBER_FN_PREFIX to create a type with a known name
// so it doesn't need to be restated throughout the member list
// all of the weirdness with the _GetType function is because you can't declare a static const pointer
// inside the class definition. we sadly can't inline anymore because of relocation.
// RelocPtr only works at a global scope, which we can't handle or we'd be bypassing the function route altogether
#define MEMBER_FN_PREFIX(className) \
typedef className _MEMBER_FN_BASE_TYPE
#define DEFINE_MEMBER_FN_LONG(className, functionName, retnType, address, ...) \
typedef retnType (className::* _##functionName##_type)(__VA_ARGS__); \
\
static const std::uintptr_t functionName##_Address = address; \
inline _##functionName##_type * _##functionName##_GetPtr(void) \
{ \
static uintptr_t _address; \
_address = address + RelocationManager::s_baseAddr; \
return (_##functionName##_type *)&_address; \
}
#define DEFINE_MEMBER_FN(functionName, retnType, address, ...) \
DEFINE_MEMBER_FN_LONG(_MEMBER_FN_BASE_TYPE, functionName, retnType, address, __VA_ARGS__)
#define DEFINE_STATIC_HEAP(staticAllocate, staticFree) \
static void * operator new(std::size_t size) \
{ \
return staticAllocate(size); \
} \
static void * operator new(std::size_t size, const std::nothrow_t &) \
{ \
return staticAllocate(size); \
} \
static void * operator new(std::size_t size, void * ptr) \
{ \
return ptr; \
} \
static void operator delete(void * ptr) \
{ \
staticFree(ptr); \
} \
static void operator delete(void * ptr, const std::nothrow_t &) \
{ \
staticFree(ptr); \
} \
static void operator delete(void *, void *) \
{ \
}
#define CALL_MEMBER_FN(obj, fn) \
((*(obj)).*(*((obj)->_##fn##_GetPtr())))
// Using the original implementation does very broken things in a Release build
#define FORCE_INLINE __forceinline
#define DEFINE_MEMBER_FN_0(fnName, retnType, addr) \
static const std::uintptr_t fnName##_Address = addr; \
FORCE_INLINE retnType fnName() { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(); \
}
#define DEFINE_MEMBER_FN_1(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1> \
FORCE_INLINE retnType fnName(T1 && t1) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1); \
}
#define DEFINE_MEMBER_FN_2(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2); \
}
#define DEFINE_MEMBER_FN_3(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3); \
}
#define DEFINE_MEMBER_FN_4(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4); \
}
#define DEFINE_MEMBER_FN_5(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4, typename T5> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4, T5 && t5) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4, t5); \
}
#define DEFINE_MEMBER_FN_6(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4, T5 && t5, T6 && t6) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4, t5, t6); \
}
#define DEFINE_MEMBER_FN_7(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4, T5 && t5, T6 && t6, T7 && t7) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4, t5, t6, t7); \
}
#define DEFINE_MEMBER_FN_8(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4, T5 && t5, T6 && t6, T7 && t7, T8 && t8) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4, t5, t6, t7, t8); \
}
#define DEFINE_MEMBER_FN_9(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4, T5 && t5, T6 && t6, T7 && t7, T8 && t8, T9 && t9) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4, t5, t6, t7, t8, t9); \
}
#define DEFINE_MEMBER_FN_10(fnName, retnType, addr, ...) \
static const std::uintptr_t fnName##_Address = addr; \
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10> \
FORCE_INLINE retnType fnName(T1 && t1, T2 && t2, T3 && t3, T4 && t4, T5 && t5, T6 && t6, T7 && t7, T8 && t8, T9 && t9, T10 && t10) { \
struct empty_struct {}; \
typedef retnType(empty_struct::*_##fnName##_type)(__VA_ARGS__); \
const static uintptr_t address = fnName##_Address + RelocationManager::s_baseAddr; \
_##fnName##_type fn = *(_##fnName##_type*)&address; \
return (reinterpret_cast<empty_struct*>(this)->*fn)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
}
// this is the solution to getting a pointer-to-member-function pointer
template <typename T>
uintptr_t GetFnAddr(T src)
{
union
{
uintptr_t u;
T t;
} data;
data.t = src;
return data.u;
}
std::string GetRuntimePath();
std::string GetRuntimeName();
const std::string & GetRuntimeDirectory();
const std::string & GetConfigPath();
std::string GetConfigOption(const char * section, const char * key);
bool GetConfigOption_UInt32(const char * section, const char * key, UInt32 * dataOut);
const std::string & GetOSInfoStr();
void * GetIATAddr(void * module, const char * searchDllName, const char * searchImportName);
const char * GetObjectClassName(void * objBase);
void DumpClass(void * theClassPtr, UInt64 nIntsToDump);