fix: port to KHook for Metamod 2.0 build 1461+

Metamod 1461+ removed SourceHook (plugin API 17 -> 18), so the MM plugin was rejected
and RayTraceImpl crashed on a null CRayTraceInterface002. Replace the two SourceHook
hooks with KHook, build against Metamod's bundled KHook headers, include ray.h
explicitly for the updated hl2sdk, and disambiguate TraceOptions/TraceResult from
CounterStrikeSharp 1.0.375's new types of the same name.
This commit is contained in:
Astra 2026-09-24 16:44:53 +01:00
parent 616e169a2c
commit 4860eaaffb
8 changed files with 33 additions and 46 deletions

View file

@ -41,11 +41,6 @@ list(APPEND SOURCE_FILES
${SOURCESDK_DIR}/entity2/entityidentity.cpp ${SOURCESDK_DIR}/entity2/entityidentity.cpp
${SOURCESDK_DIR}/entity2/entitysystem.cpp ${SOURCESDK_DIR}/entity2/entitysystem.cpp
${SOURCESDK_DIR}/entity2/entitykeyvalues.cpp ${SOURCESDK_DIR}/entity2/entitykeyvalues.cpp
${METAMOD_DIR}/core/sourcehook/sourcehook.cpp
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_chookidman.cpp
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_chookmaninfo.cpp
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_cvfnptr.cpp
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_cproto.cpp
vendor/dynlibutils/module.cpp vendor/dynlibutils/module.cpp
vendor/dynlibutils/module.h vendor/dynlibutils/module.h
) )

View file

