Update readme
This commit is contained in:
parent
98f00073ab
commit
65a480f505
4 changed files with 299 additions and 352 deletions
522
README.md
522
README.md
|
|
@ -1,400 +1,315 @@
|
||||||
# Ray-Trace
|
# Ray-Trace
|
||||||
|
|
||||||
**Shared ray tracing interface for Metamod:source & CounterStrikeSharp
|
**Shared ray tracing interface for Metamod:Source & CounterStrikeSharp plugins**
|
||||||
plugins**
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`Ray-Trace` is a lightweight **Metamod interface module** for\
|
`Ray-Trace` is a lightweight **Metamod interface module** for
|
||||||
**Counter-Strike 2** servers.
|
**Counter-Strike 2** servers.
|
||||||
|
|
||||||
It exposes a shared interface:
|
It exposes a shared interface: `CRayTraceInterface001` which can be consumed from:
|
||||||
|
|
||||||
CRayTraceInterface001
|
- Native **Metamod C++ plugins**
|
||||||
|
- Managed **CounterStrikeSharp C# plugins**
|
||||||
|
|
||||||
which can be consumed from:
|
The interface is implemented as a **C++ virtual class** and is accessed
|
||||||
|
from C# by calling its **vtable functions directly** using a native handle.
|
||||||
|
|
||||||
- Native **Metamod C++ plugins**
|
The goal is to provide a **single tracing backend** usable from both worlds
|
||||||
- Managed **CounterStrikeSharp C# plugins**
|
|
||||||
|
|
||||||
The goal is to provide a **single tracing backend** usable from both
|
|
||||||
worlds\
|
|
||||||
without duplicating engine detours.
|
without duplicating engine detours.
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Metamod meta interface (`CRayTraceInterface001`)
|
- Metamod meta interface (`CRayTraceInterface001`)
|
||||||
- Works in **C++ and C#**
|
- Works in **C++ and C#**
|
||||||
- Physics / hitbox / world trace presets
|
- Physics / hitbox / world trace presets
|
||||||
- Custom collision masks
|
- Custom collision masks
|
||||||
- Optional debug beam rendering
|
- Optional debug beam rendering
|
||||||
- Zero configuration
|
- Zero configuration
|
||||||
- Ultra low overhead
|
- Ultra low overhead
|
||||||
|
- ABI-safe (no STL types in interface)
|
||||||
|
- Virtual destructor for safe lifetime management
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Exposed Interface
|
## Exposed Interface (C++)
|
||||||
|
|
||||||
``` cpp
|
```cpp
|
||||||
class CRayTraceInterface
|
class CRayTraceInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~CRayTraceInterface() = default;
|
virtual ~CRayTraceInterface() = default;
|
||||||
|
|
||||||
virtual std::optional<TraceResult> TraceShape(
|
virtual bool TraceShape(
|
||||||
const Vector& origin,
|
const Vector* pOrigin,
|
||||||
const QAngle& viewangles,
|
const QAngle* pViewAngles,
|
||||||
CBaseEntity* ignorePlayer = nullptr,
|
CBaseEntity* pIgnorePlayer,
|
||||||
const TraceOptions* opts = nullptr) = 0;
|
const TraceOptions* pOpts,
|
||||||
|
TraceResult* pOutResult
|
||||||
|
) = 0;
|
||||||
|
|
||||||
virtual std::optional<TraceResult> TraceEndShape(
|
virtual bool TraceEndShape(
|
||||||
const Vector& origin,
|
const Vector* pOrigin,
|
||||||
const Vector& endOrigin,
|
const Vector* pEndOrigin,
|
||||||
CBaseEntity* ignorePlayer = nullptr,
|
CBaseEntity* pIgnorePlayer,
|
||||||
const TraceOptions* opts = nullptr) = 0;
|
const TraceOptions* pOpts,
|
||||||
|
TraceResult* pOutResult
|
||||||
|
) = 0;
|
||||||
|
|
||||||
virtual std::optional<TraceResult> TraceShapeEx(
|
virtual bool TraceShapeEx(
|
||||||
const Vector& vecStart,
|
const Vector* pVecStart,
|
||||||
const Vector& vecEnd,
|
const Vector* pVecEnd,
|
||||||
CTraceFilter& filterInc,
|
CTraceFilter* pFilterInc,
|
||||||
Ray_t rayInc) = 0;
|
Ray_t rayInc,
|
||||||
|
TraceResult* pOutResult
|
||||||
|
) = 0;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
**Return value:**
|
||||||
|
- true → trace hit something, TraceResult is valid
|
||||||
|
- false → no hit
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Getting the interface
|
## Getting the interface
|
||||||
|
**C++ (Metamod plugin)**
|
||||||
### C++ (Metamod plugin)
|
|
||||||
|
|
||||||
``` cpp
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
auto* rayTraceIface = static_cast<CRayTraceInterface*>(
|
|
||||||
g_SMAPI->MetaFactory("CRayTraceInterface001", &ret, nullptr)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ret == META_IFACE_FAILED || !rayTraceIface)
|
|
||||||
{
|
|
||||||
FP_ERROR("Failed to lookup Ray-Trace interface!");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### C# (CounterStrikeSharp plugin)
|
|
||||||
|
|
||||||
``` csharp
|
|
||||||
private nint _handle;
|
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
|
||||||
{
|
|
||||||
_handle = Utilities.MetaFactory("CRayTraceInterface001");
|
|
||||||
|
|
||||||
if (_handle == nint.Zero)
|
|
||||||
{
|
|
||||||
throw new Exception("Failed to get Ray-Trace interface handle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Calling methods from C++ (Metamod)
|
|
||||||
|
|
||||||
On the native side you simply call the interface methods directly
|
|
||||||
(no vtable binding required).
|
|
||||||
|
|
||||||
### Basic usage
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
CRayTraceInterface* g_RayTrace = nullptr;
|
CRayTraceInterface* g_pRayTrace = nullptr;
|
||||||
|
bool g_bRayTraceLoaded = false;
|
||||||
|
|
||||||
bool InitRayTrace()
|
bool LoadRayTrace()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int iRet = 0;
|
||||||
|
|
||||||
g_RayTrace = static_cast<CRayTraceInterface*>(
|
g_pRayTrace = static_cast<CRayTraceInterface*>(
|
||||||
g_SMAPI->MetaFactory("CRayTraceInterface001", &ret, nullptr)
|
g_SMAPI->MetaFactory("CRayTraceInterface001", &iRet, nullptr)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ret == META_IFACE_FAILED || !g_RayTrace)
|
if (iRet == META_IFACE_FAILED || !g_pRayTrace)
|
||||||
{
|
{
|
||||||
FP_ERROR("Failed to lookup Ray-Trace interface!");
|
FP_ERROR("Failed to lookup Ray-Trace interface!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_bRayTraceLoaded = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
**C# (CounterStrikeSharp plugin)**
|
||||||
|
```csharp
|
||||||
|
private nint g_pRayTraceHandle = nint.Zero;
|
||||||
|
private bool g_bRayTraceLoaded = false;
|
||||||
|
|
||||||
### Calling TraceShape
|
public override void Load(bool hotReload)
|
||||||
|
|
||||||
```cpp
|
|
||||||
TraceOptions opts;
|
|
||||||
opts.InteractsWith = MASK_SHOT_FULL;
|
|
||||||
opts.DrawBeam = true;
|
|
||||||
|
|
||||||
auto result = g_RayTrace->TraceShape(
|
|
||||||
origin,
|
|
||||||
viewAngles,
|
|
||||||
ignorePlayer,
|
|
||||||
&opts
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.has_value())
|
|
||||||
{
|
{
|
||||||
auto& tr = result.value();
|
g_pRayTraceHandle = Utilities.MetaFactory("CRayTraceInterface001");
|
||||||
|
|
||||||
Msg("Hit fraction: %f\n", tr.Fraction);
|
if (g_pRayTraceHandle == nint.Zero)
|
||||||
Msg("End pos: %f %f %f\n",
|
{
|
||||||
tr.EndPos.x,
|
throw new Exception("Failed to get Ray-Trace interface handle");
|
||||||
tr.EndPos.y,
|
}
|
||||||
tr.EndPos.z);
|
|
||||||
|
Bind();
|
||||||
|
g_bRayTraceLoaded = true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The returned handle is a pointer to the native CRayTraceInterface object.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Calling methods from C++ (Metamod)
|
||||||
|
**TraceShape example**
|
||||||
|
```cpp
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
**TraceEndShape example**
|
||||||
|
|
||||||
### Calling TraceEndShape
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto result = g_RayTrace->TraceEndShape(
|
TraceResult traceResult{};
|
||||||
startPos,
|
|
||||||
endPos,
|
bool bHit = g_pRayTrace->TraceEndShape(
|
||||||
ignorePlayer,
|
&vecStartPos,
|
||||||
&opts
|
&vecEndPos,
|
||||||
|
nullptr,
|
||||||
|
&traceOpts,
|
||||||
|
&traceResult
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
**TraceShapeEx (low-level)**
|
||||||
|
|
||||||
### Calling TraceShapeEx (low-level)
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
Ray_t ray;
|
Ray_t ray{};
|
||||||
CTraceFilter filter(
|
CTraceFilter filter(
|
||||||
static_cast<uint64_t>(MASK_SHOT_FULL),
|
static_cast<uint64_t>(MASK_SHOT_FULL),
|
||||||
COLLISION_GROUP_DEFAULT,
|
COLLISION_GROUP_DEFAULT,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
auto result = g_RayTrace->TraceShapeEx(
|
TraceResult traceResult{};
|
||||||
startPos,
|
|
||||||
endPos,
|
bool bHit = g_pRayTrace->TraceShapeEx(
|
||||||
filter,
|
&vecStartPos,
|
||||||
ray
|
&vecEndPos,
|
||||||
|
&filter,
|
||||||
|
ray,
|
||||||
|
&traceResult
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Calling methods from C# (CounterStrikeSharp plugin)
|
## Calling methods from C# (CounterStrikeSharp plugin)
|
||||||
|
```csharp
|
||||||
|
private delegate bool TraceShapeFn(
|
||||||
|
nint pThis,
|
||||||
|
nint pOrigin,
|
||||||
|
nint pAngles,
|
||||||
|
nint pIgnoreEntity,
|
||||||
|
nint pOptions,
|
||||||
|
nint pOutResult
|
||||||
|
);
|
||||||
|
|
||||||
``` csharp
|
private TraceShapeFn? _traceShape;
|
||||||
private Func<nint, nint, nint, nint, nint, nint>? _traceShape;
|
private TraceShapeFn? _traceEndShape;
|
||||||
private Func<nint, nint, nint, nint, nint, nint>? _traceEndShape;
|
private TraceShapeFn? _traceShapeEx;
|
||||||
private Func<nint, nint, nint, nint, nint, nint>? _traceShapeEx;
|
|
||||||
|
|
||||||
private void Bind()
|
private void Bind()
|
||||||
{
|
{
|
||||||
// index 1 - TraceShape
|
_traceShape = VirtualFunction.Create<TraceShapeFn>(g_pRayTraceHandle, 1);
|
||||||
_traceShape = VirtualFunction.Create<
|
_traceEndShape = VirtualFunction.Create<TraceShapeFn>(g_pRayTraceHandle, 2);
|
||||||
nint, // this
|
_traceShapeEx = VirtualFunction.Create<TraceShapeFn>(g_pRayTraceHandle, 3);
|
||||||
nint, // Vector*
|
|
||||||
nint, // QAngle*
|
|
||||||
nint, // ignore entity
|
|
||||||
nint, // TraceOptions*
|
|
||||||
nint
|
|
||||||
>(_handle, 1);
|
|
||||||
|
|
||||||
// index 2 - TraceEndShape
|
|
||||||
_traceEndShape = VirtualFunction.Create<
|
|
||||||
nint, // this
|
|
||||||
nint, // start Vector*
|
|
||||||
nint, // end Vector*
|
|
||||||
nint, // ignore entity
|
|
||||||
nint, // TraceOptions*
|
|
||||||
nint
|
|
||||||
>(_handle, 2);
|
|
||||||
|
|
||||||
// index 3 - TraceShapeEx
|
|
||||||
_traceShapeEx = VirtualFunction.Create<
|
|
||||||
nint, // this
|
|
||||||
nint, // start Vector*
|
|
||||||
nint, // end Vector*
|
|
||||||
nint, // CTraceFilter*
|
|
||||||
nint, // Ray_t*
|
|
||||||
nint
|
|
||||||
>(_handle, 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public nint TraceShape(
|
public bool TraceShape(
|
||||||
nint origin,
|
nint pOrigin,
|
||||||
nint angles,
|
nint pAngles,
|
||||||
nint ignoreEntity,
|
nint pIgnoreEntity,
|
||||||
nint options)
|
nint pOptions,
|
||||||
|
nint pOutResult)
|
||||||
{
|
{
|
||||||
|
if (!g_bRayTraceLoaded || g_pRayTraceHandle == nint.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
return _traceShape!(
|
return _traceShape!(
|
||||||
_handle,
|
g_pRayTraceHandle,
|
||||||
origin,
|
pOrigin,
|
||||||
angles,
|
pAngles,
|
||||||
ignoreEntity,
|
pIgnoreEntity,
|
||||||
options
|
pOptions,
|
||||||
);
|
pOutResult
|
||||||
}
|
|
||||||
|
|
||||||
public nint TraceEndShape(
|
|
||||||
nint start,
|
|
||||||
nint end,
|
|
||||||
nint ignoreEntity,
|
|
||||||
nint options)
|
|
||||||
{
|
|
||||||
return _traceEndShape!(
|
|
||||||
_handle,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
ignoreEntity,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public nint TraceShapeEx(
|
|
||||||
nint start,
|
|
||||||
nint end,
|
|
||||||
nint filter,
|
|
||||||
nint ray)
|
|
||||||
{
|
|
||||||
return _traceShapeEx!(
|
|
||||||
_handle,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
filter,
|
|
||||||
ray
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Collision masks (C#)
|
## Low-level usage from C# (Ray_t & CTraceFilter)
|
||||||
|
|
||||||
``` csharp
|
When using the low-level method `TraceShapeEx` from a C# plugin, the plugin
|
||||||
using System;
|
must provide its own native-compatible implementations of the following
|
||||||
|
engine structures:
|
||||||
|
|
||||||
[Flags]
|
- `Ray_t`
|
||||||
public enum InteractionLayers : ulong
|
- `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.
|
||||||
|
|
||||||
|
Example (simplified):
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Ray_t
|
||||||
{
|
{
|
||||||
Solid = 0x1,
|
public Vector3 m_vecStart;
|
||||||
Hitboxes = 0x2,
|
public Vector3 m_vecDelta;
|
||||||
Trigger = 0x4,
|
public byte m_IsRay;
|
||||||
Sky = 0x8,
|
public byte m_IsSwept;
|
||||||
PlayerClip = 0x10,
|
|
||||||
NPCClip = 0x20,
|
|
||||||
BlockLOS = 0x40,
|
|
||||||
BlockLight = 0x80,
|
|
||||||
Ladder = 0x100,
|
|
||||||
Pickup = 0x200,
|
|
||||||
BlockSound = 0x400,
|
|
||||||
NoDraw = 0x800,
|
|
||||||
Window = 0x1000,
|
|
||||||
PassBullets = 0x2000,
|
|
||||||
WorldGeometry = 0x4000,
|
|
||||||
Water = 0x8000,
|
|
||||||
Slime = 0x10000,
|
|
||||||
TouchAll = 0x20000,
|
|
||||||
Player = 0x40000,
|
|
||||||
NPC = 0x80000,
|
|
||||||
Debris = 0x100000,
|
|
||||||
Physics_Prop = 0x200000,
|
|
||||||
NavIgnore = 0x400000,
|
|
||||||
NavLocalIgnore = 0x800000,
|
|
||||||
PostProcessingVolume = 0x1000000,
|
|
||||||
UnusedLayer3 = 0x2000000,
|
|
||||||
CarriedObject = 0x4000000,
|
|
||||||
PushAway = 0x8000000,
|
|
||||||
ServerEntityOnClient = 0x10000000,
|
|
||||||
CarriedWeapon = 0x20000000,
|
|
||||||
StaticLevel = 0x40000000,
|
|
||||||
csgo_team1 = 0x80000000,
|
|
||||||
csgo_team2 = 0x100000000,
|
|
||||||
csgo_grenadeclip = 0x200000000,
|
|
||||||
csgo_droneclip = 0x400000000,
|
|
||||||
csgo_moveable = 0x800000000,
|
|
||||||
csgo_opaque = 0x1000000000,
|
|
||||||
csgo_monster = 0x2000000000,
|
|
||||||
csgo_thrown_grenade = 0x8000000000,
|
|
||||||
FUNPLAY_IGNORE_PLAYER = (0x8000000000ul << 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TraceMasks
|
|
||||||
{
|
|
||||||
public const InteractionLayers MASK_SHOT_PHYSICS =
|
|
||||||
InteractionLayers.Solid |
|
|
||||||
InteractionLayers.PlayerClip |
|
|
||||||
InteractionLayers.Window |
|
|
||||||
InteractionLayers.PassBullets |
|
|
||||||
InteractionLayers.Player |
|
|
||||||
InteractionLayers.NPC |
|
|
||||||
InteractionLayers.Physics_Prop;
|
|
||||||
|
|
||||||
public const InteractionLayers MASK_SHOT_HITBOX =
|
|
||||||
InteractionLayers.Hitboxes |
|
|
||||||
InteractionLayers.Player |
|
|
||||||
InteractionLayers.NPC;
|
|
||||||
|
|
||||||
public const InteractionLayers MASK_SHOT_FULL =
|
|
||||||
MASK_SHOT_PHYSICS |
|
|
||||||
InteractionLayers.Hitboxes;
|
|
||||||
|
|
||||||
public const InteractionLayers MASK_WORLD_ONLY =
|
|
||||||
InteractionLayers.Solid |
|
|
||||||
InteractionLayers.Window |
|
|
||||||
InteractionLayers.PassBullets;
|
|
||||||
|
|
||||||
public const InteractionLayers MASK_GRENADE =
|
|
||||||
InteractionLayers.Solid |
|
|
||||||
InteractionLayers.Window |
|
|
||||||
InteractionLayers.Physics_Prop |
|
|
||||||
InteractionLayers.PassBullets;
|
|
||||||
|
|
||||||
public const InteractionLayers MASK_PLAYER_MOVE =
|
|
||||||
InteractionLayers.Solid |
|
|
||||||
InteractionLayers.Window |
|
|
||||||
InteractionLayers.PlayerClip |
|
|
||||||
InteractionLayers.PassBullets;
|
|
||||||
|
|
||||||
public const InteractionLayers MASK_NPC_MOVE =
|
|
||||||
InteractionLayers.Solid |
|
|
||||||
InteractionLayers.Window |
|
|
||||||
InteractionLayers.NPCClip |
|
|
||||||
InteractionLayers.PassBullets;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
(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.
|
||||||
|
|
||||||
|
Example concept:
|
||||||
|
```csharp
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public unsafe struct CTraceFilter
|
||||||
|
{
|
||||||
|
public nint __vtable;
|
||||||
|
public ulong m_nInteractsWith;
|
||||||
|
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.
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Directory layout
|
## 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).
|
||||||
|
|
||||||
addons/
|
# Build
|
||||||
└── Ray-Trace/
|
## Requirements
|
||||||
└── bin/linuxsteamrt64/Ray-Trace.so
|
- HL2SDK-CS2
|
||||||
|
- Metamod:Source
|
||||||
------------------------------------------------------------------------
|
- CMake
|
||||||
|
```bash
|
||||||
## Build
|
|
||||||
|
|
||||||
### Requirements
|
|
||||||
|
|
||||||
- HL2SDK-CS2
|
|
||||||
- Metamod:Source
|
|
||||||
- CMake
|
|
||||||
|
|
||||||
``` bash
|
|
||||||
git clone https://github.com/FUNPLAY-pro-CS2/Ray-Trace.git
|
git clone https://github.com/FUNPLAY-pro-CS2/Ray-Trace.git
|
||||||
cd Ray-Trace
|
cd Ray-Trace
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
|
|
@ -404,12 +319,9 @@ docker compose -f docker/docker-compose.yml up
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
GPLv3
|
GPLv3
|
||||||
|
https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
**Michal "Slynx" Přikryl**
|
||||||
**Michal "Slynx" Přikryl**\
|
|
||||||
https://slynxdev.cz
|
https://slynxdev.cz
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <optional>
|
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "gametrace.h"
|
#include "gametrace.h"
|
||||||
|
|
||||||
|
|
@ -158,18 +157,18 @@ constexpr InteractionLayers BuildShotMask(bool includePlayers, bool includeHitbo
|
||||||
|
|
||||||
struct TraceOptions
|
struct TraceOptions
|
||||||
{
|
{
|
||||||
std::optional<InteractionLayers> InteractsWith{ MASK_SHOT_PHYSICS };
|
uint64_t InteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
|
||||||
std::optional<InteractionLayers> InteractsExclude{};
|
uint64_t InteractsExclude = 0;
|
||||||
bool DrawBeam{ false };
|
int DrawBeam = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraceResult
|
struct TraceResult
|
||||||
{
|
{
|
||||||
Vector EndPos{};
|
Vector EndPos;
|
||||||
CEntityInstance* HitEntity{};
|
CEntityInstance* HitEntity;
|
||||||
float Fraction{};
|
float Fraction;
|
||||||
bool AllSolid{};
|
int AllSolid;
|
||||||
Vector Normal{};
|
Vector Normal;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CRayTraceInterface
|
class CRayTraceInterface
|
||||||
|
|
@ -177,21 +176,27 @@ class CRayTraceInterface
|
||||||
public:
|
public:
|
||||||
virtual ~CRayTraceInterface() = default;
|
virtual ~CRayTraceInterface() = default;
|
||||||
|
|
||||||
virtual std::optional<TraceResult> TraceShape(
|
virtual bool TraceShape(
|
||||||
const Vector& origin,
|
const Vector* origin,
|
||||||
const QAngle& viewangles,
|
const QAngle* viewangles,
|
||||||
CBaseEntity* ignorePlayer = nullptr,
|
CBaseEntity* ignorePlayer,
|
||||||
const TraceOptions* opts = nullptr) = 0;
|
const TraceOptions* opts,
|
||||||
|
TraceResult* outResult
|
||||||
|
) = 0;
|
||||||
|
|
||||||
virtual std::optional<TraceResult> TraceEndShape(
|
virtual bool TraceEndShape(
|
||||||
const Vector& origin,
|
const Vector* origin,
|
||||||
const Vector& endOrigin,
|
const Vector* endOrigin,
|
||||||
CBaseEntity* ignorePlayer = nullptr,
|
CBaseEntity* ignorePlayer,
|
||||||
const TraceOptions* opts = nullptr) = 0;
|
const TraceOptions* opts,
|
||||||
|
TraceResult* outResult
|
||||||
|
) = 0;
|
||||||
|
|
||||||
virtual std::optional<TraceResult> TraceShapeEx(
|
virtual bool TraceShapeEx(
|
||||||
const Vector& vecStart,
|
const Vector* vecStart,
|
||||||
const Vector& vecEnd,
|
const Vector* vecEnd,
|
||||||
CTraceFilter& filterInc,
|
CTraceFilter* filterInc,
|
||||||
Ray_t rayInc) = 0;
|
Ray_t rayInc,
|
||||||
|
TraceResult* outResult
|
||||||
|
) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace RayTracePlugin::RayTrace
|
||||||
|
|
||||||
beam->m_clrRender().SetColor(color.r(), color.g(), color.b(), color.a());
|
beam->m_clrRender().SetColor(color.r(), color.g(), color.b(), color.a());
|
||||||
beam->m_fWidth() = 1.5f;
|
beam->m_fWidth() = 1.5f;
|
||||||
beam->m_nRenderMode() = kRenderGlow;
|
beam->m_nRenderMode() = kRenderNormal;
|
||||||
beam->m_nRenderFX() = kRenderFxNone;
|
beam->m_nRenderFX() = kRenderFxNone;
|
||||||
|
|
||||||
beam->Teleport(&start, &VectorExtends::RotationZero, &VectorExtends::VectorZero);
|
beam->Teleport(&start, &VectorExtends::RotationZero, &VectorExtends::VectorZero);
|
||||||
|
|
@ -95,10 +95,16 @@ namespace RayTracePlugin::RayTrace
|
||||||
|
|
||||||
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx();
|
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx();
|
||||||
|
|
||||||
|
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
|
||||||
|
filter.m_nInteractsExclude = 0;
|
||||||
|
|
||||||
if (opts)
|
if (opts)
|
||||||
{
|
{
|
||||||
if (opts->InteractsWith) filter.m_nInteractsWith = static_cast<uint64_t>(*opts->InteractsWith);
|
if (opts->InteractsWith != 0)
|
||||||
if (opts->InteractsExclude) filter.m_nInteractsExclude = static_cast<uint64_t>(*opts->InteractsExclude);
|
filter.m_nInteractsWith = opts->InteractsWith;
|
||||||
|
|
||||||
|
if (opts->InteractsExclude != 0)
|
||||||
|
filter.m_nInteractsExclude = opts->InteractsExclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ray_t ray;
|
Ray_t ray;
|
||||||
|
|
@ -121,10 +127,16 @@ namespace RayTracePlugin::RayTrace
|
||||||
{
|
{
|
||||||
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx();
|
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx();
|
||||||
|
|
||||||
|
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
|
||||||
|
filter.m_nInteractsExclude = 0;
|
||||||
|
|
||||||
if (opts)
|
if (opts)
|
||||||
{
|
{
|
||||||
if (opts->InteractsWith) filter.m_nInteractsWith = static_cast<uint64_t>(*opts->InteractsWith);
|
if (opts->InteractsWith != 0)
|
||||||
if (opts->InteractsExclude) filter.m_nInteractsExclude = static_cast<uint64_t>(*opts->InteractsExclude);
|
filter.m_nInteractsWith = opts->InteractsWith;
|
||||||
|
|
||||||
|
if (opts->InteractsExclude != 0)
|
||||||
|
filter.m_nInteractsExclude = opts->InteractsExclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ray_t ray;
|
Ray_t ray;
|
||||||
|
|
|
||||||
|
|
@ -50,31 +50,49 @@ namespace RayTracePlugin::RayTrace
|
||||||
class CRayTrace : public CRayTraceInterface
|
class CRayTrace : public CRayTraceInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::optional<TraceResult> TraceShape(
|
bool TraceShape(
|
||||||
const Vector& origin,
|
const Vector* origin,
|
||||||
const QAngle& viewangles,
|
const QAngle* viewangles,
|
||||||
CBaseEntity* ignorePlayer,
|
CBaseEntity* ignorePlayer,
|
||||||
const TraceOptions* opts) override
|
const TraceOptions* opts,
|
||||||
|
TraceResult* outResult) override
|
||||||
{
|
{
|
||||||
return RayTrace::TraceShape(origin, viewangles, ignorePlayer, opts);
|
auto result = RayTrace::TraceShape(*origin, *viewangles, ignorePlayer, opts);
|
||||||
|
if (!result.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*outResult = result.value();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<TraceResult> TraceEndShape(
|
bool TraceEndShape(
|
||||||
const Vector& origin,
|
const Vector* origin,
|
||||||
const Vector& endOrigin,
|
const Vector* endOrigin,
|
||||||
CBaseEntity* ignorePlayer,
|
CBaseEntity* ignorePlayer,
|
||||||
const TraceOptions* opts) override
|
const TraceOptions* opts,
|
||||||
|
TraceResult* outResult) override
|
||||||
{
|
{
|
||||||
return RayTrace::TraceEndShape(origin, endOrigin, ignorePlayer, opts);
|
auto result = RayTrace::TraceEndShape(*origin, *endOrigin, ignorePlayer, opts);
|
||||||
|
if (!result.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*outResult = result.value();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<TraceResult> TraceShapeEx(
|
bool TraceShapeEx(
|
||||||
const Vector& vecStart,
|
const Vector* vecStart,
|
||||||
const Vector& vecEnd,
|
const Vector* vecEnd,
|
||||||
CTraceFilter& filterInc,
|
CTraceFilter* filterInc,
|
||||||
Ray_t rayInc) override
|
Ray_t rayInc,
|
||||||
|
TraceResult* outResult) override
|
||||||
{
|
{
|
||||||
return RayTrace::TraceShapeEx(vecStart, vecEnd, filterInc, rayInc);
|
auto result = RayTrace::TraceShapeEx(*vecStart, *vecEnd, *filterInc, rayInc);
|
||||||
|
if (!result.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*outResult = result.value();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue