@@ -44,6 +44,20 @@ using namespace SourceHook::Impl;
4444
4545SourceHook::ISourceHook* g_SHPtr = nullptr ;
4646
47+ struct CSourceHookImplFriend {
48+ typedef HookContextStack CSourceHookImpl::* type;
49+ friend type get (CSourceHookImplFriend);
50+ };
51+
52+ template <typename Tag, typename Tag::type M>
53+ struct CSourceHookImplAccessor {
54+ friend typename Tag::type get (Tag) {
55+ return M;
56+ }
57+ };
58+
59+ template struct CSourceHookImplAccessor <CSourceHookImplFriend, &CSourceHookImpl::m_ContextStack>;
60+
4761namespace mm {
4862 PlugifyPlugin g_Plugin;
4963 PLUGIN_EXPOSE (PlugifyPlugin, g_Plugin);
@@ -531,6 +545,143 @@ namespace mm {
531545 }
532546 static ConCommand plg_command (" plg" , plugify_callback, " Plugify control options" , 0 );
533547
548+ using FindOriginalAddrFn = void * (*) (void * pClass, void * pAddr);
549+ FindOriginalAddrFn _FindOriginalAddr;
550+ bool FindOriginalAddr () {
551+ if (_FindOriginalAddr == nullptr ) {
552+ Assembly polyhook (" polyhook" , LoadFlag::Lazy | LoadFlag::Now);
553+ if (polyhook) {
554+ _FindOriginalAddr = polyhook.GetFunctionByName (" FindOriginalAddr" ).CCast <FindOriginalAddrFn>();
555+ }
556+ else
557+ {
558+ throw std::runtime_error (" PolyHook not found, therefore SourceHook could not be patched.\n " );
559+ }
560+ }
561+ return _FindOriginalAddr != nullptr ;
562+ }
563+
564+ using SetupHookLoopFn = IHookContext* (*) (CSourceHookImpl* sh, CHookManager* hi, void * vfnptr, void * thisptr, void ** origCallAddr, META_RES* statusPtr, META_RES* prevResPtr, META_RES* curResPtr, const void * origRetPtr, void * overrideRetPtr);
565+ [[maybe_unused]] SetupHookLoopFn _SetupHookLoop;
566+ IHookContext* SetupHookLoop (CSourceHookImpl* sh, CHookManager* hi, void * vfnptr, void * thisptr, void ** origCallAddr, META_RES* statusPtr, META_RES* prevResPtr, META_RES* curResPtr, const void * origRetPtr, void * overrideRetPtr) {
567+ HookContextStack& contextStack = sh->*get (CSourceHookImplFriend ());
568+ CHookContext* pCtx = NULL ;
569+ CHookContext* oldctx = contextStack.empty () ? NULL : &contextStack.front ();
570+ if (oldctx) {
571+ // SH_CALL
572+ if (oldctx->m_State == CHookContext::State_Ignore) {
573+ *statusPtr = MRES_IGNORED;
574+ oldctx->m_CallOrig = true ;
575+ oldctx->m_State = CHookContext::State_Dead;
576+
577+ List<CVfnPtr*>& vfnptr_list = hi->GetVfnPtrList ();
578+ List<CVfnPtr*>::iterator vfnptr_iter;
579+ for (vfnptr_iter = vfnptr_list.begin ();
580+ vfnptr_iter != vfnptr_list.end (); ++vfnptr_iter) {
581+ if (**vfnptr_iter == vfnptr)
582+ break ;
583+ }
584+
585+ // Workaround for overhooking
586+ if (vfnptr_iter == vfnptr_list.end () && FindOriginalAddr ()) {
587+ void * origPtr = _FindOriginalAddr (thisptr, *(void **) vfnptr);
588+ if (origPtr != nullptr ) {
589+ for (vfnptr_iter = vfnptr_list.begin ();
590+ vfnptr_iter != vfnptr_list.end (); ++vfnptr_iter) {
591+ void ** ptr = (void **) (*vfnptr_iter)->GetPtr ();
592+ if (*ptr == origPtr)
593+ {
594+ break ;
595+ }
596+ }
597+ }
598+ }
599+
600+ if (vfnptr_iter == vfnptr_list.end ()) {
601+ // ASSERT
602+ std::puts (" Could not find original address" );
603+ std::terminate ();
604+ } else {
605+ *origCallAddr = (*vfnptr_iter)->GetOrigCallAddr ();
606+ oldctx->pVfnPtr = *vfnptr_iter;
607+ }
608+
609+ oldctx->pOrigRet = origRetPtr;
610+
611+ return oldctx;
612+ }
613+ // Recall
614+ if (oldctx->m_State >= CHookContext::State_Recall_Pre && oldctx->m_State <= CHookContext::State_Recall_PostVP) {
615+ pCtx = oldctx;
616+
617+ *statusPtr = *(oldctx->pStatus );
618+ *prevResPtr = *(oldctx->pPrevRes );
619+
620+ pCtx->m_Iter = oldctx->m_Iter ;
621+
622+ // Only have possibility of calling the orig func in pre recall mode
623+ pCtx->m_CallOrig = (oldctx->m_State == CHookContext::State_Recall_Pre || oldctx->m_State == CHookContext::State_Recall_PreVP);
624+
625+ overrideRetPtr = pCtx->pOverrideRet ;
626+
627+ // When the status is low so there's no override return value and we're in a post recall,
628+ // give it the orig return value as override return value.
629+ if (pCtx->m_State == CHookContext::State_Recall_Post || pCtx->m_State == CHookContext::State_Recall_PostVP) {
630+ origRetPtr = oldctx->pOrigRet ;
631+ if (*statusPtr < MRES_OVERRIDE)
632+ overrideRetPtr = const_cast <void *>(pCtx->pOrigRet );
633+ }
634+ }
635+ }
636+ if (!pCtx) {
637+ pCtx = contextStack.make_next ();
638+ pCtx->m_State = CHookContext::State_Born;
639+ pCtx->m_CallOrig = true ;
640+ }
641+
642+ pCtx->pIface = NULL ;
643+
644+ List<CVfnPtr*>& vfnptr_list = hi->GetVfnPtrList ();
645+ List<CVfnPtr*>::iterator vfnptr_iter;
646+ for (vfnptr_iter = vfnptr_list.begin ();
647+ vfnptr_iter != vfnptr_list.end (); ++vfnptr_iter) {
648+ if (**vfnptr_iter == vfnptr)
649+ break ;
650+ }
651+
652+ // Workaround for overhooking
653+ if (vfnptr_iter == vfnptr_list.end () && FindOriginalAddr ()) {
654+ void * origPtr = _FindOriginalAddr (thisptr, *(void **) vfnptr);
655+ if (origPtr != nullptr ) {
656+ for (vfnptr_iter = vfnptr_list.begin ();
657+ vfnptr_iter != vfnptr_list.end (); ++vfnptr_iter) {
658+ void ** ptr = (void **) (*vfnptr_iter)->GetPtr ();
659+ if (*ptr == origPtr)
660+ {
661+ break ;
662+ }
663+ }
664+ }
665+ }
666+
667+ if (vfnptr_iter == vfnptr_list.end ()) {
668+ pCtx->m_State = CHookContext::State_Dead;
669+ } else {
670+ pCtx->pVfnPtr = *vfnptr_iter;
671+ *origCallAddr = pCtx->pVfnPtr ->GetOrigCallAddr ();
672+ pCtx->pIface = pCtx->pVfnPtr ->FindIface (thisptr);
673+ }
674+
675+ pCtx->pStatus = statusPtr;
676+ pCtx->pPrevRes = prevResPtr;
677+ pCtx->pCurRes = curResPtr;
678+ pCtx->pThisPtr = thisptr;
679+ pCtx->pOverrideRet = overrideRetPtr;
680+ pCtx->pOrigRet = origRetPtr;
681+
682+ return pCtx;
683+ }
684+
534685 using ServerGamePostSimulateFn = void (*)(IGameSystem*, const EventServerGamePostSimulate_t&);
535686 ServerGamePostSimulateFn _ServerGamePostSimulate;
536687 void ServerGamePostSimulate (IGameSystem* pThis, const EventServerGamePostSimulate_t& msg) {
@@ -559,6 +710,7 @@ namespace mm {
559710
560711 pluginManager->Terminate ();
561712 CONPRINT (" Plugin manager was unloaded.\n " );
713+ _FindOriginalAddr = nullptr ;
562714
563715 if (auto packageManager = g_Plugin.m_context ->GetPackageManager ().lock ()) {
564716 packageManager->Reload ();
@@ -573,6 +725,7 @@ namespace mm {
573725 }
574726
575727 pluginManager->Terminate ();
728+ _FindOriginalAddr = nullptr ;
576729
577730 if (auto packageManager = g_Plugin.m_context ->GetPackageManager ().lock ()) {
578731 packageManager->Reload ();
@@ -611,6 +764,11 @@ namespace mm {
611764 _ServerGamePostSimulate = HookMethod (&table, &ServerGamePostSimulate, offset);
612765 }
613766
767+ if (g_SHPtr != nullptr ) {
768+ int offset = GetVirtualTableIndex (&ISourceHook::SetupHookLoop);
769+ _SetupHookLoop = HookMethod (g_SHPtr, &SetupHookLoop, offset);
770+ }
771+
614772 m_context = MakePlugify ();
615773
616774 m_logger = std::make_shared<MMLogger>(" plugify" );
@@ -711,7 +869,7 @@ SMM_API PluginId Plugify_Id() {
711869SMM_API SourceHook::ISourceHook* Plugify_SourceHook () {
712870 return mm::g_SHPtr;
713871}
714-
872+ /*
715873struct CSourceHookFriend {
716874 typedef CHookIDManager CSourceHookImpl::* type;
717875 friend type get(CSourceHookFriend);
@@ -743,10 +901,10 @@ SMM_API bool Plugify_SourceHooked(void* vfnptr) {
743901 const CHookIDManager& hookIdManager = sh.*get(CSourceHookFriend());
744902 for (const CHookIDManager::Entry& entry : hookIdManager.*get(CHookIDManagerFriend())) {
745903 if (entry.vfnptr == vfnptr) {
746- CONPRINT (std::format (" Sourcehooked **vfnptr** was pathed: {}\n " , vfnptr).c_str ());
904+ // CONPRINT(std::format("Sourcehooked **vfnptr** was pathed: {}\n", vfnptr).c_str());
747905 return true;
748906 }
749907 }
750908 //CONPRINTE(std::format("**vfnptr** was not pathed!!!\n", vfnptr).c_str());
751909 return false;
752- }
910+ }*/
0 commit comments