diff --git a/managed/RayTrace/RayTraceApi/RayTraceApi.cs b/managed/RayTrace/RayTraceApi/RayTraceApi.cs index 836c7f7..66b8b29 100644 --- a/managed/RayTrace/RayTraceApi/RayTraceApi.cs +++ b/managed/RayTrace/RayTraceApi/RayTraceApi.cs @@ -89,291 +89,74 @@ namespace RayTraceAPI } } - [StructLayout(LayoutKind.Explicit, Size = 8)] - public unsafe struct CUtlString - { - [FieldOffset(0)] public nint _ptr; // make public so Marshal sees it - - public string Value - { - get - { - if (_ptr == 0 || _ptr == IntPtr.MaxValue) return string.Empty; - return Marshal.PtrToStringUTF8(_ptr)!; // read UTF8 string from native pointer - } - } - - public static implicit operator string(CUtlString s) => s.Value; - } - - [StructLayout(LayoutKind.Explicit, Size = 200)] - public unsafe struct CPhysSurfacePropertiesTrace - { - [FieldOffset(0)] public CUtlString Name; - [FieldOffset(8)] public uint NameHash; - [FieldOffset(12)] public uint BaseNameHash; - [FieldOffset(16)] public int ListIndex; - [FieldOffset(20)] public int BaseListIndex; - [MarshalAs(UnmanagedType.I1)] - [FieldOffset(24)] public bool Hidden; - [FieldOffset(32)] public CUtlString Description; - [FieldOffset(40)] public CPhysSurfacePropertiesPhysicsTrace Physics; - [FieldOffset(80)] public CPhysSurfacePropertiesSoundNamesTrace AudioSounds; - [FieldOffset(168)] public CPhysSurfacePropertiesAudioTrace AudioParams; - } - - public enum CollisionFunctionMask_t : byte - { - FCOLLISION_FUNC_ENABLE_SOLID_CONTACT = (1 << 0), - FCOLLISION_FUNC_ENABLE_TRACE_QUERY = (1 << 1), - FCOLLISION_FUNC_ENABLE_TOUCH_EVENT = (1 << 2), - FCOLLISION_FUNC_ENABLE_SELF_COLLISIONS = (1 << 3), - FCOLLISION_FUNC_IGNORE_FOR_HITBOX_TEST = (1 << 4), - FCOLLISION_FUNC_ENABLE_TOUCH_PERSISTS = (1 << 5), - } - - [StructLayout(LayoutKind.Explicit, Size = 48)] - public struct RnCollisionAttr_t - { - [FieldOffset(0)] public ulong InteractsAs; - [FieldOffset(8)] public ulong InteractsWith; - [FieldOffset(16)] public ulong InteractsExclude; - - [FieldOffset(24)] public uint EntityId; - [FieldOffset(28)] public uint OwnerId; - - [FieldOffset(32)] public ushort HierarchyId; - [FieldOffset(34)] public ushort DetailLayerMask; - - [FieldOffset(36)] public byte DetailLayerMaskType; - [FieldOffset(37)] public byte TargetDetailLayer; - [FieldOffset(38)] public byte CollisionGroup; - [FieldOffset(39)] public byte CollisionFunctionMask; - - [FieldOffset(40)] private long _pad; - } - - public enum RayType_t : int { - RAY_TYPE_LINE = 0, - RAY_TYPE_SPHERE, - RAY_TYPE_HULL, - RAY_TYPE_CAPSULE, - RAY_TYPE_MESH, - } - - [StructLayout(LayoutKind.Explicit, Size = 36)] - public unsafe struct CPhysSurfacePropertiesPhysicsTrace - { - [FieldOffset(0)] public float Friction; - [FieldOffset(4)] public float Elasticity; - [FieldOffset(8)] public float Density; - [FieldOffset(12)] public float Thickness; - [FieldOffset(16)] public float SoftContactFrequency; - [FieldOffset(20)] public float SoftContactDampingRatio; - [FieldOffset(24)] public float WheelDrag; - [FieldOffset(28)] public float HeatConductivity; - [FieldOffset(32)] public float Flashpoint; - } - - [StructLayout(LayoutKind.Explicit, Size = 88)] - public unsafe struct CPhysSurfacePropertiesSoundNamesTrace - { - [FieldOffset(0)] public CUtlString ImpactSoft; - [FieldOffset(8)] public CUtlString ImpactHard; - [FieldOffset(16)] public CUtlString ScrapeSmooth; - [FieldOffset(24)] public CUtlString ScrapeRough; - [FieldOffset(32)] public CUtlString BulletImpact; - [FieldOffset(40)] public CUtlString Rolling; - [FieldOffset(48)] public CUtlString Break; - [FieldOffset(56)] public CUtlString Strain; - [FieldOffset(64)] public CUtlString MeleeImpact; - [FieldOffset(72)] public CUtlString PushOff; - [FieldOffset(80)] public CUtlString SkidStop; - } - - [StructLayout(LayoutKind.Explicit, Size = 32)] - public unsafe struct CPhysSurfacePropertiesAudioTrace - { - [FieldOffset(0)] public float Reflectivity; - [FieldOffset(4)] public float HardnessFactor; - [FieldOffset(8)] public float RoughnessFactor; - [FieldOffset(12)] public float RoughThreshold; - [FieldOffset(16)] public float HardThreshold; - [FieldOffset(20)] public float HardVelocityThreshold; - [FieldOffset(24)] public float StaticImpactVolume; - [FieldOffset(28)] public float OcclusionFactor; - } - - [StructLayout(LayoutKind.Explicit, Size = 4)] - public unsafe struct CUtlStringToken : IEquatable - { - [FieldOffset(0)] private uint _hashCode; - - public CUtlStringToken(uint hashCode) - { - _hashCode = hashCode; - } - - public bool IsValid => _hashCode != 0; - - public uint GetHashCodeValue() => _hashCode; - - public void SetHashCode(uint hash) => _hashCode = hash; - - public bool Equals(CUtlStringToken other) - => _hashCode == other._hashCode; - - public override bool Equals(object? obj) - => obj is CUtlStringToken other && Equals(other); - - public override int GetHashCode() - => (int)_hashCode; - - public static bool operator ==(CUtlStringToken a, CUtlStringToken b) - => a._hashCode == b._hashCode; - - public static bool operator !=(CUtlStringToken a, CUtlStringToken b) - => a._hashCode != b._hashCode; - - public static bool operator <(CUtlStringToken a, CUtlStringToken b) - => a._hashCode < b._hashCode; - - public static bool operator >(CUtlStringToken a, CUtlStringToken b) - => a._hashCode > b._hashCode; - - public override string ToString() - => $"0x{_hashCode:X8}"; - } - - - [StructLayout(LayoutKind.Explicit, Size = 104)] - public unsafe struct CHitBox - { - [FieldOffset(0)] public CUtlString m_name; // pointer to CUtlString - [FieldOffset(8)] public CUtlString m_sSurfaceProperty; // pointer to CUtlString - [FieldOffset(16)] public CUtlString m_sBoneName; // pointer to CUtlString - - [FieldOffset(24)] public Vector3 m_vMinBounds; // blittable - [FieldOffset(36)] public Vector3 m_vMaxBounds; // blittable - [FieldOffset(48)] public float m_flShapeRadius; - - [FieldOffset(52)] public CUtlStringToken m_nBoneNameHash; // pointer or uint - - [FieldOffset(56)] public byte m_nShapeType; - [FieldOffset(57)] public bool m_bTranslationOnly; - [FieldOffset(60)] public uint m_CRC; - [FieldOffset(64)] public uint m_cRenderColor; - [FieldOffset(68)] public ushort m_nHitBoxIndex; - [FieldOffset(70)] public bool m_bForcedTransform; - - [FieldOffset(72)] public CTransform m_forcedTransform; // only if blittable (no managed types inside) - } - - [StructLayout(LayoutKind.Explicit, Pack = 16, Size = 32)] - public unsafe struct CTransform - { - [FieldOffset(0)] public Vector4 Position; // VectorAligned: use Vector4 for 16-byte alignment - [FieldOffset(16)] public System.Numerics.Quaternion Orientation; - - public CTransform(Vector3 position, System.Numerics.Quaternion orientation) - { - Position = new Vector4(position, 1.0f); // w = 1.0f like vec3_origin.w - Orientation = orientation; - } - - public bool IsValid() - { - return !Position.Equals(Vector4.Zero) && Orientation != System.Numerics.Quaternion.Identity; - } - - public void SetToIdentity() - { - Position = new Vector4(0, 0, 0, 1); // vec3_origin + w = 1 - Orientation = System.Numerics.Quaternion.Identity; // quat_identity - } - - public static bool operator ==(CTransform a, CTransform b) - { - return a.Position == b.Position && a.Orientation == b.Orientation; - } - - public static bool operator !=(CTransform a, CTransform b) - { - return !(a == b); - } - - public override bool Equals(object? obj) - { - return obj is CTransform t && this == t; - } - - public override int GetHashCode() - { - return HashCode.Combine(Position, Orientation); - } - - public override string ToString() - { - return $"CTransform(Position: {Position}, Orientation: {Orientation})"; - } - } - - [StructLayout(LayoutKind.Explicit, Size = 208)] + [StructLayout(LayoutKind.Explicit, Size = 136)] public unsafe struct TraceResult { - [FieldOffset(0)] public float StartPosX; - [FieldOffset(4)] public float StartPosY; - [FieldOffset(8)] public float StartPosZ; + [FieldOffset(0)] public float StartPosX; + [FieldOffset(4)] public float StartPosY; + [FieldOffset(8)] public float StartPosZ; - [FieldOffset(12)] public float EndPosX; - [FieldOffset(16)] public float EndPosY; - [FieldOffset(20)] public float EndPosZ; + [FieldOffset(12)] public float EndPosX; + [FieldOffset(16)] public float EndPosY; + [FieldOffset(20)] public float EndPosZ; - [FieldOffset(24)] public float HitPointX; - [FieldOffset(28)] public float HitPointY; - [FieldOffset(32)] public float HitPointZ; + [FieldOffset(24)] public float HitPointX; + [FieldOffset(28)] public float HitPointY; + [FieldOffset(32)] public float HitPointZ; - [FieldOffset(36)] public float NormalX; - [FieldOffset(40)] public float NormalY; - [FieldOffset(44)] public float NormalZ; + [FieldOffset(36)] public float NormalX; + [FieldOffset(40)] public float NormalY; + [FieldOffset(44)] public float NormalZ; - [FieldOffset(48)] public float Fraction; - [FieldOffset(52)] public float HitOffset; + [FieldOffset(48)] public float Fraction; + [FieldOffset(52)] public float HitOffset; - [FieldOffset(56)] public int TriangleIndex; - [FieldOffset(60)] public int HitboxBoneIndex; + [FieldOffset(56)] public int TriangleIndex; + [FieldOffset(60)] public int HitboxBoneIndex; - [FieldOffset(64)] public int Contents; - [FieldOffset(68)] public int RayType; + [FieldOffset(64)] public int Contents; + [FieldOffset(68)] public int RayType; - [FieldOffset(72)] public byte AllSolid; - [FieldOffset(73)] public byte ExactHitPoint; + [FieldOffset(72)] public int AllSolid; + [FieldOffset(76)] public int ExactHitPoint; - [FieldOffset(74)] private ushort _padFlags; + // pointer section + [FieldOffset(80)] public nint HitEntityPtr; + [FieldOffset(88)] public nint HitboxPtr; + [FieldOffset(96)] public nint SurfacePropsPtr; + [FieldOffset(104)] public nint BodyHandle; + [FieldOffset(112)] public nint ShapeHandle; - [FieldOffset(80)] public nint HitEntityHandle; - [FieldOffset(88)] public nint HitboxHandle; - [FieldOffset(96)] public nint SurfacePropsHandle; - [FieldOffset(104)] public nint BodyHandle; - [FieldOffset(112)] public nint ShapeHandle; + // thread safe heap pointer section + [FieldOffset(120)] public nint BodyTransformPtr; + [FieldOffset(128)] public nint ShapeAttributesPtr; - [FieldOffset(120)] private long _padAlign; + public unsafe ref T GetRef(nint ptr) where T : unmanaged + { + if (ptr == 0) + throw new NullReferenceException(); - [FieldOffset(128)] public CTransform BodyTransform; - [FieldOffset(160)] public RnCollisionAttr_t ShapeAttributes; + return ref *(T*)ptr; + } + + public T? GetObject(nint ptr) where T : class + { + if (ptr == 0) + return null; + + return (T)Activator.CreateInstance(typeof(T), ptr)!; + } public Vector3 StartPos => new(StartPosX, StartPosY, StartPosZ); - public Vector3 EndPos => new(EndPosX, EndPosY, EndPosZ); - public Vector3 HitPoint => new(HitPointX, HitPointY, HitPointZ); - public Vector3 Normal => new(NormalX, NormalY, NormalZ); + public Vector3 EndPos => new(EndPosX, EndPosY, EndPosZ); + public Vector3 HitPoint => new(HitPointX, HitPointY, HitPointZ); + public Vector3 Normal => new(NormalX, NormalY, NormalZ); public bool DidHit => Fraction < 1.0f; public bool IsAllSolid => AllSolid != 0; public bool HasExactHit => ExactHitPoint != 0; - public CPhysSurfacePropertiesTrace SurfaceProps => SurfacePropsHandle == 0 ? default : Marshal.PtrToStructure(SurfacePropsHandle); - public CHitBox Hitbox => HitboxHandle == 0 ? default : Marshal.PtrToStructure(HitboxHandle); - public CEntityInstance? HitEntity => HitEntityHandle == 0 ? null : new CEntityInstance(HitEntityHandle); + public CEntityInstance? HitEntity => GetObject(HitEntityPtr); } #endregion diff --git a/public/craytraceinterface.h b/public/craytraceinterface.h index 104bfa6..f00cdfc 100644 --- a/public/craytraceinterface.h +++ b/public/craytraceinterface.h @@ -172,8 +172,8 @@ struct TraceResult IPhysicsBody *BodyHandle; IPhysicsShape *ShapeHandle; - CTransform BodyTransform; - RnCollisionAttr_t ShapeAttributes; + CTransform *BodyTransform; + RnCollisionAttr_t *ShapeAttributes; }; class CRayTraceInterface diff --git a/src/raytrace.cpp b/src/raytrace.cpp index ea8e585..879639b 100644 --- a/src/raytrace.cpp +++ b/src/raytrace.cpp @@ -25,17 +25,16 @@ namespace RayTracePlugin::RayTrace bool Initialize() { - void* pCNavPhysicsInterfaceVTable = - DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CNavPhysicsInterface"); + DynLibUtils::CModule libserver = DynLibUtils::CModule(shared::g_pServer); + void** pVTable = libserver.GetVirtualTableByName("CNavPhysicsInterface").RCast(); - if (!pCNavPhysicsInterfaceVTable) + if (!pVTable) { - FP_ERROR("Failed to find CNavPhysicsInterface vtable!"); + FP_ERROR("Failed to find CNavPhysicsInterface VTable!"); return false; } - auto table = static_cast(pCNavPhysicsInterfaceVTable); - s_TraceShape = reinterpret_cast(table[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")]); + s_TraceShape = DynLibUtils::CMemory(pVTable[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")]).RCast(); return true; } @@ -66,7 +65,7 @@ namespace RayTracePlugin::RayTrace return std::nullopt; } - CGameTrace tr{}; + thread_local CGameTrace tr{}; Vector startCopy = start; Vector endCopy = end; s_TraceShape(nullptr, rayInc, startCopy, endCopy, @@ -91,17 +90,17 @@ namespace RayTracePlugin::RayTrace r.TriangleIndex = tr.m_nTriangle; r.HitboxBoneIndex = tr.m_nHitboxBoneIndex; r.Contents = tr.m_nContents; - r.RayType = static_cast(tr.m_eRayType); + r.RayType = (int)tr.m_eRayType; r.AllSolid = tr.m_bStartInSolid; r.ExactHitPoint = tr.m_bExactHitPoint; - r.HitEntity = tr.m_pEnt; - r.Hitbox = const_cast(tr.m_pHitbox); - r.SurfaceProps = const_cast(tr.m_pSurfaceProperties); - r.BodyHandle = tr.m_hBody; - r.ShapeHandle = tr.m_hShape; - r.BodyTransform = tr.m_BodyTransform; - r.ShapeAttributes = tr.m_ShapeAttributes; + r.HitEntity = (CEntityInstance*)tr.m_pEnt; + r.Hitbox = (CHitBox*)tr.m_pHitbox; + r.SurfaceProps = (CPhysSurfaceProperties*)tr.m_pSurfaceProperties; + r.BodyHandle = (IPhysicsBody*)tr.m_hBody; + r.ShapeHandle = (IPhysicsShape*)tr.m_hShape; + r.BodyTransform = &tr.m_BodyTransform; + r.ShapeAttributes = &tr.m_ShapeAttributes; return r; }