fix: port to KHook for Metamod 2.0 build 1461+
Some checks failed
Continuous Integration / Build on Linux via Docker Compose (push) Has been cancelled
Continuous Integration / Build on Windows (MSVC) (push) Has been cancelled
Continuous Integration / Release (push) Has been cancelled

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 971e91c711
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/entitysystem.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.h
)

View file

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

View file

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

View file

@ -1,4 +1,4 @@
//
//
// Created by Michal Přikryl on 10.07.2025.
// Copyright (c) 2025 slynxcz. All rights reserved.
//
@ -6,32 +6,45 @@
#include <raytrace.h>
#include <shared.h>
#include <dynlibutils/module.h>
#include <khook.hpp>
class GameSessionConfiguration_t
{
};
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*);
SH_DECL_HOOK2(IGameEventManager2, LoadEventsFromFile, SH_NOATTRIB, 0, int, const char*, bool);
static KHook::Virtual<INetworkServerService, void, const GameSessionConfiguration_t&, ISource2WorldSession*, const char*>
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() {
SH_ADD_HOOK(INetworkServerService, StartupServer, shared::g_pNetworkServerService, SH_MEMBER(&sourceHooks, &SourceHooks::Hook_StartupServer), true);
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_StartupServer.Add(shared::g_pNetworkServerService);
g_pGameEventManagerVTable = DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CGameEventManager").RCast<void*>();
if (g_pGameEventManagerVTable)
g_LoadEventsFromFile.AddGlobal(reinterpret_cast<IGameEventManager2*>(&g_pGameEventManagerVTable));
}
void DestructListeners() {
SH_REMOVE_HOOK(INetworkServerService, StartupServer, shared::g_pNetworkServerService, SH_MEMBER(&sourceHooks, &SourceHooks::Hook_StartupServer), true);
SH_REMOVE_HOOK_ID(g_iLoadEventsFromFileId);
g_StartupServer.Remove(shared::g_pNetworkServerService);
if (g_pGameEventManagerVTable)
g_LoadEventsFromFile.RemoveGlobal(reinterpret_cast<IGameEventManager2*>(&g_pGameEventManagerVTable));
}
void SourceHooks::Hook_StartupServer(const GameSessionConfiguration_t& config,
ISource2WorldSession*, const char*)
static KHook::Return<void> Hook_StartupServer(INetworkServerService*, const GameSessionConfiguration_t&,
ISource2WorldSession*, const char*)
{
if (!shared::g_bDetoursLoaded)
{
@ -39,11 +52,12 @@ namespace RayTracePlugin::Listeners {
RayTrace::g_CRayTrace.Initialize();
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));
RETURN_META_VALUE(MRES_IGNORED, 0);
ExecuteOnce(shared::g_pGameEventManager = self);
return { KHook::Action::Ignore, 0 };
}
}

View file

@ -4,19 +4,10 @@
//
#pragma once
#include <eiface.h>
#include <sourcehook.h>
#include <iserver.h>
namespace RayTracePlugin::Listeners {
void InitListeners();
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
#include <platform.h>
#include "soundflags.h"
#include <ray.h>
// struct TransmitInfo
// {

View file

@ -6,8 +6,6 @@
#include <icvar.h>
#include <iserver.h>
#include <schemasystem.h>
#include <sourcehook/sourcehook.h>
#include <sourcehook/sourcehook_impl.h>
namespace RayTracePlugin::shared
{
@ -27,11 +25,6 @@ namespace RayTracePlugin::shared
CGameResourceService *g_pGameResourceServiceServer = 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() {
INetworkGameServer *server = g_pNetworkServerService->GetIGameServer();
if (!server) return nullptr;

View file

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