From fcd0bd6e257401392c61e1506dc2649c6bbc52ab Mon Sep 17 00:00:00 2001 From: SlynxCZ Date: Wed, 11 Feb 2026 20:42:43 +0400 Subject: [PATCH] Update files --- managed/RayTrace/RayTraceApi.cs | 117 ++++++++++++ managed/RayTrace/RayTraceApi.csproj | 14 ++ managed/RayTrace/RayTraceImpl.cs | 174 ++++++++++++++++++ .../RayTraceImpl.csproj} | 7 + .../RayTraceImpl.sln} | 8 +- managed/RayTraceApi/RayTraceApi.cs | 47 ----- 6 files changed, 319 insertions(+), 48 deletions(-) create mode 100644 managed/RayTrace/RayTraceApi.cs create mode 100644 managed/RayTrace/RayTraceApi.csproj create mode 100644 managed/RayTrace/RayTraceImpl.cs rename managed/{RayTraceApi/RayTraceApi.csproj => RayTrace/RayTraceImpl.csproj} (74%) rename managed/{RayTraceApi/RayTraceApi.sln => RayTrace/RayTraceImpl.sln} (57%) delete mode 100644 managed/RayTraceApi/RayTraceApi.cs diff --git a/managed/RayTrace/RayTraceApi.cs b/managed/RayTrace/RayTraceApi.cs new file mode 100644 index 0000000..44ee6b5 --- /dev/null +++ b/managed/RayTrace/RayTraceApi.cs @@ -0,0 +1,117 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Utils; +using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; + +namespace RayTraceAPI +{ +#region Native Structs (matching C++ layout exactly) + [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, + + MASK_SHOT_PHYSICS = Solid | PlayerClip | Window | PassBullets | Player | NPC | Physics_Prop, + MASK_SHOT_HITBOX = Hitboxes | Player | NPC, + MASK_SHOT_FULL = MASK_SHOT_PHYSICS | Hitboxes, + MASK_WORLD_ONLY = Solid | Window | PassBullets, + MASK_GRENADE = Solid | Window | Physics_Prop | PassBullets, + MASK_BRUSH_ONLY = Solid | Window, + MASK_PLAYER_MOVE = Solid | Window | PlayerClip | PassBullets, + MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets + } + + [StructLayout(LayoutKind.Explicit, Size = 32)] + public struct TraceOptions + { + [FieldOffset(0)] public ulong InteractsAs; + [FieldOffset(8)] public ulong InteractsWith; + [FieldOffset(16)] public ulong InteractsExclude; + [FieldOffset(24)] public int DrawBeam; + + public TraceOptions() + { + InteractsAs = 0; + InteractsWith = (ulong)InteractionLayers.MASK_SHOT_PHYSICS; + InteractsExclude = 0; + DrawBeam = 0; + } + + public TraceOptions(InteractionLayers interactsAs, InteractionLayers interactsWith, + InteractionLayers interactsExclude = 0, bool drawBeam = false) + { + InteractsAs = (ulong)interactsAs; + InteractsWith = (ulong)interactsWith; + InteractsExclude = (ulong)interactsExclude; + DrawBeam = drawBeam ? 1 : 0; + } + } + + [StructLayout(LayoutKind.Explicit, Size = 48)] + public struct TraceResult + { + [FieldOffset(0)] public float EndPosX; + [FieldOffset(4)] public float EndPosY; + [FieldOffset(8)] public float EndPosZ; + [FieldOffset(16)] public nint HitEntity; + [FieldOffset(24)] public float Fraction; + [FieldOffset(28)] public int AllSolid; + [FieldOffset(32)] public float NormalX; + [FieldOffset(36)] public float NormalY; + [FieldOffset(40)] public float NormalZ; + + public Vector3 EndPos => new(EndPosX, EndPosY, EndPosZ); + public Vector3 Normal => new(NormalX, NormalY, NormalZ); + public bool DidHit => Fraction < 1.0f; + public bool IsAllSolid => AllSolid != 0; + } +#endregion + + public interface CRayTraceInterface + { + public unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result); + public unsafe bool TraceEndShape(Vector origin, Vector endOrigin, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result); + public unsafe bool TraceHullShape(Vector vecStart, Vector vecEnd, Vector hullMins, Vector hullMaxs, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result); + } +} \ No newline at end of file diff --git a/managed/RayTrace/RayTraceApi.csproj b/managed/RayTrace/RayTraceApi.csproj new file mode 100644 index 0000000..dacee6c --- /dev/null +++ b/managed/RayTrace/RayTraceApi.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + true + + + + + + + diff --git a/managed/RayTrace/RayTraceImpl.cs b/managed/RayTrace/RayTraceImpl.cs new file mode 100644 index 0000000..be25a9e --- /dev/null +++ b/managed/RayTrace/RayTraceImpl.cs @@ -0,0 +1,174 @@ +// +// Created by Michal Přikryl on 10.10.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +using System.Buffers; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Loader; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Core.Capabilities; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Utils; +using RayTraceAPI; + +namespace RayTrace; + +// ReSharper disable once InconsistentNaming +// ReSharper disable once UnusedType.Global +public class RayTraceImpl : BasePlugin +{ + public override string ModuleName => "RayTraceImpl"; + public override string ModuleVersion => "v1.0.0"; + public override string ModuleAuthor => "Slynx"; + + internal static PluginCapability RayTraceInterface { get; } = new("raytrace:craytraceinterface"); + + public override void Load(bool hotReload) + { + Capabilities.RegisterPluginCapability(RayTraceInterface, () => new CRayTrace()); + RegisterListener(OnMetamodAllPluginsLoaded); + } + + public override void Unload(bool hotReload) + { + RemoveListener(OnMetamodAllPluginsLoaded); + } + + private void OnMetamodAllPluginsLoaded() + { + if (!NativeBridge.Initialize()) + { + Prints.ServerLog("[RayTraceImpl] Native bridge initialization failed.", ConsoleColor.Red); + return; + } + Prints.ServerLog("[RayTraceImpl] Managed side initialized.", ConsoleColor.Green); + } +} + +public class CRayTrace : CRayTraceInterface +{ + public unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) + { + result = default; + + if (!NativeBridge.m_bRayTraceLoaded || NativeBridge.m_pRayTraceHandle == nint.Zero) + return false; + + TraceResult resultBuffer = default; + TraceOptions optionsBuffer = options; + + bool success = NativeBridge._traceShape!(NativeBridge.m_pRayTraceHandle, + origin.Handle, + angles.Handle, + ignoreEntity?.Handle ?? nint.Zero, + (nint)(&optionsBuffer), + (nint)(&resultBuffer)); + + result = resultBuffer; + return success; + } + + public unsafe bool TraceEndShape(Vector origin, Vector endOrigin, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) + { + result = default; + + if (!NativeBridge.m_bRayTraceLoaded || NativeBridge.m_pRayTraceHandle == nint.Zero) + return false; + + TraceResult resultBuffer = default; + TraceOptions optionsBuffer = options; + + bool success = NativeBridge._traceEndShape!(NativeBridge.m_pRayTraceHandle, + origin.Handle, + endOrigin.Handle, + ignoreEntity?.Handle ?? nint.Zero, + (nint)(&optionsBuffer), + (nint)(&resultBuffer)); + + result = resultBuffer; + return success; + } + + public unsafe bool TraceHullShape(Vector vecStart, Vector vecEnd, Vector hullMins, Vector hullMaxs, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) + { + result = default; + + if (!NativeBridge.m_bRayTraceLoaded || NativeBridge.m_pRayTraceHandle == nint.Zero) + return false; + + TraceResult resultBuffer = default; + TraceOptions optionsBuffer = options; + + bool success = NativeBridge._traceHullShape!(NativeBridge.m_pRayTraceHandle, + vecStart.Handle, + vecEnd.Handle, + hullMins.Handle, + hullMaxs.Handle, + ignoreEntity?.Handle ?? nint.Zero, + (nint)(&optionsBuffer), + (nint)(&resultBuffer)); + + result = resultBuffer; + return success; + } +} + +public static class NativeBridge +{ + public static nint m_pRayTraceHandle = nint.Zero; + public static bool m_bRayTraceLoaded = false; + + public static Func? _traceShape; + public static Func? _traceEndShape; + public static Func? _traceHullShape; + + public static bool Initialize() + { + m_pRayTraceHandle = (nint)Utilities.MetaFactory("CRayTraceInterface001")!; + + if (m_pRayTraceHandle == nint.Zero) + { + Prints.ServerLog("[RayTraceImpl] Failed to get Ray-Trace interface handle. Is Ray-Trace MetaMod module loaded?", ConsoleColor.Red); + return false; + } + + Bind(); + m_bRayTraceLoaded = true; + return true; + } + + private static void Bind() + { + int traceShapeIndex = 2; + int traceEndShapeIndex = 3; + int traceHullShapeIndex = 4; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + traceShapeIndex = 1; + traceEndShapeIndex = 2; + traceHullShapeIndex = 3; + } + + _traceShape = VirtualFunction.Create(m_pRayTraceHandle, traceShapeIndex); + _traceEndShape = VirtualFunction.Create(m_pRayTraceHandle, traceEndShapeIndex); + _traceHullShape = VirtualFunction.Create(m_pRayTraceHandle, traceHullShapeIndex); + } +} + +public static class Prints +{ + public static void ServerLog(string msg, ConsoleColor color = ConsoleColor.White) + { + Console.ForegroundColor = color; + Console.WriteLine(msg); + Console.ResetColor(); + } +} \ No newline at end of file diff --git a/managed/RayTraceApi/RayTraceApi.csproj b/managed/RayTrace/RayTraceImpl.csproj similarity index 74% rename from managed/RayTraceApi/RayTraceApi.csproj rename to managed/RayTrace/RayTraceImpl.csproj index f0f5dcc..1360a19 100644 --- a/managed/RayTraceApi/RayTraceApi.csproj +++ b/managed/RayTrace/RayTraceImpl.csproj @@ -7,8 +7,15 @@ true + + + ..\0Harmony.dll + + + + diff --git a/managed/RayTraceApi/RayTraceApi.sln b/managed/RayTrace/RayTraceImpl.sln similarity index 57% rename from managed/RayTraceApi/RayTraceApi.sln rename to managed/RayTrace/RayTraceImpl.sln index 16fe941..b5b4c6c 100644 --- a/managed/RayTraceApi/RayTraceApi.sln +++ b/managed/RayTrace/RayTraceImpl.sln @@ -1,6 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayTraceApi", "RayTraceApi.csproj", "{0D0FD0C6-A1A6-47A7-8370-29CCE2CD4598}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayTraceImpl", "RayTraceImpl.csproj", "{0D0FD0C6-A1A6-47A7-8370-29CCE2CD4598}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayTraceApi", "RayTraceApi.csproj", "{13E6E993-1E09-4B9A-9888-98481E1C3178}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -12,5 +14,9 @@ Global {0D0FD0C6-A1A6-47A7-8370-29CCE2CD4598}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D0FD0C6-A1A6-47A7-8370-29CCE2CD4598}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D0FD0C6-A1A6-47A7-8370-29CCE2CD4598}.Release|Any CPU.Build.0 = Release|Any CPU + {13E6E993-1E09-4B9A-9888-98481E1C3178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13E6E993-1E09-4B9A-9888-98481E1C3178}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13E6E993-1E09-4B9A-9888-98481E1C3178}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13E6E993-1E09-4B9A-9888-98481E1C3178}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/managed/RayTraceApi/RayTraceApi.cs b/managed/RayTraceApi/RayTraceApi.cs deleted file mode 100644 index b2b99b3..0000000 --- a/managed/RayTraceApi/RayTraceApi.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// Created by Michal Přikryl on 11.02.2025. -// Copyright (c) 2025 slynxcz. All rights reserved. -// -using System.Buffers; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Loader; -using System.Numerics; -using System.Text; -using System.Text.Json; -using System.Text.RegularExpressions; -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Core.Attributes.Registration; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Modules.Memory; -using CounterStrikeSharp.API.Modules.Utils; -using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; - -namespace RayTraceImpl; - -// ReSharper disable once InconsistentNaming -// ReSharper disable once UnusedType.Global -public class RayTraceImpl : BasePlugin -{ - public override string ModuleName => "RayTraceImpl"; - public override string ModuleVersion => m_pszVersion; - public override string ModuleAuthor => "Slynx"; - - public override void Load(bool hotReload) - { - RegisterListener(OnMetamodAllPluginsLoaded); - } - - public override void Unload(bool hotReload) - { - RemoveListener(OnMetamodAllPluginsLoaded); - } - - private void OnMetamodAllPluginsLoaded() - { - - } - - public static string m_pszVersion { get; private set; } = ""; -} \ No newline at end of file