Ray-Trace/README.md
2026-05-24 11:59:53 +02:00

262 lines
6.5 KiB
Markdown

# 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<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
``` cpp
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`:
``` xml
<ItemGroup>
<Reference Include="RayTraceApi">
<HintPath>libs/RayTraceApi.dll</HintPath>
</Reference>
</ItemGroup>
```
2. Use the API:
``` csharp
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