From 8e0e61acd15a1e86b8c3ad8b4a470f5c4c690a5a Mon Sep 17 00:00:00 2001 From: SlynxCZ Date: Fri, 30 Jan 2026 10:31:43 +0400 Subject: [PATCH] update readme --- README.md | 211 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 149 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index c683561..a1f507d 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,48 @@ # Ray-Trace -**Shared ray tracing interface for Metamod:Source & CounterStrikeSharp plugins** +**Shared ray tracing interface for Metamod:Source & CounterStrikeSharp +plugins** ------------------------------------------------------------------------ ## Overview -`Ray-Trace` is a lightweight **Metamod interface module** for +`Ray-Trace` is a lightweight **Metamod interface module** for\ **Counter-Strike 2** servers. -It exposes a shared interface: `CRayTraceInterface001` which can be consumed from: +It exposes a shared interface: `CRayTraceInterface001` which can be +consumed from: -- Native **Metamod C++ plugins** -- Managed **CounterStrikeSharp C# plugins** +- 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. +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 +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 +- 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++) -```cpp +``` cpp class CRayTraceInterface { public: @@ -69,16 +73,17 @@ public: ) = 0; }; ``` -**Return value:** -- true → trace hit something, TraceResult is valid + +**Return value:** - true → trace hit something, TraceResult is valid\ - false → no hit ------------------------------------------------------------------------ ## Getting the interface + **C++ (Metamod plugin)** -```cpp +``` cpp CRayTraceInterface* g_pRayTrace = nullptr; bool g_bRayTraceLoaded = false; @@ -102,7 +107,8 @@ bool LoadRayTrace() ``` **C# (CounterStrikeSharp plugin)** -```csharp + +``` csharp private nint g_pRayTraceHandle = nint.Zero; private bool g_bRayTraceLoaded = false; @@ -119,13 +125,17 @@ public override void Load(bool hotReload) g_bRayTraceLoaded = true; } ``` -The returned handle is a pointer to the native CRayTraceInterface object. + +The returned handle is a pointer to the native CRayTraceInterface +object. ------------------------------------------------------------------------ ## Calling methods from C++ (Metamod) + **TraceShape example** -```cpp + +``` cpp Vector vecOrigin{}; QAngle angView{}; TraceOptions traceOpts{}; @@ -156,7 +166,8 @@ if (g_pRayTrace && g_bRayTraceLoaded) ``` **TraceEndShape example** -```cpp + +``` cpp TraceResult traceResult{}; bool bHit = g_pRayTrace->TraceEndShape( @@ -169,7 +180,8 @@ bool bHit = g_pRayTrace->TraceEndShape( ``` **TraceShapeEx (low-level)** -```cpp + +``` cpp Ray_t ray{}; CTraceFilter filter( static_cast(MASK_SHOT_FULL), @@ -191,7 +203,8 @@ bool bHit = g_pRayTrace->TraceShapeEx( ------------------------------------------------------------------------ ## Calling methods from C# (CounterStrikeSharp plugin) -```csharp + +``` csharp private delegate bool TraceShapeFn( nint pThis, nint pOrigin, @@ -235,26 +248,94 @@ public bool TraceShape( ------------------------------------------------------------------------ +## Memory allocation from C# (Important) + +When calling `TraceShape` or `TraceEndShape` from C#, the plugin **must +allocate native memory** for the following structures: + +- `TraceOptions` +- `TraceResult` + +These parameters are native pointers in C++ (`TraceOptions*` and +`TraceResult*`) and must remain valid for the duration of the call. + +The recommended and safest approach is using **stackalloc** (or unsafe +stack variables) to provide native memory on the stack. + +Failing to allocate valid memory for these parameters will result in +crashes or undefined behavior. + +### Example (C# stackalloc) + +``` csharp +[StructLayout(LayoutKind.Sequential, Pack = 8)] +public struct TraceOptions +{ + public ulong InteractsWith; + public ulong InteractsExclude; + public int DrawBeam; +} + +[StructLayout(LayoutKind.Sequential, Pack = 8)] +public struct TraceResult +{ + public Vector EndPos; + public nint HitEntity; + public float Fraction; + public int AllSolid; + public Vector Normal; +} + +unsafe +{ + Vector origin = player.Position; + QAngle angles = player.ViewAngles; + + TraceOptions* opts = stackalloc TraceOptions[1]; + opts->InteractsWith = (ulong)MASK_SHOT_FULL; + opts->InteractsExclude = 0; + opts->DrawBeam = 0; + + TraceResult* result = stackalloc TraceResult[1]; + + bool hit = _traceShape!( + g_pRayTraceHandle, + (nint)&origin, + (nint)&angles, + nint.Zero, + (nint)opts, + (nint)result + ); + + if (hit) + { + Console.WriteLine($"Hit at: {result->EndPos}"); + } +} +``` + +------------------------------------------------------------------------ + ## Low-level usage from C# (Ray_t & CTraceFilter) -When using the low-level method `TraceShapeEx` from a C# plugin, the plugin -must provide its own native-compatible implementations of the following -engine structures: +When using the low-level method `TraceShapeEx` from a C# plugin, the +plugin must provide its own native-compatible implementations of the +following engine structures: -- `Ray_t` -- `CTraceFilter` +- `Ray_t` +- `CTraceFilter` These structures are not exposed directly by the Ray-Trace interface and must be recreated in managed code with correct memory layout. ### Ray_t (C#) -The C# plugin must define a struct that matches the native `Ray_t` layout -used by the engine. +The C# plugin must define a struct that matches the native `Ray_t` +layout used by the engine. Example (simplified): -```csharp +``` csharp [StructLayout(LayoutKind.Sequential)] public struct Ray_t { @@ -264,19 +345,21 @@ public struct Ray_t public byte m_IsSwept; } ``` -(Exact layout depends on the engine version and must match native memory.) -**CTraceFilter (C#)** +(Exact layout depends on the engine version and must match native +memory.) + +**CTraceFilter (C#)**\ For `CTraceFilter`, the plugin must: -- Define a managed struct matching the native layout. -- Resolve the CTraceFilter vtable pointer using a signature scan. -- Assign the resolved vtable to the struct before calling TraceShapeEx. -This is required because CTraceFilter is a polymorphic C++ class and its -virtual table is not directly exposed to managed code. +- Define a managed struct matching the native layout. +- Resolve the CTraceFilter vtable pointer using a signature scan. +- Assign the resolved vtable to the struct before calling + TraceShapeEx. Example concept: -```csharp + +``` csharp [StructLayout(LayoutKind.Sequential)] public unsafe struct CTraceFilter { @@ -285,31 +368,33 @@ public unsafe struct CTraceFilter public T ...; } ``` -The vtable pointer must be resolved at runtime using a signature scan -against the game binary. -**Important notes** -- This setup is only required when using the low-level API: -- TraceShapeEx(...) -- High-level functions (TraceShape, TraceEndShape) do not require custom Ray_t or CTraceFilter handling from C#. -- Incorrect structure layout or invalid vtable resolution will result in crashes or undefined behavior. -- This is considered an advanced use case intended for engine-level plugins. +**Important notes** - This setup is only required when using the +low-level API: - TraceShapeEx(...) - High-level functions (TraceShape, +TraceEndShape) do not require custom Ray_t or CTraceFilter handling from +C#. - Incorrect structure layout or invalid vtable resolution will +result in crashes or undefined behavior. - This is considered an +advanced use case intended for engine-level plugins. ------------------------------------------------------------------------ ## 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). + +- 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). # Build + ## Requirements -- HL2SDK-CS2 -- Metamod:Source -- CMake -```bash + +- HL2SDK-CS2 +- Metamod:Source +- CMake + +``` bash git clone https://github.com/FUNPLAY-pro-CS2/Ray-Trace.git cd Ray-Trace git submodule update --init --recursive @@ -319,9 +404,11 @@ docker compose -f docker/docker-compose.yml up ------------------------------------------------------------------------ ## License -GPLv3 + +GPLv3\ https://www.gnu.org/licenses/gpl-3.0.en.html ## Author -**Michal "Slynx" Přikryl** -https://slynxdev.cz \ No newline at end of file + +**Michal "Slynx" Přikryl**\ +https://slynxdev.cz