- C++ 85.5%
- C# 6.3%
- CMake 5.7%
- Shell 1.6%
- Dockerfile 0.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Continuous Integration / Build and Release on Linux via Docker Compose (push) Successful in 5m57s
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> |
||
| .github/workflows | ||
| configs/addons | ||
| docker | ||
| makefiles | ||
| managed/RayTrace | ||
| public | ||
| src | ||
| vendor | ||
| .clang-tidy | ||
| .gitignore | ||
| .gitmodules | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
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,TraceResultis 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:
- Add reference in your plugin
.csproj:
<ItemGroup>
<Reference Include="RayTraceApi">
<HintPath>libs/RayTraceApi.dll</HintPath>
</Reference>
</ItemGroup>
- 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
CRayTraceInterfacehas a virtual destructor.- The object is owned by the Ray-Trace Metamod module.
- Plugins must never call
deleteon 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