diff --git a/core/sourcehook/sourcehook.cpp b/core/sourcehook/sourcehook.cpp index 8b66b2c31..41c2b9e55 100644 --- a/core/sourcehook/sourcehook.cpp +++ b/core/sourcehook/sourcehook.cpp @@ -97,6 +97,14 @@ namespace SourceHook int CSourceHookImpl::AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) + { + HookManagerPubFuncHandler pubFunc(myHookMan); + SHDelegateHandler shDelegate(handler); + return AddHook(plug, mode, iface, thisptr_offs, pubFunc, shDelegate, post); + } + + int CSourceHookImpl::AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + const SHDelegateHandler &handler, bool post) { if (mode != Hook_Normal && mode != Hook_VP && mode != Hook_DVP) return 0; @@ -174,7 +182,7 @@ namespace SourceHook ISHDelegate *handler, bool post) { // Get info about hook manager and compute adjustediface - CHookManager tmpHookMan(plug, myHookMan); + CHookManager tmpHookMan(plug, HookManagerPubFuncHandler(myHookMan)); void *adjustediface = reinterpret_cast(reinterpret_cast(iface)+thisptr_offs); @@ -224,8 +232,6 @@ namespace SourceHook if (hook_iter == hooks.end()) return false; - hook_iter->GetHandler()->DeleteThis(); - // Iterator movage! List::iterator oldhookiter = hook_iter; hook_iter = hooks.erase(hook_iter); @@ -417,6 +423,12 @@ namespace SourceHook } void CSourceHookImpl::RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) + { + // Find the hook manager + RemoveHookManager(plug, HookManagerPubFuncHandler(pubFunc)); + } + + void CSourceHookImpl::RemoveHookManager(Plugin plug, const HookManagerPubFuncHandler &pubFunc) { // Find the hook manager CHookManList::iterator hookman_iter = m_HookManList.find(CHookManager::Descriptor(plug, pubFunc)); diff --git a/core/sourcehook/sourcehook.h b/core/sourcehook/sourcehook.h index f562bc230..d52213d61 100644 --- a/core/sourcehook/sourcehook.h +++ b/core/sourcehook/sourcehook.h @@ -16,6 +16,8 @@ #ifndef __SOURCEHOOK_H__ #define __SOURCEHOOK_H__ +#include + // Interface revisions: // 1 - Initial revision // 2 - Changed to virtual functions for iterators and all queries @@ -173,6 +175,20 @@ namespace SourceHook */ struct PassInfo { + PassInfo() + : size(0) + , type(0) + , flags(0) + { + } + + PassInfo(size_t typeSize, int typeId, unsigned int typeFlags) + : size(typeSize) + , type(typeId) + , flags(typeFlags) + { + } + enum PassType { PassType_Unknown=0, /**< Unknown -- no extra info available */ @@ -206,6 +222,22 @@ namespace SourceHook struct V2Info { + V2Info() + : pNormalCtor(nullptr) + , pCopyCtor(nullptr) + , pDtor(nullptr) + , pAssignOperator(nullptr) + { + } + + V2Info(void *normalCtor, void *copyCtor, void *dtor, void *assignOperator) + : pNormalCtor(normalCtor) + , pCopyCtor(copyCtor) + , pDtor(dtor) + , pAssignOperator(assignOperator) + { + } + void *pNormalCtor; void *pCopyCtor; void *pDtor; @@ -241,29 +273,242 @@ namespace SourceHook const PassInfo::V2Info *paramsPassInfo2; }; + class IProtoInfo + { + public: + enum class ProtoInfoVersion : int + { + ProtoInfoVersionInvalid = -1, + ProtoInfoVersion1 = 0, + ProtoInfoVersion2 = 1 + }; + + virtual ~IProtoInfo() = default; + virtual size_t GetNumOfParams() const = 0; + virtual const PassInfo &GetRetPassInfo() const = 0; + virtual const PassInfo *GetParamsPassInfo() const = 0; + virtual int GetConvention() const = 0; + virtual IProtoInfo::ProtoInfoVersion GetVersion() const = 0; + virtual const PassInfo::V2Info &GetRetPassInfo2() const = 0; + virtual const PassInfo::V2Info *GetParamsPassInfo2() const = 0; + }; + struct IHookManagerInfo; /** * @brief Pointer to hook manager interface function * * The hook manager should store hi for later use if store==true. It should then call hi->SetInfo(...) if hi - * is non-null. The hook manager can return 0 for success or a non-zero value if it doesn't want to be used. + * is non-null. The hook manager can return 0 for success or a non-zero value if it doesn't want to be used. * * @param hi A pointer to IHookManagerInfo */ typedef int (*HookManagerPubFunc)(bool store, IHookManagerInfo *hi); + /** + * @brief Pointer to hook manager interface function for member and static functions + * + * The hook manager should store hi for later use if store==true. It should then call hi->SetInfo(...) if hi + * is non-null. The hook manager can return 0 for success or a non-zero value if it doesn't want to be used. + * + * @param hi A pointer to IHookManagerInfo + */ + + class IHookManagerMemberFunc + { + public: + virtual ~IHookManagerMemberFunc() = default; + virtual int Call(bool store, IHookManagerInfo *hi) const = 0; + }; + + class HookManagerPubFuncHandler + { + public: + HookManagerPubFuncHandler() + : staticFunc_(nullptr) + , memberFunc_(nullptr) + { + } + + explicit HookManagerPubFuncHandler(HookManagerPubFunc func) + : staticFunc_(func) + , memberFunc_(nullptr) + { + } + + explicit HookManagerPubFuncHandler(IHookManagerMemberFunc* funcHandler) + : staticFunc_(nullptr) + , memberFunc_(funcHandler) + { + } + + explicit HookManagerPubFuncHandler(const HookManagerPubFuncHandler& other) + : staticFunc_(other.staticFunc_) + , memberFunc_(other.memberFunc_) + { + } + + explicit HookManagerPubFuncHandler(HookManagerPubFuncHandler&& other) + : staticFunc_(other.staticFunc_) + , memberFunc_(other.memberFunc_) + { + other.staticFunc_ = nullptr; + other.memberFunc_ = nullptr; + } + + HookManagerPubFuncHandler& operator=(const HookManagerPubFuncHandler& other) + { + staticFunc_ = other.staticFunc_; + memberFunc_ = other.memberFunc_; + return *this; + } + + HookManagerPubFuncHandler& operator=(HookManagerPubFuncHandler&& other) + { + if (this == &other) + return *this; + + staticFunc_ = other.staticFunc_; + memberFunc_ = other.memberFunc_; + other.staticFunc_ = nullptr; + other.memberFunc_ = nullptr; + return *this; + } + + HookManagerPubFuncHandler& operator=(HookManagerPubFunc func) + { + staticFunc_ = func; + memberFunc_ = nullptr; + return *this; + } + + HookManagerPubFuncHandler& operator=(IHookManagerMemberFunc* funcHandler) + { + staticFunc_ = nullptr; + memberFunc_ = funcHandler; + return *this; + } + + operator bool() const + { + return (staticFunc_ != nullptr || + memberFunc_ != nullptr); + } + + operator HookManagerPubFunc() const + { + return staticFunc_; + } + + operator IHookManagerMemberFunc*() const + { + return memberFunc_; + } + + int operator()(bool store, IHookManagerInfo *hi) const + { + if(staticFunc_ != nullptr) + return staticFunc_(store, hi); + + if(memberFunc_ != nullptr) + return memberFunc_->Call(store, hi); + + return 0; + } + + bool operator==(const HookManagerPubFuncHandler &rhs) const + { + return staticFunc_ == rhs.staticFunc_ && + memberFunc_ == rhs.memberFunc_; + } + + bool operator==(HookManagerPubFunc staticFunc) const + { + return staticFunc_ == staticFunc && + memberFunc_ == nullptr; + } + + bool operator==(const IHookManagerMemberFunc *memberFunc) const + { + return staticFunc_ == nullptr && + memberFunc_ == memberFunc; + } + + private: + HookManagerPubFunc staticFunc_; + IHookManagerMemberFunc* memberFunc_; + }; + + class SHDelegateHandler; + class ISHDelegate { public: virtual bool IsEqual(ISHDelegate *pOtherDeleg) = 0; // pOtherDeleg is from the same plugin and hookman + private: + friend class SHDelegateHandler; virtual void DeleteThis() = 0; }; + // ISHDelegate doesn't provide a virtual destructor, use this wrapper to handle it + class SHDelegateHandler final + { + public: + template + static SHDelegateHandler Make(Params&&... params) + { + ISHDelegate* delegate = new U(std::forward(params)...); + return SHDelegateHandler(delegate); + } + + SHDelegateHandler() + : ptr_(nullptr, &SHDelegateHandler::DeleteDelegate) + { + } + + explicit SHDelegateHandler(ISHDelegate* delegate) + : ptr_(delegate, &SHDelegateHandler::DeleteDelegate) + { + } + + void Reset() + { + ptr_.reset(); + } + + bool operator==(const SHDelegateHandler &other) const + { + return ptr_.get() == other.Get(); + } + + ISHDelegate* operator->() const + { + return ptr_.get(); + } + + ISHDelegate* Get() const + { + return ptr_.get(); + } + + private: + static void DeleteDelegate(ISHDelegate* delegate) + { + if(delegate) + delegate->DeleteThis(); + } + + private: + std::shared_ptr ptr_; + }; + struct IHookManagerInfo { virtual void SetInfo(int hookman_version, int vtbloffs, int vtblidx, ProtoInfo *proto, void *hookfunc_vfnptr) = 0; + + virtual void SetInfo(int hookman_version, int vtbloffs, int vtblidx, + IProtoInfo *proto, void *hookfunc_vfnptr) = 0; }; // I'm adding support for functions which return references. @@ -353,7 +598,7 @@ namespace SourceHook Hook_Normal, Hook_VP, Hook_DVP - }; + }; /** * @brief Add a (VP) hook. @@ -424,7 +669,7 @@ namespace SourceHook * @brief Remove a hook manager. Auto-removes all hooks attached to it from plugin plug. * * @param plug The owner of the hook manager - * @param pubFunc The hook manager's info function + * @param pubFunc The hook manager's info function */ virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) = 0; @@ -499,6 +744,32 @@ namespace SourceHook const void *origRetPtr, void *overrideRetPtr) = 0; virtual void EndContext(IHookContext *pCtx) = 0; + + /** + * @brief Add a (VP) hook. + * + * @return non-zero hook id on success, 0 otherwise + * + * @param plug The unique identifier of the plugin that calls this function + * @param mode Can be either Hook_Normal or Hook_VP (vtable-wide hook) + * @param iface The interface pointer + * @param ifacesize The size of the class iface points to + * @param myHookMan A hook manager function that should be capable of handling the function + * @param handler A pointer to the hook handler something + * @param post Set to true if you want a post handler + */ + + virtual int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + const SHDelegateHandler &handler, bool post) = 0; + + /** + * @brief Remove a hook manager. Auto-removes all hooks attached to it from plugin plug. + * + * @param plug The owner of the hook manager + * @param pubFunc The hook manager's info function + */ + + virtual void RemoveHookManager(Plugin plug, const HookManagerPubFuncHandler &pubFunc) = 0; }; @@ -4923,6 +5194,5 @@ namespace SourceHook return reinterpret_cast(shptr->GetIfacePtr()); } } - #endif // The pope is dead. -> :( diff --git a/core/sourcehook/sourcehook_handlers.h b/core/sourcehook/sourcehook_handlers.h new file mode 100644 index 000000000..2117505be --- /dev/null +++ b/core/sourcehook/sourcehook_handlers.h @@ -0,0 +1,722 @@ +/* ======== SourceHook ======== +* Copyright (C) 2004-2023 Metamod:Source Development Team +* No warranties of any kind +* +* License: zlib/libpng +* +* Author(s): mixern6 (SVRL_) +* ============================ +*/ + +/** +* @file sourcehook_handlers.h +* @brief Contains the public SourceHook API +*/ + +#ifndef __SOURCEHOOK_HANDLERS_H__ +#define __SOURCEHOOK_HANDLERS_H__ + +#include "sourcehook.h" +#include + +namespace SourceHook +{ +class ISourceHook; +typedef int Plugin; +} + +extern SourceHook::ISourceHook *g_SHPtr; +extern SourceHook::Plugin g_PLID; + +namespace SourceHook +{ + +// Get type info for type T +template +inline void TypeInfo(PassInfo& passInfo) +{ + passInfo.size = sizeof(T); + passInfo.type = GetPassInfo::type; + passInfo.flags = GetPassInfo::flags; +} + +// Get type info for type T +template<> +inline void TypeInfo(PassInfo& passInfo) +{ + passInfo.size = 1; + passInfo.type = 0; + passInfo.flags = 0; +} + +template +class PassInfoInitializer +{ +public: + constexpr PassInfoInitializer() + { + InitializePassInfo(); + } + + const PassInfo *GetParamsPassInfo() const + { + return params_; + } + + const PassInfo::V2Info *GetParamsPassInfoV2() const + { + return paramsV2_; + } + + const size_t GetParamsPassInfoSize() const + { + return sizeof...(ArgsType); + } + +private: + template + inline typename std::enable_if::type InitializePassInfo() + { + TypeInfo(params_[index]); + InitializePassInfo(); + } + + template + inline void InitializePassInfo() + { + TypeInfo(params_[index]); + } + + PassInfo params_[sizeof...(ArgsType)]; + PassInfo::V2Info paramsV2_[sizeof...(ArgsType)]; +}; + +// For zero arguments +template<> +class PassInfoInitializer<> +{ +public: + constexpr PassInfoInitializer() + { + } + + const PassInfo *GetParamsPassInfo() const + { + return nullptr; + } + + const PassInfo::V2Info *GetParamsPassInfoV2() const + { + return nullptr; + } + + const size_t GetParamsPassInfoSize() const + { + return 0; + } +}; + +template +struct ReturnTypeInfo +{ + static const size_t size() + { + return sizeof(T); + } + + static const int type() + { + return GetPassInfo::type; + } + + static const unsigned int flags() + { + return GetPassInfo::flags; + } +}; + +template <> +struct ReturnTypeInfo +{ + static const size_t size() + { + return 0; + } + + static const int type() + { + return 0; + } + + static const unsigned int flags() + { + return 0; + } +}; + +template +class CHookManagerMemberFuncHandler : public IHookManagerMemberFunc +{ +public: + typedef int (T::*HookManagerMemberFunc)(bool store, IHookManagerInfo *hi); + + explicit CHookManagerMemberFuncHandler(T* funcHandler, HookManagerMemberFunc func) + : funcHandler_(funcHandler) + , func_(func) + { + } + + virtual ~CHookManagerMemberFuncHandler() + { + } + +private: + virtual int Call(bool store, IHookManagerInfo *hi) const override + { + return (funcHandler_->*func_)(store, hi); + } + +private: + T* funcHandler_; + HookManagerMemberFunc func_; +}; + +template +class CProtoInfo : public IProtoInfo +{ +public: + constexpr CProtoInfo() + : retPassInfo(ReturnTypeInfo::size(), + ReturnTypeInfo::type(), + ReturnTypeInfo::flags()) + { + } + + virtual ~CProtoInfo() override + { + } + + virtual size_t GetNumOfParams() const override + { + return paramsPassInfo.GetParamsPassInfoSize(); + } + + virtual const PassInfo &GetRetPassInfo() const override + { + return retPassInfo; + } + + virtual const PassInfo *GetParamsPassInfo() const override + { + return paramsPassInfo.GetParamsPassInfo(); + } + + virtual int GetConvention() const override + { + return 0; + } + + // version of the ProtoInfo structure. + virtual IProtoInfo::ProtoInfoVersion GetVersion() const override + { + return ProtoInfoVersion::ProtoInfoVersion2; + } + + virtual const PassInfo::V2Info &GetRetPassInfo2() const override + { + return retPassInfo2; + } + + virtual const PassInfo::V2Info *GetParamsPassInfo2() const override + { + return paramsPassInfo.GetParamsPassInfoV2(); + } + +private: + int numOfParams; //!< number of parameters + PassInfo retPassInfo; //!< PassInfo for the return value. size=0 -> no retval + PassInfo::V2Info retPassInfo2; //!< Version2 only + PassInfoInitializer paramsPassInfo; //!< PassInfos for the parameters +}; + +template +class ManualHookHandler : public CHookManagerMemberFuncHandler> +{ +public: + typedef ManualHookHandler ThisType; + typedef ReturnType(EmptyClass::*ECMFP)(Params...); + typedef ExecutableClassN CallEC; + + template + struct HookedMemberFuncType + { + typedef ReturnType (U::*HookFunc)(Params...); + }; + + struct HookedStaticFuncType + { + typedef ReturnType (*HookFunc)(Params...); + }; + + template + struct HookedMemberFuncIFaceType + { + typedef ReturnType (U::*HookFunc)(T*, Params...); + }; + + template + struct HookedStaticFuncIFaceType + { + typedef ReturnType (*HookFunc)(T*, Params...); + }; + + constexpr ManualHookHandler() + : CHookManagerMemberFuncHandler(this, &ThisType::HookManPubFunc) + , msMFI_{false, 0, 0, 0} + , msHI_(nullptr) + { + } + + ManualHookHandler(const ManualHookHandler&) = delete; + + ManualHookHandler(ManualHookHandler&&) = delete; + + ManualHookHandler& operator=(const ManualHookHandler&) = delete; + + ManualHookHandler& operator=(ManualHookHandler&&) = delete; + + virtual ~ManualHookHandler() + { + HookManagerPubFuncHandler pubFunc(this); + g_SHPtr->RemoveHookManager(g_PLID, pubFunc); + } + + void Reconfigure(int vtblindex, int vtbloffs = 0, int thisptroffs = 0) + { + HookManagerPubFuncHandler pubFunc(this); + g_SHPtr->RemoveHookManager(g_PLID, pubFunc); + msMFI_.thisptroffs = thisptroffs; + msMFI_.vtblindex = vtblindex; + msMFI_.vtbloffs = vtbloffs; + } + + // Hook with a statuc function callback + // ReturnType Callback(Params...); + [[nodiscard]] int Add(void *iface, + typename HookedStaticFuncType::HookFunc callbackFuncPtr, + bool post = true, + ISourceHook::AddHookMode mode = ISourceHook::AddHookMode::Hook_Normal) + { + HookManagerPubFuncHandler pubFunc(this); + SHDelegateHandler shDelegate = SHDelegateHandler::Make(callbackFuncPtr); + return g_SHPtr->AddHook(g_PLID, mode, iface, 0, pubFunc, shDelegate, post); + } + + // Hook with a statuc function callback with iface pointer first argument + // ReturnType Callback(T *iface, Params...); + template + [[nodiscard]] int Add(T *iface, + typename HookedStaticFuncIFaceType::HookFunc callbackFuncPtr, + bool post = true, + ISourceHook::AddHookMode mode = ISourceHook::AddHookMode::Hook_Normal) + { + HookManagerPubFuncHandler pubFunc(this); + SHDelegateHandler shDelegate = SHDelegateHandler::Make>(callbackFuncPtr); + return g_SHPtr->AddHook(g_PLID, mode, iface, 0, pubFunc, shDelegate, post); + } + + // Hook with a member function callback + // ReturnType U::Callback(Params...); + template::value, void>::type* = nullptr> + [[nodiscard]] int Add(void *iface, + U* callbackInstPtr, + typename HookedMemberFuncType::HookFunc callbackFuncPtr, + bool post = true, + ISourceHook::AddHookMode mode = ISourceHook::AddHookMode::Hook_Normal) + { + HookManagerPubFuncHandler pubFunc(this); + SHDelegateHandler shDelegate = SHDelegateHandler::Make>(callbackInstPtr, callbackFuncPtr); + return g_SHPtr->AddHook(g_PLID, mode, iface, 0, pubFunc, shDelegate, post); + } + + // Hook with a member function callback with iface pointer first argument + // ReturnType U::Callback(T *iface, Params...); + template::value, void>::type* = nullptr> + [[nodiscard]] int Add(T *iface, + U *callbackInstPtr, + typename HookedMemberFuncIFaceType::HookFunc callbackFuncPtr, + bool post = true, + ISourceHook::AddHookMode mode = ISourceHook::AddHookMode::Hook_Normal) + { + HookManagerPubFuncHandler pubFunc(this); + SHDelegateHandler shDelegate = SHDelegateHandler::Make>(callbackInstPtr, callbackFuncPtr); + return g_SHPtr->AddHook(g_PLID, mode, iface, 0, pubFunc, shDelegate, post); + } + + inline bool Remove(int hookid) + { + return g_SHPtr->RemoveHookByID(hookid); + } + + inline bool Pause(int hookid) + { + return g_SHPtr->PauseHookByID(hookid); + } + + inline bool Unpause(int hookid) + { + return g_SHPtr->UnpauseHookByID(hookid); + } + + // See RETURN_META_MNEWPARAMS + // For void return type only + template::value, void>::type* = nullptr> + void Recall(META_RES result, Params... newparams) + { + g_SHPtr->SetRes(result); + g_SHPtr->DoRecall(); + SourceHook::EmptyClass *thisptr = reinterpret_cast(g_SHPtr->GetIfacePtr()); + (thisptr->*(GetRecallMFP(thisptr)))(newparams...); + g_SHPtr->SetRes(MRES_SUPERCEDE); + } + + // See RETURN_META_VALUE_MNEWPARAMS + // For any return type but void + template::value, void>::type* = nullptr> + [[nodiscard]] U Recall(META_RES result, U value, Params... newparams) + { + g_SHPtr->SetRes(result); + g_SHPtr->DoRecall(); + if ((result) >= MRES_OVERRIDE) + { + SetOverrideResult(g_SHPtr, value); + } + EmptyClass *thisptr = reinterpret_cast(g_SHPtr->GetIfacePtr()); + g_SHPtr->SetRes(MRES_SUPERCEDE); + return (thisptr->*(GetRecallMFP(thisptr)))(newparams...); + } + + // See RETURN_META. + // NOTE: for RETURN_META_VALUE return the value after this call + inline void SetResult(META_RES res) + { + g_SHPtr->SetRes(res); + } + + [[nodiscard]] inline META_RES GetPreviousResult() const + { + return g_SHPtr->GetPrevRes(); + } + + [[nodiscard]] inline META_RES GetStatus() const + { + return g_SHPtr->GetStatus(); + } + +private: + struct IMyDelegate : ISHDelegate + { + virtual ReturnType Call(Params... params) = 0; + + // Unneeded + // old SH_REMOVE_HOOK syntax is not supported + virtual bool IsEqual(ISHDelegate */*pOtherDeleg*/) override + { + SH_ASSERT(false, ("Forbidden use of ISHDelegate::IsEqual")); + return false; + } + }; + + struct CStaticDelegateImpl : public IMyDelegate + { + typename HookedStaticFuncType::HookFunc funcPtr_; + CStaticDelegateImpl(typename HookedStaticFuncType::HookFunc callbackFuncPtr) + : funcPtr_(callbackFuncPtr) + { + } + + virtual ReturnType Call(Params... params) override + { + return funcPtr_(params...); + } + + virtual void DeleteThis() override + { + delete this; + } + }; + + template + struct CStaticIFaceDelegateImpl : public IMyDelegate + { + typename HookedStaticFuncIFaceType::HookFunc funcPtr_; + CStaticIFaceDelegateImpl(typename HookedStaticFuncIFaceType::HookFunc callbackFuncPtr) + : funcPtr_(callbackFuncPtr) + { + } + + virtual ReturnType Call(Params... params) override + { + return funcPtr_(reinterpret_cast(g_SHPtr->GetIfacePtr()), params...); + } + + virtual void DeleteThis() override + { + delete this; + } + }; + + template + struct CMemberDelegateImpl : public IMyDelegate + { + U* instPtr_; + typename HookedMemberFuncType::HookFunc funcPtr_; + CMemberDelegateImpl(U* callbackInstPtr, typename HookedMemberFuncType::HookFunc callbackFuncPtr) + : instPtr_(callbackInstPtr) + , funcPtr_(callbackFuncPtr) + { + } + + virtual ReturnType Call(Params... params) override + { + return (instPtr_->*funcPtr_)(params...); + } + + virtual void DeleteThis() override + { + delete this; + } + }; + + template + struct CMemberIFaceDelegateImpl : public IMyDelegate + { + U* instPtr_; + typename HookedMemberFuncIFaceType::HookFunc funcPtr_; + CMemberIFaceDelegateImpl(U* callbackInstPtr, typename HookedMemberFuncIFaceType::HookFunc callbackFuncPtr) + : instPtr_(callbackInstPtr) + , funcPtr_(callbackFuncPtr) + { + } + + virtual ReturnType Call(Params... params) override + { + return (instPtr_->*funcPtr_)(reinterpret_cast(g_SHPtr->GetIfacePtr()), params...); + } + + virtual void DeleteThis() override + { + delete this; + } + }; + + // Implementation for any return type but void + template::value, void>::type* = nullptr> + U Func(Params... params) + { + /* 1) Set up calls */ + void *ourvfnptr = reinterpret_cast(*reinterpret_cast(reinterpret_cast(this) + msMFI_.vtbloffs) + msMFI_.vtblindex); + void *vfnptr_origentry; + + META_RES status = MRES_IGNORED; + META_RES prev_res; + META_RES cur_res; + + typedef typename ReferenceCarrier::type my_rettype; + my_rettype orig_ret; + my_rettype override_ret; + my_rettype plugin_ret; + IMyDelegate *iter = nullptr; + + IHookContext *pContext = g_SHPtr->SetupHookLoop(msHI_, + ourvfnptr, + reinterpret_cast(this), + &vfnptr_origentry, + &status, + &prev_res, + &cur_res, + &orig_ret, + &override_ret); + + prev_res = MRES_IGNORED; + + while ((iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + plugin_ret = iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + + if (cur_res >= MRES_OVERRIDE) + *reinterpret_cast(pContext->GetOverrideRetPtr()) = plugin_ret; + } + + if (status != MRES_SUPERCEDE && pContext->ShouldCallOrig()) + { + ReturnType (EmptyClass::*mfp)(Params...); + SH_SETUP_MFP(mfp); + + orig_ret = (reinterpret_cast(this)->*mfp)(params...); + } + else + orig_ret = override_ret; /* :TODO: ??? : use pContext->GetOverrideRetPtr() or not? */ + + prev_res = MRES_IGNORED; + while ((iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + plugin_ret = iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + + if (cur_res >= MRES_OVERRIDE) + *reinterpret_cast(pContext->GetOverrideRetPtr()) = plugin_ret; + } + + const void* repPtr = (status >= MRES_OVERRIDE) ? pContext->GetOverrideRetPtr() : + pContext->GetOrigRetPtr(); + + g_SHPtr->EndContext(pContext); + + return *reinterpret_cast(repPtr); + } + + // Implementation for void return type only + template::value, void>::type* = nullptr> + void Func(Params... params) + { + /* 1) Set up calls */ + void *ourvfnptr = reinterpret_cast(*reinterpret_cast(reinterpret_cast(this) + msMFI_.vtbloffs) + msMFI_.vtblindex); + void *vfnptr_origentry; + + META_RES status = MRES_IGNORED; + META_RES prev_res; + META_RES cur_res; + + IMyDelegate *iter = nullptr; + + IHookContext *pContext = g_SHPtr->SetupHookLoop(msHI_, + ourvfnptr, + reinterpret_cast(this), + &vfnptr_origentry, + &status, + &prev_res, + &cur_res, + nullptr, + nullptr); + + prev_res = MRES_IGNORED; + while ((iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + } + + if (status != MRES_SUPERCEDE && pContext->ShouldCallOrig()) + { + void (EmptyClass::*mfp)(Params...); + SH_SETUP_MFP(mfp); + + (reinterpret_cast(this)->*mfp)(params...); + } + + prev_res = MRES_IGNORED; + while ( (iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + + iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + } + + g_SHPtr->EndContext(pContext); + } + + int HookManPubFunc(bool store, IHookManagerInfo *hi) + { + /* Verify interface version */ + if (g_SHPtr->GetIfaceVersion() != SH_IFACE_VERSION) + return 1; + + if (g_SHPtr->GetImplVersion() < SH_IMPL_VERSION) + return 1; + + if (store) + msHI_ = hi; + + if (hi) + { + MemFuncInfo mfi = {true, -1, 0, 0}; + GetFuncInfo(this, &ThisType::Func, mfi); + + hi->SetInfo(SH_HOOKMAN_VERSION, + msMFI_.vtbloffs, + msMFI_.vtblindex, + &msProto_, + reinterpret_cast(reinterpret_cast(this) + mfi.vtbloffs)[mfi.vtblindex]); + } + + return 0; + } + + typename ManualHookHandler::ECMFP GetRecallMFP(EmptyClass *thisptr) + { + union + { + typename ManualHookHandler::ECMFP mfp; + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + + u.s.addr = (*reinterpret_cast(reinterpret_cast(thisptr) + msMFI_.vtbloffs))[msMFI_.vtblindex]; + u.s.adjustor = 0; + + return u.mfp; + } + + typename ManualHookHandler::CallEC Call(void *ptr) + { + typename ManualHookHandler::ECMFP mfp; + void *vfnptr = reinterpret_cast(*reinterpret_cast((reinterpret_cast(ptr) + msMFI_.thisptroffs + msMFI_.vtbloffs) ) + msMFI_.vtblindex); + + /* patch mfp */ + *reinterpret_cast(&mfp) = *reinterpret_cast(vfnptr); + + if (sizeof(mfp) == 2*sizeof(void*)) /* gcc */ + *(reinterpret_cast(&mfp) + 1) = 0; + + return ManualHookHandler::CallEC(reinterpret_cast(ptr), mfp, vfnptr, g_SHPtr); + } + + // Implementation for any return type but void + template::value, void>::type* = nullptr> + void SetOverrideResult(ISourceHook *shptr, U value) + { + OverrideFunctor overrideFunc = SourceHook::SetOverrideResult(); + overrideFunc(shptr, value); + } + +private: + MemFuncInfo msMFI_; // ms_MFI + IHookManagerInfo *msHI_; // ms_HI + + CProtoInfo msProto_; // ms_Proto +}; + +} // SourceHook + +#endif // __SOURCEHOOK_HANDLERS_H__ diff --git a/core/sourcehook/sourcehook_hookmangen.cpp b/core/sourcehook/sourcehook_hookmangen.cpp index 287a64322..205d8fb92 100644 --- a/core/sourcehook/sourcehook_hookmangen.cpp +++ b/core/sourcehook/sourcehook_hookmangen.cpp @@ -1959,12 +1959,12 @@ namespace SourceHook return m_GeneratedPubFunc; } - bool GenContext::Equal(const CProto &proto, int vtbl_offs, int vtbl_idx) + bool GenContext::Equal(const CProto &proto, int vtbl_offs, int vtbl_idx) const { return (m_OrigProto.ExactlyEqual(proto) && m_VtblOffs == vtbl_offs && m_VtblIdx == vtbl_idx); } - bool GenContext::Equal(HookManagerPubFunc other) + bool GenContext::Equal(HookManagerPubFunc other) const { return m_GeneratedPubFunc == other; } @@ -2013,11 +2013,9 @@ namespace SourceHook { return NULL; } - else - { - m_Contexts.push_back(sctx); - return sctx.m_GenContext->GetPubFunc(); - } + + m_Contexts.push_back(sctx); + return sctx.m_GenContext->GetPubFunc(); } void CHookManagerAutoGen::ReleaseHookMan(HookManagerPubFunc pubFunc) diff --git a/core/sourcehook/sourcehook_hookmangen.h b/core/sourcehook/sourcehook_hookmangen.h index 9e565f77e..0193273cb 100644 --- a/core/sourcehook/sourcehook_hookmangen.h +++ b/core/sourcehook/sourcehook_hookmangen.h @@ -265,8 +265,8 @@ namespace SourceHook GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr); ~GenContext(); - bool Equal(const CProto &proto, int vtbl_offs, int vtbl_idx); - bool Equal(HookManagerPubFunc other); + bool Equal(const CProto &proto, int vtbl_offs, int vtbl_idx) const; + bool Equal(HookManagerPubFunc other) const; HookManagerPubFunc GetPubFunc(); }; diff --git a/core/sourcehook/sourcehook_impl.h b/core/sourcehook/sourcehook_impl.h index f9ef068f3..c73e3c589 100644 --- a/core/sourcehook/sourcehook_impl.h +++ b/core/sourcehook/sourcehook_impl.h @@ -322,6 +322,9 @@ namespace SourceHook int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post); + int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + const SHDelegateHandler &handler, bool post); + bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post); @@ -355,6 +358,8 @@ namespace SourceHook void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc); + void RemoveHookManager(Plugin plug, const HookManagerPubFuncHandler &pubFunc); + void SetIgnoreHooks(void *vfnptr); void ResetIgnoreHooks(void *vfnptr); diff --git a/core/sourcehook/sourcehook_impl_chook.h b/core/sourcehook/sourcehook_impl_chook.h index 2050ed795..aef773ea8 100644 --- a/core/sourcehook/sourcehook_impl_chook.h +++ b/core/sourcehook/sourcehook_impl_chook.h @@ -20,7 +20,7 @@ namespace SourceHook // *** Data *** Plugin m_OwnerPlugin; int m_ThisPointerOffset; - ISHDelegate *m_pHandler; + SHDelegateHandler m_pHandler; int m_HookID; bool m_Paused; public: @@ -30,9 +30,9 @@ namespace SourceHook { Plugin m_OwnerPlugin; int m_ThisPointerOffset; - ISHDelegate *m_pHandler; + SHDelegateHandler m_pHandler; - Descriptor(Plugin ownerPlugin, int thisPtrOffset, ISHDelegate *pHandler) + Descriptor(Plugin ownerPlugin, int thisPtrOffset, const SHDelegateHandler &pHandler) : m_OwnerPlugin(ownerPlugin), m_ThisPointerOffset(thisPtrOffset), m_pHandler(pHandler) { @@ -40,7 +40,7 @@ namespace SourceHook }; // *** Interface *** - inline CHook(Plugin ownerPlugin, int thisPtrOffset, ISHDelegate *pHandler, int hookid, bool paused=false); + inline CHook(Plugin ownerPlugin, int thisPtrOffset, const SHDelegateHandler &pHandler, int hookid, bool paused=false); inline bool operator==(const Descriptor &other) const; inline bool operator==(int hookid) const; inline Plugin GetOwnerPlugin() const; @@ -52,7 +52,7 @@ namespace SourceHook }; // *** Implementation *** - inline CHook::CHook(Plugin ownerPlugin, int thisPtrOffset, ISHDelegate *pHandler, int hookid, bool paused) + inline CHook::CHook(Plugin ownerPlugin, int thisPtrOffset, const SHDelegateHandler &pHandler, int hookid, bool paused) : m_OwnerPlugin(ownerPlugin), m_ThisPointerOffset(thisPtrOffset), m_pHandler(pHandler), m_HookID(hookid), m_Paused(paused) { @@ -82,7 +82,7 @@ namespace SourceHook inline ISHDelegate *CHook::GetHandler() const { - return m_pHandler; + return m_pHandler.Get(); } inline void CHook::SetPaused(bool value) diff --git a/core/sourcehook/sourcehook_impl_chookidman.cpp b/core/sourcehook/sourcehook_impl_chookidman.cpp index 29a3d09a7..e16ecf42b 100644 --- a/core/sourcehook/sourcehook_impl_chookidman.cpp +++ b/core/sourcehook/sourcehook_impl_chookidman.cpp @@ -19,15 +19,34 @@ namespace SourceHook { } + void CHookIDManager::OptimizeEntryVector() + { + const size_t curSize = m_Entries.size(); + size_t newSize = curSize; + for(size_t i = m_Entries.size(); i != 0; --i) + { + const size_t entryIndex = i - 1; + if (!m_Entries[entryIndex].IsFree()) + break; + + newSize = entryIndex; + } + + if(curSize != newSize) + { + m_Entries.resize(newSize); + } + } + int CHookIDManager::New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr, - void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post) + void *adjustediface, Plugin plug, int thisptr_offs, const SHDelegateHandler &handler, bool post) { Entry tmp(proto, vtbl_offs, vtbl_idx, vfnptr, adjustediface, plug, thisptr_offs, handler, post); size_t cursize = m_Entries.size(); for (size_t i = 0; i < cursize; ++i) { - if (m_Entries[i].isfree) + if (m_Entries[i].IsFree()) { m_Entries[i] = tmp; return static_cast(i) + 1; @@ -41,20 +60,20 @@ namespace SourceHook bool CHookIDManager::Remove(int hookid) { int realid = hookid - 1; - if (realid < 0 || realid >= static_cast(m_Entries.size()) || m_Entries[realid].isfree) + if (realid < 0 || realid >= static_cast(m_Entries.size()) || m_Entries[realid].IsFree()) return false; - m_Entries[realid].isfree = true; + m_Entries[realid].Reset(); - // :TODO: remove free ids from back sometimes ?? + OptimizeEntryVector(); return true; } - const CHookIDManager::Entry * CHookIDManager::QueryHook(int hookid) + const CHookIDManager::Entry *CHookIDManager::QueryHook(int hookid) { int realid = hookid - 1; - if (realid < 0 || realid >= static_cast(m_Entries.size()) || m_Entries[realid].isfree) + if (realid < 0 || realid >= static_cast(m_Entries.size()) || m_Entries[realid].IsFree()) return NULL; return &m_Entries[realid]; @@ -67,7 +86,7 @@ namespace SourceHook size_t cursize = m_Entries.size(); for (size_t i = 0; i < cursize; ++i) { - if (!m_Entries[i].isfree && m_Entries[i].proto == proto && m_Entries[i].vtbl_offs == vtbl_offs && + if (!m_Entries[i].IsFree() && m_Entries[i].proto == proto && m_Entries[i].vtbl_offs == vtbl_offs && m_Entries[i].vtbl_idx == vtbl_idx && m_Entries[i].adjustediface == adjustediface && m_Entries[i].plug == plug && m_Entries[i].thisptr_offs == thisptr_offs && m_Entries[i].handler->IsEqual(handler) && m_Entries[i].post == post) { @@ -81,7 +100,7 @@ namespace SourceHook size_t cursize = m_Entries.size(); for (size_t i = 0; i < cursize; ++i) { - if (!m_Entries[i].isfree) + if (!m_Entries[i].IsFree()) output.push_back(static_cast(i) + 1); } } @@ -91,7 +110,7 @@ namespace SourceHook size_t cursize = m_Entries.size(); for (size_t i = 0; i < cursize; ++i) { - if (!m_Entries[i].isfree && m_Entries[i].plug == plug) + if (!m_Entries[i].IsFree() && m_Entries[i].plug == plug) output.push_back(static_cast(i) + 1); } } @@ -102,9 +121,13 @@ namespace SourceHook size_t cursize = m_Entries.size(); for (size_t i = 0; i < cursize; ++i) { - if (!m_Entries[i].isfree && m_Entries[i].vfnptr == vfnptr) - m_Entries[i].isfree = true; + if (!m_Entries[i].IsFree() && m_Entries[i].vfnptr == vfnptr) + { + m_Entries[i].Reset(); + } } + + OptimizeEntryVector(); } } diff --git a/core/sourcehook/sourcehook_impl_chookidman.h b/core/sourcehook/sourcehook_impl_chookidman.h index 03f0bc590..f5a94eb66 100644 --- a/core/sourcehook/sourcehook_impl_chookidman.h +++ b/core/sourcehook/sourcehook_impl_chookidman.h @@ -24,8 +24,6 @@ namespace SourceHook public: struct Entry { - bool isfree; - // hookman info CProto proto; int vtbl_offs; @@ -40,12 +38,22 @@ namespace SourceHook // hook Plugin plug; int thisptr_offs; - ISHDelegate *handler; + SHDelegateHandler handler; bool post; + bool IsFree() const + { + return handler.Get() == nullptr; + } + + void Reset() + { + handler.Reset(); + } + Entry(const CProto &pprt, int pvo, int pvi, void *pvp, void *pai, Plugin pplug, int pto, - ISHDelegate *ph, bool ppost) - : isfree(false), proto(pprt), vtbl_offs(pvo), vtbl_idx(pvi), vfnptr(pvp), + const SHDelegateHandler &ph, bool ppost) + : proto(pprt), vtbl_offs(pvo), vtbl_idx(pvi), vfnptr(pvp), adjustediface(pai), plug(pplug), thisptr_offs(pto), handler(ph), post(ppost) { } @@ -57,10 +65,14 @@ namespace SourceHook // Internally, hookid 1 is stored as m_Entries[0] CVector m_Entries; + + // Remove free entries from back + void OptimizeEntryVector(); + public: CHookIDManager(); int New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr, void *adjustediface, - Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post); + Plugin plug, int thisptr_offs, const SHDelegateHandler &handler, bool post); bool Remove(int hookid); const Entry * QueryHook(int hookid); diff --git a/core/sourcehook/sourcehook_impl_chookmaninfo.cpp b/core/sourcehook/sourcehook_impl_chookmaninfo.cpp index 639b7a2a9..bb497f723 100644 --- a/core/sourcehook/sourcehook_impl_chookmaninfo.cpp +++ b/core/sourcehook/sourcehook_impl_chookmaninfo.cpp @@ -15,7 +15,7 @@ namespace SourceHook { namespace Impl { - CHookManager::CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc) + CHookManager::CHookManager(Plugin ownerPlugin, const HookManagerPubFuncHandler& pubFunc) : m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc), m_Version(-1) { // Query pubfunc @@ -37,6 +37,16 @@ namespace SourceHook m_HookfuncVfnptr = hookfunc_vfnptr; } + void CHookManager::SetInfo(int hookman_version, int vtbloffs, int vtblidx, + IProtoInfo *proto, void *hookfunc_vfnptr) + { + m_Version = hookman_version; + m_VtblOffs = vtbloffs; + m_VtblIdx = vtblidx; + m_Proto = proto; + m_HookfuncVfnptr = hookfunc_vfnptr; + } + void CHookManager::Register() { m_PubFunc(true, this); @@ -61,7 +71,7 @@ namespace SourceHook Unregister(); } - CHookManager *CHookManList::GetHookMan(Plugin plug, HookManagerPubFunc pubFunc) + CHookManager *CHookManList::GetHookMan(Plugin plug, const HookManagerPubFuncHandler &pubFunc) { CHookManager hm(plug, pubFunc); return GetHookMan(hm); diff --git a/core/sourcehook/sourcehook_impl_chookmaninfo.h b/core/sourcehook/sourcehook_impl_chookmaninfo.h index 6a805ea9c..5d7578525 100644 --- a/core/sourcehook/sourcehook_impl_chookmaninfo.h +++ b/core/sourcehook/sourcehook_impl_chookmaninfo.h @@ -24,7 +24,7 @@ namespace SourceHook { // *** Data *** Plugin m_OwnerPlugin; - HookManagerPubFunc m_PubFunc; + HookManagerPubFuncHandler m_PubFunc; int m_VtblOffs; int m_VtblIdx; CProto m_Proto; @@ -38,15 +38,15 @@ namespace SourceHook struct Descriptor { Plugin m_OwnerPlugin; - HookManagerPubFunc m_PubFunc; - Descriptor(Plugin ownerPlugin, HookManagerPubFunc pubFunc) + HookManagerPubFuncHandler m_PubFunc; + Descriptor(Plugin ownerPlugin, const HookManagerPubFuncHandler &pubFunc) : m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc) { } }; // *** Interface *** - CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc); + CHookManager(Plugin ownerPlugin, const HookManagerPubFuncHandler &pubFunc); inline bool operator==(const Descriptor &other) const; inline bool operator==(const CHookManager &other) const; @@ -58,7 +58,7 @@ namespace SourceHook inline const CProto &GetProto() const; inline int GetVersion() const; inline void *GetHookFunc() const; - inline HookManagerPubFunc GetPubFunc() const; + inline const HookManagerPubFuncHandler &GetPubFunc() const; void Register(); void Unregister(); @@ -74,12 +74,15 @@ namespace SourceHook // *** IHookManagerInfo interface *** void SetInfo(int hookman_version, int vtbloffs, int vtblidx, ProtoInfo *proto, void *hookfunc_vfnptr); + + void SetInfo(int hookman_version, int vtbloffs, int vtblidx, + IProtoInfo *proto, void *hookfunc_vfnptr); }; class CHookManList : public List { public: - CHookManager *GetHookMan(Plugin plug, HookManagerPubFunc pubFunc); + CHookManager *GetHookMan(Plugin plug, const HookManagerPubFuncHandler &pubFunc); CHookManager *GetHookMan(CHookManager &hm); }; @@ -132,7 +135,7 @@ namespace SourceHook return *reinterpret_cast(m_HookfuncVfnptr); } - inline HookManagerPubFunc CHookManager::GetPubFunc() const + inline const HookManagerPubFuncHandler &CHookManager::GetPubFunc() const { return m_PubFunc; } diff --git a/core/sourcehook/sourcehook_impl_ciface.h b/core/sourcehook/sourcehook_impl_ciface.h index 978c16a06..9bb0f50b0 100644 --- a/core/sourcehook/sourcehook_impl_ciface.h +++ b/core/sourcehook/sourcehook_impl_ciface.h @@ -48,16 +48,6 @@ namespace SourceHook inline CIface::~CIface() { - // Before getting deleted, delete all remaining hook handlers - for (List::iterator iter = m_PreHooks.begin(); iter != m_PreHooks.end(); ++iter) - { - iter->GetHandler()->DeleteThis(); - } - - for (List::iterator iter = m_PostHooks.begin(); iter != m_PostHooks.end(); ++iter) - { - iter->GetHandler()->DeleteThis(); - } } inline bool CIface::operator==(const Descriptor &other) diff --git a/core/sourcehook/sourcehook_impl_cproto.cpp b/core/sourcehook/sourcehook_impl_cproto.cpp index ff8af2886..a386c1036 100644 --- a/core/sourcehook/sourcehook_impl_cproto.cpp +++ b/core/sourcehook/sourcehook_impl_cproto.cpp @@ -37,7 +37,6 @@ namespace SourceHook m_RetPassInfo.pDtor = NULL; m_RetPassInfo.pAssignOperator = NULL; - m_ParamsPassInfo.resize(pProto->numOfParams); for (int i = 1; i <= pProto->numOfParams; ++i) @@ -89,6 +88,45 @@ namespace SourceHook } } + void CProto::Fill(const IProtoInfo *pProto) + { + if (pProto == nullptr) + m_Version = -1; + + m_ParamsPassInfo.clear(); + + m_Version = static_cast(pProto->GetVersion()); + m_Convention = pProto->GetConvention(); + m_NumOfParams = pProto->GetNumOfParams(); + + const PassInfo& retPassInfo = pProto->GetRetPassInfo(); + m_RetPassInfo.size = retPassInfo.size; + m_RetPassInfo.type = retPassInfo.type; + m_RetPassInfo.flags = retPassInfo.flags; + + const PassInfo::V2Info& retPassInfo2 = pProto->GetRetPassInfo2(); + m_RetPassInfo.pNormalCtor = retPassInfo2.pNormalCtor; // should be nullptr for Version 1 + m_RetPassInfo.pCopyCtor = retPassInfo2.pCopyCtor; // should be nullptr for Version 1 + m_RetPassInfo.pDtor = retPassInfo2.pDtor; // should be nullptr for Version 1 + m_RetPassInfo.pAssignOperator = retPassInfo2.pAssignOperator; // should be nullptr for Version 1 + + m_ParamsPassInfo.resize(pProto->GetNumOfParams()); + + const PassInfo* paramsPassInfo = pProto->GetParamsPassInfo(); + const PassInfo::V2Info* paramsPassInfo2 = pProto->GetParamsPassInfo2(); + for (int i = 0; i != m_NumOfParams; ++i) + { + m_ParamsPassInfo[i].size = paramsPassInfo[i].size; + m_ParamsPassInfo[i].type = paramsPassInfo[i].type; + m_ParamsPassInfo[i].flags = paramsPassInfo[i].flags; + + m_ParamsPassInfo[i].pNormalCtor = paramsPassInfo2[i].pNormalCtor; // should be nullptr for Version 1 + m_ParamsPassInfo[i].pCopyCtor = paramsPassInfo2[i].pCopyCtor; // should be nullptr for Version 1 + m_ParamsPassInfo[i].pDtor = paramsPassInfo2[i].pDtor; // should be nullptr for Version 1 + m_ParamsPassInfo[i].pAssignOperator = paramsPassInfo2[i].pAssignOperator; // should be nullptr for Version 1 + } + } + // Basic compat test // Other than this, we assume that the plugins know what they're doing bool CProto::operator == (const CProto &other) const diff --git a/core/sourcehook/sourcehook_impl_cproto.h b/core/sourcehook/sourcehook_impl_cproto.h index cb436f115..c209dba6a 100644 --- a/core/sourcehook/sourcehook_impl_cproto.h +++ b/core/sourcehook/sourcehook_impl_cproto.h @@ -53,6 +53,8 @@ namespace SourceHook void Fill(const ProtoInfo *pProto); + void Fill(const IProtoInfo *pProto); + // For old sourcehook.h: flags 0 -> assume ByVal static unsigned int GetRealFlags(const PassInfo &info) { @@ -69,6 +71,11 @@ namespace SourceHook Fill(pProto); } + CProto(const IProtoInfo *pProto) + { + Fill(pProto); + } + CProto(const CProto &other) : m_Version(other.m_Version), m_NumOfParams(other.m_NumOfParams), m_RetPassInfo(other.m_RetPassInfo), m_ParamsPassInfo(other.m_ParamsPassInfo), m_Convention(other.m_Convention)