No description
Find a file
2026-02-05 17:42:33 +04:00
.github/workflows Fix: fix crash on plugin start with no spdlog loaded 2026-01-14 17:36:03 +04:00
configs/addons Update collision rules and teleport offsets in gamedata.json 2026-01-26 20:50:01 +04:00
docker Fix: fix crash on plugin start with no spdlog loaded 2026-01-14 17:36:03 +04:00
makefiles Update protobuf.cmake 2026-01-26 21:34:34 +04:00
public update readme 2026-01-31 19:58:28 +04:00
src Update readme 2026-01-26 21:29:09 +04:00
vendor Cleanup 2026-01-28 21:37:13 +04:00
.clang-tidy Initial commit 2026-01-11 18:57:42 +04:00
.gitignore Initial commit 2026-01-11 18:57:42 +04:00
.gitmodules prepare KHook 2026-01-12 21:03:08 +04:00
CMakeLists.txt prepare KHook 2026-01-12 21:03:08 +04:00
LICENSE Initial commit 2026-01-11 18:57:42 +04:00
README.md Update README.md 2026-02-05 17:42:33 +04:00

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: CRayTraceInterface001 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 (CRayTraceInterface001)
  • 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++)

class CRayTraceInterface
{
public:
    virtual ~CRayTraceInterface() = default;

    virtual bool TraceShape(
        const Vector* pOrigin,
        const QAngle* pViewAngles,
        CBaseEntity* pIgnorePlayer,
        const TraceOptions* pOpts,
        TraceResult* pOutResult
    ) = 0;

    virtual bool TraceEndShape(
        const Vector* pOrigin,
        const Vector* pEndOrigin,
        CBaseEntity* pIgnorePlayer,
        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)

CRayTraceInterface* g_pRayTrace = nullptr;
bool g_bRayTraceLoaded = false;

bool LoadRayTrace()
{
    int iRet = 0;

    g_pRayTrace = static_cast<CRayTraceInterface*>(
        g_SMAPI->MetaFactory("CRayTraceInterface001", &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)

For managed plugins, use the provided official wrapper:

public/Example.cs

This file contains:

  • Correct vtable bindings for Linux & Windows
  • Native-compatible struct layouts (TraceOptions, TraceResult)
  • High-level safe API for tracing
  • No need to manually bind delegates

Calling methods from C++ (Metamod)

TraceShape example

Vector vecOrigin{};
QAngle angView{};
TraceOptions traceOpts{};
traceOpts.InteractsWith = static_cast<uint64_t>(MASK_SHOT_FULL);
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)

The official managed API is implemented in:

public/Example.cs

Example usage

using RayTrace;
using CounterStrikeSharp.API.Modules.Utils;

public void DoTrace(CCSPlayerController player)
{
    Vector origin = player.PlayerPawn.Value!.AbsOrigin;
    QAngle angles = player.PlayerPawn.Value!.EyeAngles;

    TraceOptions options = new(
        InteractionLayers.MASK_SHOT_FULL
    );

    if (CRayTrace.TraceShape(origin, angles, null, options, out TraceResult result))
    {
        Console.WriteLine($"Hit fraction: {result.Fraction}");
        Console.WriteLine($"EndPos: {result.EndPos}");
    }
}

VTable offsets (ABI note)

Due to C++ ABI differences:

Platform TraceShape index TraceEndShape index
Linux (Itanium ABI) 2 3
Windows (MSVC ABI) 1 2

public/Example.cs applies Itanium offsets by default.


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