# Ray-Trace **Shared ray tracing interface for Metamod:Source & CounterStrikeSharp plugins** ------------------------------------------------------------------------ ## Overview `Ray-Trace` is a lightweight **Metamod interface module** for\ **Counter-Strike 2** servers. It exposes a shared interface: `CRayTraceInterface002` which can be consumed from: - Native **Metamod C++ plugins** - Managed **CounterStrikeSharp C# plugins** The interface is implemented as a **C++ virtual class** and is accessed from C# by calling its **vtable functions directly** using a native handle. The goal is to provide a **single tracing backend** usable from both worlds without duplicating engine detours. ------------------------------------------------------------------------ ## Features - Metamod meta interface (`CRayTraceInterface002`) - Works in **C++ and C#** - Physics / hitbox / world trace presets - Custom collision masks - Optional debug beam rendering - Zero configuration - Ultra low overhead - ABI-safe (no STL types in interface) - Virtual destructor for safe lifetime management ------------------------------------------------------------------------ ## Exposed Interface (C++) ``` cpp class CRayTraceInterface { public: virtual ~CRayTraceInterface() = default; virtual bool TraceShape( const Vector* pOrigin, const QAngle* pViewAngles, CBaseEntity* pIgnoreEntity, const TraceOptions* pOpts, TraceResult* pOutResult ) = 0; virtual bool TraceEndShape( const Vector* pOrigin, const Vector* pEndOrigin, CBaseEntity* pIgnoreEntity, const TraceOptions* pOpts, TraceResult* pOutResult ) = 0; virtual bool TraceHullShape( const Vector* pVecStart, const Vector* pVecEnd, const Vector* pHullMins, const Vector* pHullMaxs, CBaseEntity* pIgnoreEntity, const TraceOptions* pOpts, TraceResult* pOutResult ) = 0; virtual bool TraceShapeEx( const Vector* pVecStart, const Vector* pVecEnd, CTraceFilter* pFilterInc, Ray_t* rayInc, TraceResult* pOutResult ) = 0; }; ``` **Return value:** - `true` → trace hit something, `TraceResult` is valid\ - `false` → no hit ------------------------------------------------------------------------ ## Getting the interface ### C++ (Metamod plugin) Include header from `public/craytraceinterface.h` ``` cpp CRayTraceInterface* g_pRayTrace = nullptr; bool g_bRayTraceLoaded = false; bool LoadRayTrace() { int iRet = 0; g_pRayTrace = static_cast( g_SMAPI->MetaFactory(RAYTRACE_INTERFACE_VERSION, &iRet, nullptr) ); if (iRet == META_IFACE_FAILED || !g_pRayTrace) { FP_ERROR("Failed to lookup Ray-Trace interface!"); return false; } g_bRayTraceLoaded = true; return true; } ``` ### C# (CounterStrikeSharp plugin) The recommended way is to use the prebuilt release components: - Install **RayTraceImpl** as a CS# plugin: addons/counterstrikesharp/plugins/RayTraceImpl/RayTraceImpl.dll - Install **RayTraceApi** as a shared assembly: addons/counterstrikesharp/shared/RayTraceApi/RayTraceApi.dll Then reference `RayTraceApi.dll` in your own plugin project and call the API normally. ------------------------------------------------------------------------ ## Calling methods from C++ (Metamod) ### TraceShape example ``` cpp Vector vecOrigin{}; QAngle angView{}; TraceOptions traceOpts{}; traceOpts.InteractsWith = static_cast(MASK_SHOT_PHYSICS); traceOpts.DrawBeam = 1; TraceResult traceResult{}; if (g_pRayTrace && g_bRayTraceLoaded) { bool bHit = g_pRayTrace->TraceShape( &vecOrigin, &angView, nullptr, &traceOpts, &traceResult ); if (bHit) { Msg("Hit fraction: %f\n", traceResult.Fraction); Msg("End pos: %f %f %f\n", traceResult.EndPos.x, traceResult.EndPos.y, traceResult.EndPos.z); } } ``` ------------------------------------------------------------------------ ## Calling methods from C# (CounterStrikeSharp plugin) After installing RayTraceImpl + RayTraceApi from releases: 1. Add reference in your plugin `.csproj`: ``` xml libs/RayTraceApi.dll ``` 2. Use the API: ``` csharp using RayTraceAPI; using CounterStrikeSharp.API.Modules.Utils; internal static PluginCapability RayTraceInterface { get; } = new("raytrace:craytraceinterface"); public void DoTrace(CCSPlayerController player) { var rayTrace = RayTraceInterface.Get(); if (rayTrace == null) return; var playerPawn = player.PlayerPawn.Value; if (playerPawn == null) return; Vector origin = playerPawn.AbsOrigin!; QAngle angles = playerPawn.EyeAngles!; TraceOptions options = new(); if (rayTrace.TraceShape(origin, angles, null, options, out TraceResult result)) { Console.WriteLine($"Hit fraction: {result.Fraction}"); Console.WriteLine($"EndPos: {result.EndPos}"); } } ``` The bridge handles: - Interface lookup via MetaFactory - Correct vtable offsets (Linux / Windows) - Delegate binding - Native struct layout alignment ------------------------------------------------------------------------ ## VTable offsets (ABI note) Due to C++ ABI differences: | Platform | TraceShape index | TraceEndShape index | TraceHullShape index | | ------------------- | ---------------- | ------------------- |----------------------| | Linux (Itanium ABI) | 2 | 3 | 4 | | Windows (MSVC ABI) | 1 | 2 | 3 | Release builds handle this automatically inside RayTraceImpl. ------------------------------------------------------------------------ ## Notes about ABI & Destructor - `CRayTraceInterface` has a virtual destructor. - The object is owned by the Ray-Trace Metamod module. - Plugins must never call `delete` on the interface pointer. - C# must only clear its handle on unload. - All parameters are passed as native pointers (`nint`). ------------------------------------------------------------------------ ## License GPLv3\ https://www.gnu.org/licenses/gpl-3.0.en.html ------------------------------------------------------------------------ ## Author **Michal "Slynx" Přikryl**\ https://slynxdev.cz