mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-06 18:08:36 +00:00
Add gamedata parser
This commit is contained in:
parent
600e07fafb
commit
fff6f07ae3
@ -6,7 +6,10 @@ sources = [
|
||||
'src/globals.cpp',
|
||||
'src/handle.cpp',
|
||||
'src/register.cpp',
|
||||
'src/natives/dhookparam.cpp'
|
||||
'src/signatures.cpp',
|
||||
'src/sp_inc.cpp',
|
||||
'src/natives/dhookparam.cpp',
|
||||
'src/natives/dhookreturn.cpp'
|
||||
]
|
||||
|
||||
for cxx in builder.targets:
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "globals.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "hook.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#if defined(DHOOKS_X86_64)
|
||||
#include <khook/asm/x86_64.hpp>
|
||||
@ -27,53 +28,6 @@ using AsmJit = KHook::Asm::x86_64_Jit;
|
||||
using AsmJit = KHook::Asm::x86_Jit;
|
||||
#endif
|
||||
|
||||
struct Variable {
|
||||
public:
|
||||
enum Alignment {
|
||||
OneByte = 1,
|
||||
TwoBytes = 2,
|
||||
FourBytes = 4,
|
||||
EightBytes = 8,
|
||||
SixteenBytes = 16
|
||||
};
|
||||
|
||||
sp::HookParamType dhook_type;
|
||||
size_t dhook_size;
|
||||
sp::DHookPassFlag dhook_pass_flags;
|
||||
sp::DHookRegister dhook_custom_register;
|
||||
|
||||
// Provided by the ABI, used by the JIT
|
||||
// If DHook is to ever support complex type, transform those fields
|
||||
// into an array so that the SP natives know where to look when offsetting into an object
|
||||
std::optional<AsmRegCode> reg_index;
|
||||
std::optional<AsmFloatRegCode> float_reg_index;
|
||||
std::optional<size_t> reg_offset;
|
||||
Alignment alignment;
|
||||
// Atm it's exactly the same as _dhook_size
|
||||
// We differentiate it anyways, to avoid having to refactor the JIT
|
||||
size_t type_size;
|
||||
};
|
||||
|
||||
struct ReturnVariable {
|
||||
public:
|
||||
enum Alignment {
|
||||
OneByte = 1,
|
||||
TwoBytes = 2,
|
||||
FourBytes = 4,
|
||||
EightBytes = 8,
|
||||
SixteenBytes = 16
|
||||
};
|
||||
|
||||
sp::ReturnType dhook_type;
|
||||
size_t dhook_size;
|
||||
sp::DHookPassFlag dhook_pass_flags;
|
||||
sp::DHookRegister dhook_custom_register;
|
||||
|
||||
std::optional<AsmRegCode> reg_index;
|
||||
std::optional<AsmFloatRegCode> float_reg_index;
|
||||
size_t reg_offset;
|
||||
};
|
||||
|
||||
struct HookCallback;
|
||||
class Capsule {
|
||||
public:
|
||||
|
||||
@ -9,6 +9,10 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace dhooks {
|
||||
class SignatureGameConfig;
|
||||
};
|
||||
|
||||
namespace dhooks::globals {
|
||||
|
||||
extern std::thread::id main_thread;
|
||||
@ -17,6 +21,7 @@ extern SourceMod::IGameHelpers* gamehelpers;
|
||||
extern SourceMod::IExtension* myself;
|
||||
extern SourceMod::ISourceMod* sourcemod;
|
||||
extern std::vector<sp_nativeinfo_t> natives;
|
||||
extern dhooks::SignatureGameConfig* dhooks_config;
|
||||
|
||||
void init();
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
namespace dhooks::handle {
|
||||
|
||||
SourceMod::HandleType_t ParamReturn::HANDLE_TYPE = 0;
|
||||
SourceMod::HandleType_t HookSetup::VIRTUAL_HANDLE_TYPE = 0;
|
||||
SourceMod::HandleType_t HookSetup::ADDRESS_HANDLE_TYPE = 0;
|
||||
|
||||
ParamReturn::ParamReturn(const Capsule* capsule, GeneralRegister* generalregs, FloatRegister* floatregs, void* return_ptr) :
|
||||
_handle(globals::handlesys->CreateHandle(handle::ParamReturn::HANDLE_TYPE, this, globals::myself->GetIdentity(), globals::myself->GetIdentity(), nullptr)),
|
||||
@ -64,6 +66,8 @@ void init() {
|
||||
// Do not allow cloning, the struct self-manage its handle
|
||||
security.access[SourceMod::HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
|
||||
ParamReturn::HANDLE_TYPE = globals::handlesys->CreateType("DHookParamReturn", nullptr, 0, nullptr, &security, globals::myself->GetIdentity(), nullptr);
|
||||
HookSetup::VIRTUAL_HANDLE_TYPE = globals::handlesys->CreateType("DynamicHook", nullptr, 0, nullptr, &security, globals::myself->GetIdentity(), nullptr);
|
||||
HookSetup::ADDRESS_HANDLE_TYPE = globals::handlesys->CreateType("DynamicDetour", nullptr, 0, nullptr, &security, globals::myself->GetIdentity(), nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,10 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "register.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <IHandleSys.h>
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace dhooks {
|
||||
class Capsule;
|
||||
}
|
||||
@ -42,4 +46,23 @@ private:
|
||||
void* _return;
|
||||
};
|
||||
|
||||
class HookSetup {
|
||||
public:
|
||||
HookSetup(sp::ThisPointerType, sp::CallingConvention, void* address, const std::vector<Variable>& params, const ReturnVariable& ret);
|
||||
HookSetup(sp::ThisPointerType, std::uint32_t offset, const std::vector<Variable>& params, const ReturnVariable& ret);
|
||||
~HookSetup();
|
||||
|
||||
static SourceMod::HandleType_t VIRTUAL_HANDLE_TYPE;
|
||||
static SourceMod::HandleType_t ADDRESS_HANDLE_TYPE;
|
||||
private:
|
||||
cell_t _handle;
|
||||
std::optional<std::uint32_t> _virtual_offset;
|
||||
std::optional<void*> _address;
|
||||
|
||||
sp::ThisPointerType _this_pointer;
|
||||
sp::CallingConvention _dhook_call_conv;
|
||||
std::vector<Variable> _dhook_params;
|
||||
ReturnVariable _dhook_return;
|
||||
};
|
||||
|
||||
};
|
||||
@ -5,6 +5,14 @@
|
||||
|
||||
namespace dhooks::natives::dhookparam {
|
||||
|
||||
static void FreeChangedVector(void* data) {
|
||||
delete (sdk::Vector*)data;
|
||||
}
|
||||
|
||||
static void FreeChangedCharPtr(void* data) {
|
||||
delete[] (const char*)data;
|
||||
}
|
||||
|
||||
inline handle::ParamReturn* Get(SourcePawn::IPluginContext* context, const cell_t param) {
|
||||
SourceMod::HandleSecurity security;
|
||||
security.pOwner = globals::myself->GetIdentity();
|
||||
@ -33,175 +41,6 @@ inline cell_t GetParam(SourcePawn::IPluginContext* context, handle::ParamReturn*
|
||||
return index;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_GetReturn(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_Int:
|
||||
return *obj->GetReturn<int>();
|
||||
case sp::ReturnType_Bool:
|
||||
return (*obj->GetReturn<bool>()) ? 1 : 0;
|
||||
case sp::ReturnType_CBaseEntity:
|
||||
return globals::gamehelpers->EntityToBCompatRef(*obj->GetReturn<CBaseEntity*>());
|
||||
case sp::ReturnType_Edict:
|
||||
return globals::gamehelpers->IndexOfEdict(*obj->GetReturn<edict_t*>());
|
||||
case sp::ReturnType_Float:
|
||||
return sp_ftoc(*obj->GetReturn<float>());
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type (%i) to get", ret.dhook_type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_SetReturn(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_Int:
|
||||
*obj->GetReturn<int>() = params[2];
|
||||
break;
|
||||
case sp::ReturnType_Bool:
|
||||
*obj->GetReturn<bool>() = params[2] != 0;
|
||||
break;
|
||||
case sp::ReturnType_CBaseEntity: {
|
||||
CBaseEntity* entity = globals::gamehelpers->ReferenceToEntity(params[2]);
|
||||
if (entity == nullptr) {
|
||||
return context->ThrowNativeError("Invalid entity index passed for return value");
|
||||
}
|
||||
*obj->GetReturn<CBaseEntity*>() = entity;
|
||||
break;
|
||||
}
|
||||
case sp::ReturnType_Edict: {
|
||||
sdk::edict_t* edict = reinterpret_cast<sdk::edict_t*>(globals::gamehelpers->EdictOfIndex(params[2]));
|
||||
if (edict == nullptr || edict->IsFree()) {
|
||||
return context->ThrowNativeError("Invalid entity index passed for return value");
|
||||
}
|
||||
*obj->GetReturn<sdk::edict_t*>() = edict;
|
||||
break;
|
||||
}
|
||||
case sp::ReturnType_Float:
|
||||
*obj->GetReturn<float>() = sp_ctof(params[2]);
|
||||
break;
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type (%i) to get", ret.dhook_type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_GetReturnVector(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t *buffer;
|
||||
context->LocalToPhysAddr(params[2], &buffer);
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
|
||||
sdk::Vector* vector = nullptr;
|
||||
if (ret.dhook_type == sp::ReturnType_Vector) {
|
||||
vector = obj->GetReturn<sdk::Vector>();
|
||||
} else if(ret.dhook_type == sp::ReturnType_VectorPtr) {
|
||||
auto pvector = obj->GetReturn<sdk::Vector*>();
|
||||
if (*pvector == nullptr) {
|
||||
return context->ThrowNativeError("Vector pointer is null");
|
||||
}
|
||||
vector = *pvector;
|
||||
} else {
|
||||
return context->ThrowNativeError("Return type is not a vector type");
|
||||
}
|
||||
buffer[0] = sp_ftoc(vector->x);
|
||||
buffer[1] = sp_ftoc(vector->y);
|
||||
buffer[2] = sp_ftoc(vector->z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FreeChangedVector(void* data) {
|
||||
delete (sdk::Vector*)data;
|
||||
}
|
||||
cell_t DHookReturn_SetReturnVector(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t *buffer;
|
||||
context->LocalToPhysAddr(params[2], &buffer);
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
|
||||
if (ret.dhook_type == sp::ReturnType_Vector) {
|
||||
*(obj->GetReturn<sdk::Vector>()) = sdk::Vector(sp_ctof(buffer[0]), sp_ctof(buffer[1]), sp_ctof(buffer[2]));
|
||||
}
|
||||
else if (ret.dhook_type == sp::ReturnType_VectorPtr) {
|
||||
// Lazily free the vector a frame later
|
||||
auto vector = new sdk::Vector(sp_ctof(buffer[0]), sp_ctof(buffer[1]), sp_ctof(buffer[2]));
|
||||
*(obj->GetReturn<sdk::Vector*>()) = vector;
|
||||
globals::sourcemod->AddFrameAction(FreeChangedVector, vector);
|
||||
} else {
|
||||
return context->ThrowNativeError("Return type is not a vector type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_GetReturnString(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_String:
|
||||
context->StringToLocal(params[2], params[3], obj->GetReturn<sdk::string_t>()->ToCStr());
|
||||
return 1;
|
||||
case sp::ReturnType_StringPtr:
|
||||
context->StringToLocal(params[2], params[3], (obj->GetReturn<sdk::string_t*>() != nullptr) ? (*obj->GetReturn<sdk::string_t*>())->ToCStr() : "");
|
||||
return 1;
|
||||
case sp::ReturnType_CharPtr:
|
||||
context->StringToLocal(params[2], params[3], (*(obj->GetReturn<const char*>()) == nullptr) ? "" : *(obj->GetReturn<const char*>()));
|
||||
return 1;
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type to get. Param is not a string.");
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeChangedCharPtr(void* data) {
|
||||
delete[] (const char*)data;
|
||||
}
|
||||
cell_t DHookReturn_SetReturnString(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
|
||||
char *value;
|
||||
context->LocalToString(params[2], &value);
|
||||
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_CharPtr: {
|
||||
auto new_str = new char[strlen(value) + 1];
|
||||
strcpy(new_str, value);
|
||||
*(obj->GetReturn<const char*>()) = new_str;
|
||||
// Free it later (cheaply) after the function returned.
|
||||
globals::sourcemod->AddFrameAction(FreeChangedCharPtr, new_str);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type to get. Param is not a char pointer.");
|
||||
}
|
||||
}
|
||||
|
||||
cell_t DHookParam_GetParam(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
@ -703,19 +542,7 @@ void init(std::vector<sp_nativeinfo_t>& natives) {
|
||||
{"DHookParam.GetObjectVarVector", DHookParam_GetParamObjectPtrVarVector},
|
||||
{"DHookParam.SetObjectVarVector", DHookParam_SetParamObjectPtrVarVector},
|
||||
{"DHookParam.GetObjectVarString", DHookParam_GetParamObjectPtrString},
|
||||
{"DHookParam.IsNull", DHookParam_IsNullParam},
|
||||
{"DHookGetReturn", DHookReturn_GetReturn},
|
||||
{"DHookSetReturn", DHookReturn_SetReturn},
|
||||
{"DHookGetReturnVector", DHookReturn_GetReturnVector},
|
||||
{"DHookSetReturnVector", DHookReturn_SetReturnVector},
|
||||
{"DHookGetReturnString", DHookReturn_GetReturnString},
|
||||
{"DHookSetReturnString", DHookReturn_SetReturnString},
|
||||
{"DHookReturn.Value.get", DHookReturn_GetReturn},
|
||||
{"DHookReturn.Value.set", DHookReturn_SetReturn},
|
||||
{"DHookReturn.GetVector", DHookReturn_GetReturnVector},
|
||||
{"DHookReturn.SetVector", DHookReturn_SetReturnVector},
|
||||
{"DHookReturn.GetString", DHookReturn_GetReturnString},
|
||||
{"DHookReturn.SetString", DHookReturn_SetReturnString}
|
||||
{"DHookParam.IsNull", DHookParam_IsNullParam}
|
||||
};
|
||||
natives.insert(natives.end(), std::begin(list), std::end(list));
|
||||
}
|
||||
|
||||
211
extensions/dhooks/src/natives/dhookreturn.cpp
Normal file
211
extensions/dhooks/src/natives/dhookreturn.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
#include "../globals.hpp"
|
||||
#include "../sdk_types.hpp"
|
||||
#include "../handle.hpp"
|
||||
#include "../capsule.hpp"
|
||||
|
||||
namespace dhooks::natives::dhookreturn {
|
||||
|
||||
static void FreeChangedVector(void* data) {
|
||||
delete (sdk::Vector*)data;
|
||||
}
|
||||
|
||||
static void FreeChangedCharPtr(void* data) {
|
||||
delete[] (const char*)data;
|
||||
}
|
||||
|
||||
inline handle::ParamReturn* Get(SourcePawn::IPluginContext* context, const cell_t param) {
|
||||
SourceMod::HandleSecurity security;
|
||||
security.pOwner = globals::myself->GetIdentity();
|
||||
security.pIdentity = globals::myself->GetIdentity();
|
||||
SourceMod::Handle_t hndl = static_cast<SourceMod::Handle_t>(param);
|
||||
handle::ParamReturn* obj = nullptr;
|
||||
SourceMod::HandleError chnderr = globals::handlesys->ReadHandle(hndl, handle::ParamReturn::HANDLE_TYPE, &security, (void **)&obj);
|
||||
if (chnderr != SourceMod::HandleError_None) {
|
||||
context->ThrowNativeError("Invalid Handle %x (error %i: %s)", hndl, chnderr, globals::HandleErrorToString(chnderr));
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_GetReturn(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_Int:
|
||||
return *obj->GetReturn<int>();
|
||||
case sp::ReturnType_Bool:
|
||||
return (*obj->GetReturn<bool>()) ? 1 : 0;
|
||||
case sp::ReturnType_CBaseEntity:
|
||||
return globals::gamehelpers->EntityToBCompatRef(*obj->GetReturn<CBaseEntity*>());
|
||||
case sp::ReturnType_Edict:
|
||||
return globals::gamehelpers->IndexOfEdict(*obj->GetReturn<edict_t*>());
|
||||
case sp::ReturnType_Float:
|
||||
return sp_ftoc(*obj->GetReturn<float>());
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type (%i) to get", ret.dhook_type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_SetReturn(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_Int:
|
||||
*obj->GetReturn<int>() = params[2];
|
||||
break;
|
||||
case sp::ReturnType_Bool:
|
||||
*obj->GetReturn<bool>() = params[2] != 0;
|
||||
break;
|
||||
case sp::ReturnType_CBaseEntity: {
|
||||
CBaseEntity* entity = globals::gamehelpers->ReferenceToEntity(params[2]);
|
||||
if (entity == nullptr) {
|
||||
return context->ThrowNativeError("Invalid entity index passed for return value");
|
||||
}
|
||||
*obj->GetReturn<CBaseEntity*>() = entity;
|
||||
break;
|
||||
}
|
||||
case sp::ReturnType_Edict: {
|
||||
sdk::edict_t* edict = reinterpret_cast<sdk::edict_t*>(globals::gamehelpers->EdictOfIndex(params[2]));
|
||||
if (edict == nullptr || edict->IsFree()) {
|
||||
return context->ThrowNativeError("Invalid entity index passed for return value");
|
||||
}
|
||||
*obj->GetReturn<sdk::edict_t*>() = edict;
|
||||
break;
|
||||
}
|
||||
case sp::ReturnType_Float:
|
||||
*obj->GetReturn<float>() = sp_ctof(params[2]);
|
||||
break;
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type (%i) to get", ret.dhook_type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_GetReturnVector(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t *buffer;
|
||||
context->LocalToPhysAddr(params[2], &buffer);
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
|
||||
sdk::Vector* vector = nullptr;
|
||||
if (ret.dhook_type == sp::ReturnType_Vector) {
|
||||
vector = obj->GetReturn<sdk::Vector>();
|
||||
} else if(ret.dhook_type == sp::ReturnType_VectorPtr) {
|
||||
auto pvector = obj->GetReturn<sdk::Vector*>();
|
||||
if (*pvector == nullptr) {
|
||||
return context->ThrowNativeError("Vector pointer is null");
|
||||
}
|
||||
vector = *pvector;
|
||||
} else {
|
||||
return context->ThrowNativeError("Return type is not a vector type");
|
||||
}
|
||||
buffer[0] = sp_ftoc(vector->x);
|
||||
buffer[1] = sp_ftoc(vector->y);
|
||||
buffer[2] = sp_ftoc(vector->z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_SetReturnVector(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t *buffer;
|
||||
context->LocalToPhysAddr(params[2], &buffer);
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
|
||||
if (ret.dhook_type == sp::ReturnType_Vector) {
|
||||
*(obj->GetReturn<sdk::Vector>()) = sdk::Vector(sp_ctof(buffer[0]), sp_ctof(buffer[1]), sp_ctof(buffer[2]));
|
||||
}
|
||||
else if (ret.dhook_type == sp::ReturnType_VectorPtr) {
|
||||
// Lazily free the vector a frame later
|
||||
auto vector = new sdk::Vector(sp_ctof(buffer[0]), sp_ctof(buffer[1]), sp_ctof(buffer[2]));
|
||||
*(obj->GetReturn<sdk::Vector*>()) = vector;
|
||||
globals::sourcemod->AddFrameAction(FreeChangedVector, vector);
|
||||
} else {
|
||||
return context->ThrowNativeError("Return type is not a vector type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t DHookReturn_GetReturnString(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_String:
|
||||
context->StringToLocal(params[2], params[3], obj->GetReturn<sdk::string_t>()->ToCStr());
|
||||
return 1;
|
||||
case sp::ReturnType_StringPtr:
|
||||
context->StringToLocal(params[2], params[3], (obj->GetReturn<sdk::string_t*>() != nullptr) ? (*obj->GetReturn<sdk::string_t*>())->ToCStr() : "");
|
||||
return 1;
|
||||
case sp::ReturnType_CharPtr:
|
||||
context->StringToLocal(params[2], params[3], (*(obj->GetReturn<const char*>()) == nullptr) ? "" : *(obj->GetReturn<const char*>()));
|
||||
return 1;
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type to get. Param is not a string.");
|
||||
}
|
||||
}
|
||||
|
||||
cell_t DHookReturn_SetReturnString(SourcePawn::IPluginContext* context, const cell_t* params) {
|
||||
auto obj = Get(context, params[1]);
|
||||
if (obj == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& ret = obj->GetCapsule()->GetReturn();
|
||||
|
||||
char *value;
|
||||
context->LocalToString(params[2], &value);
|
||||
|
||||
switch (ret.dhook_type) {
|
||||
case sp::ReturnType_CharPtr: {
|
||||
auto new_str = new char[strlen(value) + 1];
|
||||
strcpy(new_str, value);
|
||||
*(obj->GetReturn<const char*>()) = new_str;
|
||||
// Free it later (cheaply) after the function returned.
|
||||
globals::sourcemod->AddFrameAction(FreeChangedCharPtr, new_str);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return context->ThrowNativeError("Invalid param type to get. Param is not a char pointer.");
|
||||
}
|
||||
}
|
||||
|
||||
void init(std::vector<sp_nativeinfo_t>& natives) {
|
||||
sp_nativeinfo_t list[] = {
|
||||
{"DHookGetReturn", DHookReturn_GetReturn},
|
||||
{"DHookSetReturn", DHookReturn_SetReturn},
|
||||
{"DHookGetReturnVector", DHookReturn_GetReturnVector},
|
||||
{"DHookSetReturnVector", DHookReturn_SetReturnVector},
|
||||
{"DHookGetReturnString", DHookReturn_GetReturnString},
|
||||
{"DHookSetReturnString", DHookReturn_SetReturnString},
|
||||
{"DHookReturn.Value.get", DHookReturn_GetReturn},
|
||||
{"DHookReturn.Value.set", DHookReturn_SetReturn},
|
||||
{"DHookReturn.GetVector", DHookReturn_GetReturnVector},
|
||||
{"DHookReturn.SetVector", DHookReturn_SetReturnVector},
|
||||
{"DHookReturn.GetString", DHookReturn_GetReturnString},
|
||||
{"DHookReturn.SetString", DHookReturn_SetReturnString}
|
||||
};
|
||||
natives.insert(natives.end(), std::begin(list), std::end(list));
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ std::optional<AsmRegCode> Translate_DHookRegister(sp::DHookRegister reg) {
|
||||
case sp::DHookRegister_AH:
|
||||
case sp::DHookRegister_EAX:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RAX:
|
||||
return KHook::Asm::rax;
|
||||
#else
|
||||
return KHook::Asm::eax;
|
||||
@ -16,6 +17,7 @@ std::optional<AsmRegCode> Translate_DHookRegister(sp::DHookRegister reg) {
|
||||
case sp::DHookRegister_CH:
|
||||
case sp::DHookRegister_ECX:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RCX:
|
||||
return KHook::Asm::rcx;
|
||||
#else
|
||||
return KHook::Asm::ecx;
|
||||
@ -24,6 +26,7 @@ std::optional<AsmRegCode> Translate_DHookRegister(sp::DHookRegister reg) {
|
||||
case sp::DHookRegister_DH:
|
||||
case sp::DHookRegister_EDX:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RDX:
|
||||
return KHook::Asm::rdx;
|
||||
#else
|
||||
return KHook::Asm::edx;
|
||||
@ -32,30 +35,35 @@ std::optional<AsmRegCode> Translate_DHookRegister(sp::DHookRegister reg) {
|
||||
case sp::DHookRegister_BH:
|
||||
case sp::DHookRegister_EBX:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RBX:
|
||||
return KHook::Asm::rbx;
|
||||
#else
|
||||
return KHook::Asm::ebx;
|
||||
#endif
|
||||
case sp::DHookRegister_ESP:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RSP:
|
||||
return KHook::Asm::rsp;
|
||||
#else
|
||||
return KHook::Asm::esp;
|
||||
#endif
|
||||
case sp::DHookRegister_EBP:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RBP:
|
||||
return KHook::Asm::rbp;
|
||||
#else
|
||||
return KHook::Asm::ebp;
|
||||
#endif
|
||||
case sp::DHookRegister_ESI:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RSI:
|
||||
return KHook::Asm::rsi;
|
||||
#else
|
||||
return KHook::Asm::esi;
|
||||
#endif
|
||||
case sp::DHookRegister_EDI:
|
||||
#ifdef DHOOKS_X86_64
|
||||
case sp::DHookRegister_RDI:
|
||||
return KHook::Asm::rdi;
|
||||
#else
|
||||
return KHook::Asm::edi;
|
||||
|
||||
@ -6,7 +6,7 @@ namespace sdk {
|
||||
|
||||
class CBaseEntity;
|
||||
|
||||
static constexpr size_t FL_EDICT_FREE = (1<<1);
|
||||
static constexpr std::size_t FL_EDICT_FREE = (1<<1);
|
||||
struct edict_t {
|
||||
public:
|
||||
bool IsFree() { return (m_fStateFlags & FL_EDICT_FREE) != 0; }
|
||||
|
||||
657
extensions/dhooks/src/signatures.cpp
Normal file
657
extensions/dhooks/src/signatures.cpp
Normal file
@ -0,0 +1,657 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Dynamic Hooks Extension
|
||||
* Copyright (C) 2012-2021 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "signatures.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
namespace dhooks {
|
||||
|
||||
SignatureGameConfig* dhooks_config = nullptr;
|
||||
SignatureWrapper* g_CurrentSignature;
|
||||
|
||||
enum class ParseState
|
||||
{
|
||||
None,
|
||||
Root,
|
||||
Function,
|
||||
Arguments,
|
||||
Argument
|
||||
};
|
||||
|
||||
ParseState g_ParseState;
|
||||
unsigned int g_IgnoreLevel;
|
||||
// The parent section type of a platform specific "windows" or "linux" section.
|
||||
ParseState g_PlatformOnlyState;
|
||||
std::string g_CurrentFunctionName;
|
||||
ArgumentInfo g_CurrentArgumentInfo;
|
||||
|
||||
SignatureWrapper* SignatureGameConfig::GetFunctionSignature(const char* function)
|
||||
{
|
||||
auto sig = signatures_.find(function);
|
||||
if (sig == signatures_.end())
|
||||
return nullptr;
|
||||
|
||||
return (*sig).second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Game config "Functions" section parsing.
|
||||
*/
|
||||
SourceMod::SMCResult SignatureGameConfig::ReadSMC_NewSection(const SourceMod::SMCStates *states, const char *name)
|
||||
{
|
||||
// We're ignoring the parent section. Ignore all child sections as well.
|
||||
if (g_IgnoreLevel > 0)
|
||||
{
|
||||
g_IgnoreLevel++;
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
// Handle platform specific sections first.
|
||||
#ifdef DHOOKS_X86_64
|
||||
#if defined WIN32
|
||||
if (!strcmp(name, "windows64"))
|
||||
#elif defined _LINUX
|
||||
if (!strcmp(name, "linux64"))
|
||||
#elif defined _OSX
|
||||
if (!strcmp(name, "mac64"))
|
||||
#endif
|
||||
#else
|
||||
#if defined WIN32
|
||||
if (!strcmp(name, "windows"))
|
||||
#elif defined _LINUX
|
||||
if (!strcmp(name, "linux"))
|
||||
#elif defined _OSX
|
||||
if (!strcmp(name, "mac"))
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
// We're already in a section for a different OS that we're ignoring. Can't have a section for our OS in here.
|
||||
if (g_IgnoreLevel > 0)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Unreachable platform specific section in \"%s\" Function: line: %i col: %i", g_CurrentFunctionName.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
// We don't support nested (useless) sections of the same OS like "windows" { "windows" { "foo" "bar" } }
|
||||
if (g_PlatformOnlyState != ParseState::None)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Duplicate platform specific section for \"%s\". Already parsing only for that OS: line: %i col: %i", name, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
// This is a specific block for us.
|
||||
g_PlatformOnlyState = g_ParseState;
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
else if (!strcmp(name, "windows") || !strcmp(name, "linux") || !strcmp(name, "mac")
|
||||
|| !strcmp(name, "windows64") || !strcmp(name, "linux64") || !strcmp(name, "mac64"))
|
||||
{
|
||||
if (g_PlatformOnlyState != ParseState::None)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Unreachable platform specific section in \"%s\" Function: line: %i col: %i", g_CurrentFunctionName.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
// A specific block for a different platform.
|
||||
g_IgnoreLevel++;
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
switch (g_ParseState) {
|
||||
case ParseState::Root: {
|
||||
auto sig = signatures_.find(name);
|
||||
if (sig != signatures_.end())
|
||||
g_CurrentSignature = (*sig).second;
|
||||
else
|
||||
g_CurrentSignature = new SignatureWrapper();
|
||||
g_CurrentFunctionName = name;
|
||||
g_ParseState = ParseState::Function;
|
||||
break;
|
||||
}
|
||||
|
||||
case ParseState::Function: {
|
||||
if (!strcmp(name, "arguments"))
|
||||
{
|
||||
g_ParseState = ParseState::Arguments;
|
||||
}
|
||||
else
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Unknown subsection \"%s\" (expected \"arguments\"): line: %i col: %i", name, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ParseState::Arguments: {
|
||||
g_ParseState = ParseState::Argument;
|
||||
g_CurrentArgumentInfo.name = name;
|
||||
|
||||
// Reset the parameter info.
|
||||
ParamInfo info;
|
||||
info.type = sp::HookParamType_Unknown;
|
||||
info.size = 0;
|
||||
info.custom_register = sp::DHookRegister_Default;
|
||||
info.flags = sp::DHookPass_ByVal;
|
||||
g_CurrentArgumentInfo.info = info;
|
||||
|
||||
// See if we already have info about this argument.
|
||||
for (auto &arg : g_CurrentSignature->args) {
|
||||
if (!arg.name.compare(name)) {
|
||||
// Continue changing that argument now.
|
||||
g_CurrentArgumentInfo.info = arg.info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
globals::sourcemod->LogError(globals::myself, "Unknown subsection \"%s\": line: %i col: %i", name, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
SourceMod::SMCResult SignatureGameConfig::ReadSMC_KeyValue(const SourceMod::SMCStates* states, const char* key, const char* value)
|
||||
{
|
||||
// We don't care for anything in this section or subsections.
|
||||
if (g_IgnoreLevel > 0)
|
||||
return SourceMod::SMCResult_Continue;
|
||||
|
||||
switch (g_ParseState)
|
||||
{
|
||||
case ParseState::Function: {
|
||||
if (!strcmp(key, "signature"))
|
||||
{
|
||||
if (g_CurrentSignature->address.length() > 0 || g_CurrentSignature->offset.length() > 0)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Cannot have \"signature\", \"address\" or \"offset\" keys at the same time in one function: line: %i col: %i", states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
g_CurrentSignature->signature = value;
|
||||
}
|
||||
else if (!strcmp(key, "address"))
|
||||
{
|
||||
if (g_CurrentSignature->signature.length() > 0 || g_CurrentSignature->offset.length() > 0)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Cannot have \"signature\", \"address\" or \"offset\" keys at the same time in one function: line: %i col: %i", states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
g_CurrentSignature->address = value;
|
||||
}
|
||||
else if (!strcmp(key, "offset"))
|
||||
{
|
||||
if (g_CurrentSignature->address.length() > 0 || g_CurrentSignature->signature.length() > 0)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Cannot have \"signature\", \"address\" or \"offset\" keys at the same time in one function: line: %i col: %i", states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
g_CurrentSignature->offset = value;
|
||||
}
|
||||
else if (!strcmp(key, "callconv"))
|
||||
{
|
||||
sp::CallingConvention callConv;
|
||||
|
||||
if (!strcmp(value, "cdecl"))
|
||||
callConv = sp::CallConv_CDECL;
|
||||
else if (!strcmp(value, "thiscall"))
|
||||
callConv = sp::CallConv_THISCALL;
|
||||
else if (!strcmp(value, "stdcall"))
|
||||
callConv = sp::CallConv_STDCALL;
|
||||
else if (!strcmp(value, "fastcall"))
|
||||
callConv = sp::CallConv_FASTCALL;
|
||||
else
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid calling convention \"%s\": line: %i col: %i", value, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
g_CurrentSignature->callConv = callConv;
|
||||
}
|
||||
else if (!strcmp(key, "hooktype"))
|
||||
{
|
||||
sp::HookType hookType;
|
||||
|
||||
if (!strcmp(value, "entity"))
|
||||
hookType = sp::HookType_Entity;
|
||||
else if (!strcmp(value, "gamerules"))
|
||||
hookType = sp::HookType_GameRules;
|
||||
else if (!strcmp(value, "raw"))
|
||||
hookType = sp::HookType_Raw;
|
||||
else
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid hook type \"%s\": line: %i col: %i", value, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
g_CurrentSignature->hookType = hookType;
|
||||
}
|
||||
else if (!strcmp(key, "return"))
|
||||
{
|
||||
g_CurrentSignature->retType = GetReturnTypeFromString(value);
|
||||
|
||||
if (g_CurrentSignature->retType == sp::ReturnType_Unknown)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid return type \"%s\": line: %i col: %i", value, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(key, "this"))
|
||||
{
|
||||
if (!strcmp(value, "ignore"))
|
||||
g_CurrentSignature->thisType = sp::ThisPointer_Ignore;
|
||||
else if (!strcmp(value, "entity"))
|
||||
g_CurrentSignature->thisType = sp::ThisPointer_CBaseEntity;
|
||||
else if (!strcmp(value, "address"))
|
||||
g_CurrentSignature->thisType = sp::ThisPointer_Address;
|
||||
else
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid this type \"%s\": line: %i col: %i", value, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Unknown key in Functions section \"%s\": line: %i col: %i", key, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ParseState::Argument: {
|
||||
if (!strcmp(key, "type"))
|
||||
{
|
||||
g_CurrentArgumentInfo.info.type = GetHookParamTypeFromString(value);
|
||||
if (g_CurrentArgumentInfo.info.type == sp::HookParamType_Unknown)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid argument type \"%s\" for argument \"%s\": line: %i col: %i", value, g_CurrentArgumentInfo.name.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(key, "size"))
|
||||
{
|
||||
g_CurrentArgumentInfo.info.size = static_cast<int>(strtol(value, NULL, 0));
|
||||
|
||||
if (g_CurrentArgumentInfo.info.size < 1)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid argument size \"%s\" for argument \"%s\": line: %i col: %i", value, g_CurrentArgumentInfo.name.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(key, "flags"))
|
||||
{
|
||||
sp::DHookPassFlag flags = static_cast<sp::DHookPassFlag>(0);
|
||||
if (strstr(value, "byval"))
|
||||
flags = static_cast<sp::DHookPassFlag>(static_cast<int>(flags)|sp::DHookPass_ByVal);
|
||||
if (strstr(value, "byref"))
|
||||
flags = static_cast<sp::DHookPassFlag>(static_cast<int>(flags)|sp::DHookPass_ByRef);
|
||||
/*
|
||||
if (strstr(value, "odtor"))
|
||||
flags |= PASSFLAG_ODTOR;
|
||||
if (strstr(value, "octor"))
|
||||
flags |= PASSFLAG_OCTOR;
|
||||
if (strstr(value, "oassignop"))
|
||||
flags |= PASSFLAG_OASSIGNOP;
|
||||
#ifdef PASSFLAG_OCOPYCTOR
|
||||
if (strstr(value, "ocopyctor"))
|
||||
flags |= PASSFLAG_OCOPYCTOR;
|
||||
#endif
|
||||
#ifdef PASSFLAG_OUNALIGN
|
||||
if (strstr(value, "ounalign"))
|
||||
flags |= PASSFLAG_OUNALIGN;
|
||||
#endif
|
||||
*/
|
||||
g_CurrentArgumentInfo.info.flags = flags;
|
||||
}
|
||||
else if (!strcmp(key, "register"))
|
||||
{
|
||||
g_CurrentArgumentInfo.info.custom_register = GetCustomRegisterFromString(value);
|
||||
|
||||
if (g_CurrentArgumentInfo.info.custom_register == sp::DHookRegister_Default)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Invalid register \"%s\": line: %i col: %i", value, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Unknown key in Functions section \"%s\": line: %i col: %i", key, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
globals::sourcemod->LogError(globals::myself, "Unknown key in Functions section \"%s\": line: %i col: %i", key, states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
SourceMod::SMCResult SignatureGameConfig::ReadSMC_LeavingSection(const SourceMod::SMCStates* states)
|
||||
{
|
||||
// We were ignoring this section.
|
||||
if (g_IgnoreLevel > 0)
|
||||
{
|
||||
g_IgnoreLevel--;
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
// We were in a section only for our OS.
|
||||
if (g_PlatformOnlyState == g_ParseState)
|
||||
{
|
||||
g_PlatformOnlyState = ParseState::None;
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
switch (g_ParseState)
|
||||
{
|
||||
case ParseState::Function:
|
||||
g_ParseState = ParseState::Root;
|
||||
|
||||
if (!g_CurrentSignature->address.length() && !g_CurrentSignature->signature.length() && !g_CurrentSignature->offset.length())
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Function \"%s\" doesn't have a \"signature\", \"offset\" nor \"address\" set: line: %i col: %i", g_CurrentFunctionName.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
if (!g_CurrentSignature->offset.length())
|
||||
{
|
||||
// DynamicDetours doesn't expose the passflags concept like SourceHook.
|
||||
// See if we're trying to set some invalid flags on detour arguments.
|
||||
for (auto &arg : g_CurrentSignature->args)
|
||||
{
|
||||
if ((arg.info.flags & ~sp::DHookPass_ByVal) > 0)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Function \"%s\" uses unsupported pass flags in argument \"%s\". Flags are only supported for virtual hooks: line: %i col: %i", g_CurrentFunctionName.c_str(), arg.name.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save this function signature in our cache.
|
||||
signatures_[g_CurrentFunctionName] = g_CurrentSignature;
|
||||
g_CurrentFunctionName = "";
|
||||
g_CurrentSignature = nullptr;
|
||||
break;
|
||||
case ParseState::Arguments:
|
||||
g_ParseState = ParseState::Function;
|
||||
break;
|
||||
case ParseState::Argument:
|
||||
g_ParseState = ParseState::Arguments;
|
||||
|
||||
if (g_CurrentArgumentInfo.info.type == sp::HookParamType_Unknown)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Missing argument type for argument \"%s\": line: %i col: %i", g_CurrentArgumentInfo.name.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
// The size wasn't set in the config. See if that's fine and we can guess it from the type.
|
||||
if (!g_CurrentArgumentInfo.info.size)
|
||||
{
|
||||
if (g_CurrentArgumentInfo.info.type == sp::HookParamType_Object)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "Object param \"%s\" being set with no size: line: %i col: %i", g_CurrentArgumentInfo.name.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_CurrentArgumentInfo.info.size = sp::GetParamTypeSize(g_CurrentArgumentInfo.info.type);
|
||||
if (g_CurrentArgumentInfo.info.size == 0)
|
||||
{
|
||||
globals::sourcemod->LogError(globals::myself, "param \"%s\" size could not be auto-determined!", g_CurrentArgumentInfo.name.c_str(), states->line, states->col);
|
||||
return SourceMod::SMCResult_HaltFail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See if we were changing an existing argument.
|
||||
bool changed = false;
|
||||
for (auto &arg : g_CurrentSignature->args)
|
||||
{
|
||||
if (!arg.name.compare(g_CurrentArgumentInfo.name))
|
||||
{
|
||||
arg.info = g_CurrentArgumentInfo.info;
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// This was a new argument. Add it to the end of the list.
|
||||
if (!changed)
|
||||
g_CurrentSignature->args.push_back(g_CurrentArgumentInfo);
|
||||
|
||||
g_CurrentArgumentInfo.name = "";
|
||||
break;
|
||||
}
|
||||
|
||||
return SourceMod::SMCResult_Continue;
|
||||
}
|
||||
|
||||
void SignatureGameConfig::ReadSMC_ParseStart()
|
||||
{
|
||||
g_ParseState = ParseState::Root;
|
||||
g_IgnoreLevel = 0;
|
||||
g_PlatformOnlyState = ParseState::None;
|
||||
g_CurrentSignature = nullptr;
|
||||
g_CurrentFunctionName = "";
|
||||
g_CurrentArgumentInfo.name = "";
|
||||
}
|
||||
|
||||
sp::ReturnType SignatureGameConfig::GetReturnTypeFromString(const char* str)
|
||||
{
|
||||
if (!strcmp(str, "void"))
|
||||
return sp::ReturnType_Void;
|
||||
else if (!strcmp(str, "int"))
|
||||
return sp::ReturnType_Int;
|
||||
else if (!strcmp(str, "bool"))
|
||||
return sp::ReturnType_Bool;
|
||||
else if (!strcmp(str, "float"))
|
||||
return sp::ReturnType_Float;
|
||||
else if (!strcmp(str, "string"))
|
||||
return sp::ReturnType_String;
|
||||
else if (!strcmp(str, "stringptr"))
|
||||
return sp::ReturnType_StringPtr;
|
||||
else if (!strcmp(str, "charptr"))
|
||||
return sp::ReturnType_CharPtr;
|
||||
else if (!strcmp(str, "vector"))
|
||||
return sp::ReturnType_Vector;
|
||||
else if (!strcmp(str, "vectorptr"))
|
||||
return sp::ReturnType_VectorPtr;
|
||||
else if (!strcmp(str, "cbaseentity"))
|
||||
return sp::ReturnType_CBaseEntity;
|
||||
else if (!strcmp(str, "edict"))
|
||||
return sp::ReturnType_Edict;
|
||||
|
||||
return sp::ReturnType_Unknown;
|
||||
}
|
||||
|
||||
sp::HookParamType SignatureGameConfig::GetHookParamTypeFromString(const char* str)
|
||||
{
|
||||
if (!strcmp(str, "int"))
|
||||
return sp::HookParamType_Int;
|
||||
else if (!strcmp(str, "bool"))
|
||||
return sp::HookParamType_Bool;
|
||||
else if (!strcmp(str, "float"))
|
||||
return sp::HookParamType_Float;
|
||||
else if (!strcmp(str, "string"))
|
||||
return sp::HookParamType_String;
|
||||
else if (!strcmp(str, "stringptr"))
|
||||
return sp::HookParamType_StringPtr;
|
||||
else if (!strcmp(str, "charptr"))
|
||||
return sp::HookParamType_CharPtr;
|
||||
else if (!strcmp(str, "vectorptr"))
|
||||
return sp::HookParamType_VectorPtr;
|
||||
else if (!strcmp(str, "cbaseentity"))
|
||||
return sp::HookParamType_CBaseEntity;
|
||||
else if (!strcmp(str, "objectptr"))
|
||||
return sp::HookParamType_ObjectPtr;
|
||||
else if (!strcmp(str, "edict"))
|
||||
return sp::HookParamType_Edict;
|
||||
else if (!strcmp(str, "object"))
|
||||
return sp::HookParamType_Object;
|
||||
return sp::HookParamType_Unknown;
|
||||
}
|
||||
|
||||
sp::DHookRegister SignatureGameConfig::GetCustomRegisterFromString(const char* str)
|
||||
{
|
||||
if (!strcmp(str, "al"))
|
||||
return sp::DHookRegister_AL;
|
||||
else if (!strcmp(str, "cl"))
|
||||
return sp::DHookRegister_CL;
|
||||
else if (!strcmp(str, "dl"))
|
||||
return sp::DHookRegister_DL;
|
||||
else if (!strcmp(str, "bl"))
|
||||
return sp::DHookRegister_BL;
|
||||
else if (!strcmp(str, "ah"))
|
||||
return sp::DHookRegister_AH;
|
||||
else if (!strcmp(str, "ch"))
|
||||
return sp::DHookRegister_CH;
|
||||
else if (!strcmp(str, "dh"))
|
||||
return sp::DHookRegister_DH;
|
||||
else if (!strcmp(str, "bh"))
|
||||
return sp::DHookRegister_BH;
|
||||
else if (!strcmp(str, "ax"))
|
||||
return sp::DHookRegister_EAX;
|
||||
else if (!strcmp(str, "cx"))
|
||||
return sp::DHookRegister_ECX;
|
||||
else if (!strcmp(str, "dx"))
|
||||
return sp::DHookRegister_EDX;
|
||||
else if (!strcmp(str, "bx"))
|
||||
return sp::DHookRegister_EBX;
|
||||
else if (!strcmp(str, "sp"))
|
||||
return sp::DHookRegister_ESP;
|
||||
else if (!strcmp(str, "bp"))
|
||||
return sp::DHookRegister_EBP;
|
||||
else if (!strcmp(str, "si"))
|
||||
return sp::DHookRegister_ESI;
|
||||
else if (!strcmp(str, "di"))
|
||||
return sp::DHookRegister_EDI;
|
||||
else if (!strcmp(str, "eax"))
|
||||
return sp::DHookRegister_EAX;
|
||||
else if (!strcmp(str, "ecx"))
|
||||
return sp::DHookRegister_ECX;
|
||||
else if (!strcmp(str, "edx"))
|
||||
return sp::DHookRegister_EDX;
|
||||
else if (!strcmp(str, "ebx"))
|
||||
return sp::DHookRegister_EBX;
|
||||
else if (!strcmp(str, "esp"))
|
||||
return sp::DHookRegister_ESP;
|
||||
else if (!strcmp(str, "ebp"))
|
||||
return sp::DHookRegister_EBP;
|
||||
else if (!strcmp(str, "esi"))
|
||||
return sp::DHookRegister_ESI;
|
||||
else if (!strcmp(str, "edi"))
|
||||
return sp::DHookRegister_EDI;
|
||||
else if (!strcmp(str, "rax"))
|
||||
return sp::DHookRegister_RAX;
|
||||
else if (!strcmp(str, "rcx"))
|
||||
return sp::DHookRegister_RCX;
|
||||
else if (!strcmp(str, "rdx"))
|
||||
return sp::DHookRegister_RDX;
|
||||
else if (!strcmp(str, "rbx"))
|
||||
return sp::DHookRegister_RBX;
|
||||
else if (!strcmp(str, "rsp"))
|
||||
return sp::DHookRegister_RSP;
|
||||
else if (!strcmp(str, "rbp"))
|
||||
return sp::DHookRegister_RBP;
|
||||
else if (!strcmp(str, "rsi"))
|
||||
return sp::DHookRegister_RSI;
|
||||
else if (!strcmp(str, "rdi"))
|
||||
return sp::DHookRegister_RDI;
|
||||
else if (!strcmp(str, "r8"))
|
||||
return sp::DHookRegister_R8;
|
||||
else if (!strcmp(str, "r9"))
|
||||
return sp::DHookRegister_R9;
|
||||
else if (!strcmp(str, "r10"))
|
||||
return sp::DHookRegister_R10;
|
||||
else if (!strcmp(str, "r11"))
|
||||
return sp::DHookRegister_R11;
|
||||
else if (!strcmp(str, "r12"))
|
||||
return sp::DHookRegister_R12;
|
||||
else if (!strcmp(str, "r13"))
|
||||
return sp::DHookRegister_R13;
|
||||
else if (!strcmp(str, "r14"))
|
||||
return sp::DHookRegister_R14;
|
||||
else if (!strcmp(str, "r15"))
|
||||
return sp::DHookRegister_R15;
|
||||
else if (!strcmp(str, "mm0"))
|
||||
return sp::DHookRegister_XMM0;
|
||||
else if (!strcmp(str, "mm1"))
|
||||
return sp::DHookRegister_XMM1;
|
||||
else if (!strcmp(str, "mm2"))
|
||||
return sp::DHookRegister_XMM2;
|
||||
else if (!strcmp(str, "mm3"))
|
||||
return sp::DHookRegister_XMM3;
|
||||
else if (!strcmp(str, "mm4"))
|
||||
return sp::DHookRegister_XMM4;
|
||||
else if (!strcmp(str, "mm5"))
|
||||
return sp::DHookRegister_XMM5;
|
||||
else if (!strcmp(str, "mm6"))
|
||||
return sp::DHookRegister_XMM6;
|
||||
else if (!strcmp(str, "mm7"))
|
||||
return sp::DHookRegister_XMM7;
|
||||
else if (!strcmp(str, "xmm0"))
|
||||
return sp::DHookRegister_XMM0;
|
||||
else if (!strcmp(str, "xmm1"))
|
||||
return sp::DHookRegister_XMM1;
|
||||
else if (!strcmp(str, "xmm2"))
|
||||
return sp::DHookRegister_XMM2;
|
||||
else if (!strcmp(str, "xmm3"))
|
||||
return sp::DHookRegister_XMM3;
|
||||
else if (!strcmp(str, "xmm4"))
|
||||
return sp::DHookRegister_XMM4;
|
||||
else if (!strcmp(str, "xmm5"))
|
||||
return sp::DHookRegister_XMM5;
|
||||
else if (!strcmp(str, "xmm6"))
|
||||
return sp::DHookRegister_XMM6;
|
||||
else if (!strcmp(str, "xmm7"))
|
||||
return sp::DHookRegister_XMM7;
|
||||
else if (!strcmp(str, "xmm8"))
|
||||
return sp::DHookRegister_XMM8;
|
||||
else if (!strcmp(str, "xmm9"))
|
||||
return sp::DHookRegister_XMM9;
|
||||
else if (!strcmp(str, "xmm10"))
|
||||
return sp::DHookRegister_XMM10;
|
||||
else if (!strcmp(str, "xmm11"))
|
||||
return sp::DHookRegister_XMM11;
|
||||
else if (!strcmp(str, "xmm12"))
|
||||
return sp::DHookRegister_XMM12;
|
||||
else if (!strcmp(str, "xmm13"))
|
||||
return sp::DHookRegister_XMM13;
|
||||
else if (!strcmp(str, "xmm14"))
|
||||
return sp::DHookRegister_XMM14;
|
||||
else if (!strcmp(str, "xmm15"))
|
||||
return sp::DHookRegister_XMM15;
|
||||
else if (!strcmp(str, "st0"))
|
||||
return sp::DHookRegister_ST0;
|
||||
return sp::DHookRegister_Default;
|
||||
}
|
||||
|
||||
}
|
||||
96
extensions/dhooks/src/signatures.hpp
Normal file
96
extensions/dhooks/src/signatures.hpp
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Dynamic Hooks Extension
|
||||
* Copyright (C) 2012-2021 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SIGNATURES_H_
|
||||
#define _INCLUDE_SIGNATURES_H_
|
||||
|
||||
#include "sp_inc.hpp"
|
||||
|
||||
#include "ITextParsers.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace dhooks {
|
||||
|
||||
struct ParamInfo
|
||||
{
|
||||
sp::HookParamType type;
|
||||
size_t size;
|
||||
sp::DHookPassFlag flags;
|
||||
sp::DHookRegister custom_register;
|
||||
};
|
||||
|
||||
struct ArgumentInfo {
|
||||
ArgumentInfo() : name()
|
||||
{ }
|
||||
|
||||
ArgumentInfo(std::string name, ParamInfo info) : name(name), info(info)
|
||||
{ }
|
||||
|
||||
std::string name;
|
||||
ParamInfo info;
|
||||
};
|
||||
|
||||
class SignatureWrapper {
|
||||
public:
|
||||
std::string signature;
|
||||
std::string address;
|
||||
std::string offset;
|
||||
std::vector<ArgumentInfo> args;
|
||||
sp::CallingConvention callConv;
|
||||
sp::HookType hookType;
|
||||
sp::ReturnType retType;
|
||||
sp::ThisPointerType thisType;
|
||||
};
|
||||
|
||||
class SignatureGameConfig : public SourceMod::ITextListener_SMC {
|
||||
public:
|
||||
SignatureWrapper* GetFunctionSignature(const char *function);
|
||||
public:
|
||||
//ITextListener_SMC
|
||||
virtual SourceMod::SMCResult ReadSMC_NewSection(const SourceMod::SMCStates* states, const char* name) override;
|
||||
virtual SourceMod::SMCResult ReadSMC_KeyValue(const SourceMod::SMCStates* states, const char* key, const char* value) override;
|
||||
virtual SourceMod::SMCResult ReadSMC_LeavingSection(const SourceMod::SMCStates* states) override;
|
||||
virtual void ReadSMC_ParseStart() override;
|
||||
|
||||
private:
|
||||
sp::ReturnType GetReturnTypeFromString(const char* str);
|
||||
sp::HookParamType GetHookParamTypeFromString(const char* str);
|
||||
sp::DHookRegister GetCustomRegisterFromString(const char* str);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, SignatureWrapper*> signatures_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
33
extensions/dhooks/src/sp_inc.cpp
Normal file
33
extensions/dhooks/src/sp_inc.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "sp_inc.hpp"
|
||||
#include "sdk_types.hpp"
|
||||
|
||||
namespace dhooks::sp {
|
||||
|
||||
std::size_t GetParamTypeSize(HookParamType type) {
|
||||
switch (type) {
|
||||
case HookParamType_Int:
|
||||
return sizeof(int);
|
||||
case HookParamType_Bool:
|
||||
return sizeof(bool);
|
||||
case HookParamType_Float:
|
||||
return sizeof(float);
|
||||
case HookParamType_String:
|
||||
return sizeof(sdk::string_t);
|
||||
case HookParamType_StringPtr:
|
||||
return sizeof(sdk::string_t*);
|
||||
case HookParamType_CharPtr:
|
||||
return sizeof(const char*);
|
||||
case HookParamType_VectorPtr:
|
||||
return sizeof(sdk::Vector*);
|
||||
case HookParamType_CBaseEntity:
|
||||
return sizeof(sdk::CBaseEntity*);
|
||||
case HookParamType_ObjectPtr:
|
||||
return sizeof(void*);
|
||||
case HookParamType_Edict:
|
||||
return sizeof(sdk::edict_t*);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,7 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dhooks::sp {
|
||||
|
||||
enum HookType
|
||||
{
|
||||
HookType_Entity,
|
||||
HookType_GameRules,
|
||||
HookType_Raw
|
||||
};
|
||||
|
||||
enum ThisPointerType
|
||||
{
|
||||
ThisPointer_Ignore,
|
||||
@ -53,7 +62,7 @@ enum ReturnType
|
||||
ReturnType_Edict
|
||||
};
|
||||
|
||||
enum DHookPassFlag
|
||||
enum DHookPassFlag : std::uint8_t
|
||||
{
|
||||
DHookPass_ByVal = (1<<0),
|
||||
DHookPass_ByRef = (1<<1),
|
||||
@ -99,7 +108,31 @@ enum DHookRegister
|
||||
DHookRegister_XMM5,
|
||||
DHookRegister_XMM6,
|
||||
DHookRegister_XMM7,
|
||||
DHookRegister_ST0
|
||||
DHookRegister_ST0,
|
||||
DHookRegister_RAX,
|
||||
DHookRegister_RCX,
|
||||
DHookRegister_RDX,
|
||||
DHookRegister_RBX,
|
||||
DHookRegister_RSP,
|
||||
DHookRegister_RBP,
|
||||
DHookRegister_RSI,
|
||||
DHookRegister_RDI,
|
||||
DHookRegister_R8,
|
||||
DHookRegister_R9,
|
||||
DHookRegister_R10,
|
||||
DHookRegister_R11,
|
||||
DHookRegister_R12,
|
||||
DHookRegister_R13,
|
||||
DHookRegister_R14,
|
||||
DHookRegister_R15,
|
||||
DHookRegister_XMM8,
|
||||
DHookRegister_XMM9,
|
||||
DHookRegister_XMM10,
|
||||
DHookRegister_XMM11,
|
||||
DHookRegister_XMM12,
|
||||
DHookRegister_XMM13,
|
||||
DHookRegister_XMM14,
|
||||
DHookRegister_XMM15
|
||||
};
|
||||
|
||||
enum ObjectValueType
|
||||
@ -119,4 +152,6 @@ enum ObjectValueType
|
||||
ObjectValueType_String
|
||||
};
|
||||
|
||||
std::size_t GetParamTypeSize(HookParamType type);
|
||||
|
||||
}
|
||||
56
extensions/dhooks/src/variable.hpp
Normal file
56
extensions/dhooks/src/variable.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "sp_inc.hpp"
|
||||
#include "register.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace dhooks {
|
||||
struct Variable {
|
||||
public:
|
||||
enum Alignment {
|
||||
OneByte = 1,
|
||||
TwoBytes = 2,
|
||||
FourBytes = 4,
|
||||
EightBytes = 8,
|
||||
SixteenBytes = 16
|
||||
};
|
||||
|
||||
sp::HookParamType dhook_type;
|
||||
std::size_t dhook_size;
|
||||
sp::DHookPassFlag dhook_pass_flags;
|
||||
sp::DHookRegister dhook_custom_register;
|
||||
|
||||
// Provided by the ABI, used by the JIT
|
||||
// If DHook is to ever support complex type, transform those fields
|
||||
// into an array so that the SP natives know where to look when offsetting into an object
|
||||
std::optional<AsmRegCode> reg_index;
|
||||
std::optional<AsmFloatRegCode> float_reg_index;
|
||||
std::optional<size_t> reg_offset;
|
||||
Alignment alignment;
|
||||
// Atm it's exactly the same as _dhook_size
|
||||
// We differentiate it anyways, to avoid having to refactor the JIT
|
||||
std::size_t type_size;
|
||||
};
|
||||
|
||||
struct ReturnVariable {
|
||||
public:
|
||||
enum Alignment {
|
||||
OneByte = 1,
|
||||
TwoBytes = 2,
|
||||
FourBytes = 4,
|
||||
EightBytes = 8,
|
||||
SixteenBytes = 16
|
||||
};
|
||||
|
||||
sp::ReturnType dhook_type;
|
||||
size_t dhook_size;
|
||||
sp::DHookPassFlag dhook_pass_flags;
|
||||
sp::DHookRegister dhook_custom_register;
|
||||
|
||||
std::optional<AsmRegCode> reg_index;
|
||||
std::optional<AsmFloatRegCode> float_reg_index;
|
||||
size_t reg_offset;
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user