@ -59,8 +59,7 @@ include_directories(
${SOURCESDK}/public/game/server ${SOURCESDK}/public/game/server
${SOURCESDK}/public/schemasystem ${SOURCESDK}/public/schemasystem
${METAMOD_DIR}/core ${METAMOD_DIR}/core
${METAMOD_DIR}/core/sourcehook ${METAMOD_DIR}/third_party/khook/include
vendor/khook/include
vendor/spdlog/include vendor/spdlog/include
vendor/nlohmann vendor/nlohmann
vendor vendor

View file

@ -21,6 +21,8 @@ using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using RayTraceAPI; using RayTraceAPI;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
using TraceOptions = RayTraceAPI.TraceOptions;
using TraceResult = RayTraceAPI.TraceResult;
namespace RayTraceImpl; namespace RayTraceImpl;

View file

@ -1,4 +1,4 @@
// //
// Created by Michal Přikryl on 10.07.2025. // Created by Michal Přikryl on 10.07.2025.
// Copyright (c) 2025 slynxcz. All rights reserved. // Copyright (c) 2025 slynxcz. All rights reserved.
// //
@ -6,32 +6,45 @@
#include <raytrace.h> #include <raytrace.h>
#include <shared.h> #include <shared.h>
#include <dynlibutils/module.h> #include <dynlibutils/module.h>
#include <khook.hpp>
class GameSessionConfiguration_t class GameSessionConfiguration_t
{ {
}; };
namespace RayTracePlugin::Listeners { namespace RayTracePlugin::Listeners {
SourceHooks sourceHooks; // Metamod 2.0 build 1461+ dropped SourceHook for KHook; these replace the old SH_DECL_HOOK*s.
static KHook::Return<void> Hook_StartupServer(INetworkServerService*, const GameSessionConfiguration_t&,
ISource2WorldSession*, const char*);
static KHook::Return<int> Hook_LoadEventsFromFile(IGameEventManager2* self, const char* filename, bool bSearchAll);
SH_DECL_HOOK3_void(INetworkServerService, StartupServer, SH_NOATTRIB, 0, const GameSessionConfiguration_t&, ISource2WorldSession*, const char*); static KHook::Virtual<INetworkServerService, void, const GameSessionConfiguration_t&, ISource2WorldSession*, const char*>
SH_DECL_HOOK2(IGameEventManager2, LoadEventsFromFile, SH_NOATTRIB, 0, int, const char*, bool); g_StartupServer(&INetworkServerService::StartupServer, nullptr, &Hook_StartupServer);
int g_iLoadEventsFromFileId = -1; static KHook::Virtual<IGameEventManager2, int, const char*, bool>
g_LoadEventsFromFile(&IGameEventManager2::LoadEventsFromFile, &Hook_LoadEventsFromFile, nullptr);
// AddGlobal() reads the vtable from the first word of the "object" it is given, so hooking a raw
// vtable (the old SH_ADD_DVPHOOK) means passing a pointer to a slot that holds the vtable address.
static void* g_pGameEventManagerVTable = nullptr;
void InitListeners() { void InitListeners() {
SH_ADD_HOOK(INetworkServerService, StartupServer, shared::g_pNetworkServerService, SH_MEMBER(&sourceHooks, &SourceHooks::Hook_StartupServer), true); g_StartupServer.Add(shared::g_pNetworkServerService);
auto pCGameEventManagerVTable = DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CGameEventManager").RCast<IGameEventManager2*>();
g_iLoadEventsFromFileId = SH_ADD_DVPHOOK(IGameEventManager2, LoadEventsFromFile, pCGameEventManagerVTable, SH_MEMBER(&sourceHooks, &SourceHooks::Hook_LoadEventsFromFile), false); g_pGameEventManagerVTable = DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CGameEventManager").RCast<void*>();
if (g_pGameEventManagerVTable)
g_LoadEventsFromFile.AddGlobal(reinterpret_cast<IGameEventManager2*>(&g_pGameEventManagerVTable));
} }
void DestructListeners() { void DestructListeners() {
SH_REMOVE_HOOK(INetworkServerService, StartupServer, shared::g_pNetworkServerService, SH_MEMBER(&sourceHooks, &SourceHooks::Hook_StartupServer), true); g_StartupServer.Remove(shared::g_pNetworkServerService);
SH_REMOVE_HOOK_ID(g_iLoadEventsFromFileId);
if (g_pGameEventManagerVTable)
g_LoadEventsFromFile.RemoveGlobal(reinterpret_cast<IGameEventManager2*>(&g_pGameEventManagerVTable));
} }
void SourceHooks::Hook_StartupServer(const GameSessionConfiguration_t& config, static KHook::Return<void> Hook_StartupServer(INetworkServerService*, const GameSessionConfiguration_t&,
ISource2WorldSession*, const char*) ISource2WorldSession*, const char*)
{ {
if (!shared::g_bDetoursLoaded) if (!shared::g_bDetoursLoaded)
{ {
@ -39,11 +52,12 @@ namespace RayTracePlugin::Listeners {
RayTrace::g_CRayTrace.Initialize(); RayTrace::g_CRayTrace.Initialize();
shared::g_bDetoursLoaded = true; shared::g_bDetoursLoaded = true;
} }
return { KHook::Action::Ignore };
} }
int SourceHooks::Hook_LoadEventsFromFile(const char* filename, bool bSearchAll) static KHook::Return<int> Hook_LoadEventsFromFile(IGameEventManager2* self, const char* filename, bool bSearchAll)
{ {
ExecuteOnce(shared::g_pGameEventManager = META_IFACEPTR(IGameEventManager2)); ExecuteOnce(shared::g_pGameEventManager = self);
RETURN_META_VALUE(MRES_IGNORED, 0); return { KHook::Action::Ignore, 0 };
} }
} }

View file

@ -4,19 +4,10 @@
// //
#pragma once #pragma once
#include <eiface.h> #include <eiface.h>
#include <sourcehook.h>
#include <iserver.h> #include <iserver.h>
namespace RayTracePlugin::Listeners { namespace RayTracePlugin::Listeners {
void InitListeners(); void InitListeners();
void DestructListeners(); void DestructListeners();
class SourceHooks {
public:
void Hook_StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession*, const char*);
int Hook_LoadEventsFromFile(const char* filename, bool bSearchAll);
};
extern SourceHooks sourceHooks;
} }

View file

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <platform.h> #include <platform.h>
#include "soundflags.h" #include "soundflags.h"
#include <ray.h>
// struct TransmitInfo // struct TransmitInfo
// { // {

View file

@ -6,8 +6,6 @@
#include <icvar.h> #include <icvar.h>
#include <iserver.h> #include <iserver.h>
#include <schemasystem.h> #include <schemasystem.h>
#include <sourcehook/sourcehook.h>
#include <sourcehook/sourcehook_impl.h>
namespace RayTracePlugin::shared namespace RayTracePlugin::shared
{ {
@ -27,11 +25,6 @@ namespace RayTracePlugin::shared
CGameResourceService *g_pGameResourceServiceServer = nullptr; CGameResourceService *g_pGameResourceServiceServer = nullptr;
CGameConfig *g_pGameConfig = nullptr; CGameConfig *g_pGameConfig = nullptr;
SourceHook::Impl::CSourceHookImpl source_hook_impl;
SourceHook::ISourceHook* source_hook = &source_hook_impl;
int source_hook_pluginid = 0;
CGlobalVars *getGlobalVars() { CGlobalVars *getGlobalVars() {
INetworkGameServer *server = g_pNetworkServerService->GetIGameServer(); INetworkGameServer *server = g_pNetworkServerService->GetIGameServer();
if (!server) return nullptr; if (!server) return nullptr;

View file

@ -11,7 +11,6 @@
#include <gameconfig.h> #include <gameconfig.h>
#include <igameeventsystem.h> #include <igameeventsystem.h>
#include "schema/cgameresourceserviceserver.h" #include "schema/cgameresourceserviceserver.h"
#include <sourcehook/sourcehook.h>
class CGameEntitySystem; class CGameEntitySystem;
@ -33,15 +32,8 @@ namespace RayTracePlugin::shared
extern CGameResourceService* g_pGameResourceServiceServer; extern CGameResourceService* g_pGameResourceServiceServer;
extern CGameConfig *g_pGameConfig; extern CGameConfig *g_pGameConfig;
extern SourceHook::ISourceHook *source_hook;
extern int source_hook_pluginid;
CGlobalVars* getGlobalVars(); CGlobalVars* getGlobalVars();
extern bool g_bDetoursLoaded; extern bool g_bDetoursLoaded;
} }
#undef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR RayTracePlugin::shared::source_hook
#undef SH_GLOB_PLUGPTR
#define SH_GLOB_PLUGPTR RayTracePlugin::shared::source_hook_pluginid