diff --git a/README.md b/README.md new file mode 100644 index 0000000..75f713e --- /dev/null +++ b/README.md @@ -0,0 +1,363 @@ +# 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: + + CRayTraceInterface001 + +which can be consumed from: + +- Native **Metamod C++ plugins** +- Managed **CounterStrikeSharp C# plugins** + +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 + +------------------------------------------------------------------------ + +## Exposed Interface + +``` cpp +class CRayTraceInterface +{ +public: + virtual ~CRayTraceInterface() = default; + + virtual std::optional TraceShape( + const Vector& origin, + const QAngle& viewangles, + CBaseEntity* ignorePlayer = nullptr, + const TraceOptions* opts = nullptr) = 0; + + virtual std::optional TraceEndShape( + const Vector& origin, + const Vector& endOrigin, + CBaseEntity* ignorePlayer = nullptr, + const TraceOptions* opts = nullptr) = 0; + + virtual std::optional TraceShapeEx( + const Vector& vecStart, + const Vector& vecEnd, + CTraceFilter& filterInc, + Ray_t rayInc) = 0; +}; +``` + +------------------------------------------------------------------------ + +## Getting the interface + +### C++ (Metamod plugin) + +``` cpp +int ret = 0; + +auto* rayTraceIface = static_cast( + 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 +CRayTraceInterface* g_RayTrace = nullptr; + +bool InitRayTrace() +{ + int ret = 0; + + g_RayTrace = static_cast( + g_SMAPI->MetaFactory("CRayTraceInterface001", &ret, nullptr) + ); + + if (ret == META_IFACE_FAILED || !g_RayTrace) + { + FP_ERROR("Failed to lookup Ray-Trace interface!"); + return false; + } + + return true; +} +``` + +--- + +### Calling TraceShape + +```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(); + + Msg("Hit fraction: %f\n", tr.Fraction); + Msg("End pos: %f %f %f\n", + tr.EndPos.x, + tr.EndPos.y, + tr.EndPos.z); +} +``` + +--- + +### Calling TraceEndShape + +```cpp +auto result = g_RayTrace->TraceEndShape( + startPos, + endPos, + ignorePlayer, + &opts +); +``` + +--- + +### Calling TraceShapeEx (low-level) + +```cpp +Ray_t ray; +CTraceFilter filter( + static_cast(MASK_SHOT_FULL), + COLLISION_GROUP_DEFAULT, + true +); + +auto result = g_RayTrace->TraceShapeEx( + startPos, + endPos, + filter, + ray +); +``` + +------------------------------------------------------------------------ + +## Calling methods from C# (CounterStrikeSharp plugin) + +``` csharp +private Func? _traceShape; + +private void Bind() +{ + _traceShape = VirtualFunction.Create< + nint, // thisptr + nint, // Vector* + nint, // QAngle* + nint, // ignore entity + nint, // TraceOptions* + nint // return + >(_handle, 0); +} + +public bool TraceShape( + nint origin, + nint angles, + nint ignoreEntity, + nint options) +{ + return _traceShape!( + _handle, + origin, + angles, + ignoreEntity, + options, + nint.Zero + ) != nint.Zero; +} +``` + +------------------------------------------------------------------------ + +## Collision masks (C#) + +``` csharp +using System; + +[Flags] +public enum InteractionLayers : ulong +{ + Solid = 0x1, + Hitboxes = 0x2, + Trigger = 0x4, + Sky = 0x8, + 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; +} +``` + +------------------------------------------------------------------------ + +## Directory layout + + addons/ + └── Ray-Trace/ + └── bin/linuxsteamrt64/Ray-Trace.so + +------------------------------------------------------------------------ + +## Build + +### Requirements + +- 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 +docker compose -f docker/docker-compose.yml up +``` + +------------------------------------------------------------------------ + +## License + +GPLv3 + +------------------------------------------------------------------------ + +## Author + +**Michal "Slynx" Přikryl**\ +https://slynxdev.cz diff --git a/public/CRayTraceInterface.h b/public/CRayTraceInterface.h index b13d246..5207c58 100644 --- a/public/CRayTraceInterface.h +++ b/public/CRayTraceInterface.h @@ -47,8 +47,7 @@ enum class InteractionLayers : uint64_t csgo_moveable = 0x800000000, csgo_opaque = 0x1000000000, csgo_monster = 0x2000000000, - csgo_thrown_grenade = 0x8000000000, - FUNPLAY_IGNORE_PLAYER = (0x8000000000ull << 1) + csgo_thrown_grenade = 0x8000000000 }; constexpr InteractionLayers operator|(InteractionLayers a, InteractionLayers b)