Ray Trace system for CS2 (mirrored from github)
This repository has been archived on 2026-09-10. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
  • C++ 85.5%
  • C# 6.3%
  • CMake 5.7%
  • Shell 1.6%
  • Dockerfile 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
mrc4tt f483abab25
All checks were successful
Continuous Integration / Build and Release on Linux via Docker Compose (push) Successful in 5m57s
ci: rebuild the builder image on every run
The Dockerfile bakes the checkout in with "COPY . /app/source" and the
container compiles that copy, but "docker compose run" reuses an existing
image instead of rebuilding it. On the persistent runner that meant every
job after the first kept compiling the commit that originally produced
cmake-builder — the Ray_t fix was pushed but never actually built.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 13:29:53 +02:00
.github/workflows ci: rebuild the builder image on every run 2026-08-01 13:29:53 +02:00
configs/addons fix: update sigs, vtable indices and schema vfunc for 2026-07-08 CS2 update 2026-07-10 12:46:44 +02:00
docker fix repo 2026-08-01 12:23:51 +02:00
makefiles update build scripts for new hl2sdk commits 2026-08-01 12:19:23 +02:00
managed/RayTrace Update .NET to v10 2026-06-11 18:05:08 +02:00
public Update interface version 2026-04-22 23:28:10 +02:00
src fix: include ray.h in globaltypes.h 2026-08-01 13:03:33 +02: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 update build scripts for new hl2sdk commits 2026-08-01 12:19:23 +02:00
LICENSE Initial commit 2026-01-11 18:57:42 +04:00
README.md Update README.md 2026-05-24 11:59:53 +02: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: 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++)

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

CRayTraceInterface* g_pRayTrace = nullptr;
bool g_bRayTraceLoaded = false;

bool LoadRayTrace()
{
    int iRet = 0;

    g_pRayTrace = static_cast<CRayTraceInterface*>(
        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

Vector vecOrigin{};
QAngle angView{};
TraceOptions traceOpts{};
traceOpts.InteractsWith = static_cast<uint64_t>(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:
<ItemGroup>
  <Reference Include="RayTraceApi">
    <HintPath>libs/RayTraceApi.dll</HintPath>
  </Reference>
</ItemGroup>
  1. Use the API:
using RayTraceAPI;
using CounterStrikeSharp.API.Modules.Utils;

internal static PluginCapability<CRayTraceInterface> 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