jRandomSkills/jRandomSkills - SRC Files/src/utils/RayTrace.cs
Juzlus 42e5453fd4 v1.2.2.b4
- #### General:
    - ###### Updated the GitHub source code to implement the changes introduced in merge request (https://github.com/Juzlus/jRandomSkills/pull/32).

- #### Skill improvements:
    - ###### Ninja:
        - ###### Removed debug chat messages that were used for testing.
2026-06-29 16:10:59 +02:00

358 lines
No EOL
13 KiB
C#

using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using RayTraceAPI;
using System.Drawing;
using System.Numerics;
using TraceOptions = RayTraceAPI.TraceOptions;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
namespace src.utils
{
public static class RayTrace
{
private static PluginCapability<CRayTraceInterface> RayTraceInterface { get; } = new("raytrace:craytraceinterface");
public static CustomTraceResult? TraceShape(CCSPlayerController player, Vector startPos, Vector endPos, ulong? mask = null, ulong? contents = null)
{
if (player == null || !player.IsValid) return null;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null ||
!playerPawn.IsValid ||
playerPawn.Handle == IntPtr.Zero ||
playerPawn.Collision == null ||
playerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE ||
playerPawn.CBodyComponent?.SceneNode == null)
return null;
CRayTraceInterface? rayTrace;
try { rayTrace = RayTraceInterface.Get(); }
catch { return null; }
if (rayTrace == null)
return null;
if (mask == null)
{
try
{
if (playerPawn.Collision?.CollisionAttribute != null)
{
mask = playerPawn.Collision.CollisionAttribute.InteractsWith | (ulong)InteractionLayers.Hitboxes;
mask &= ~(ulong)InteractionLayers.PlayerClip;
}
else
mask = (ulong)(InteractionLayers.Solid | InteractionLayers.Hitboxes);
}
catch
{
mask = (ulong)(InteractionLayers.Solid | InteractionLayers.Hitboxes);
}
}
contents ??= 0;
bool drawBeam = Config.LoadedConfig.TraceRayBeam;
TraceOptions options = new()
{
InteractsWith = (ulong)mask,
InteractsExclude = (ulong)contents,
DrawBeam = drawBeam == true ? 1 : 0,
};
Vector mins = new(-0.5f, -0.5f, -0.5f);
Vector maxs = new(0.5f, 0.5f, 0.5f);
TraceResult result = default;
try
{
rayTrace.TraceHullShape(startPos, endPos, mins, maxs, playerPawn, options, out result);
}
catch (Exception ex)
{
Console.WriteLine($"[jRandomSkills] A memory error was caught during RayTrace: {ex.Message}");
return null;
}
return new CustomTraceResult(result, startPos, (ulong)mask, (ulong)contents, drawBeam);
}
public static CustomTraceResult? EyeTrace(CCSPlayerController player)
{
if (player == null || !player.IsValid) return null;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null)
return null;
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
if (playerInfo == null) return null;
float maxDistance = SkillsInfo.GetValue<float>(playerInfo.Skill, "maxDistance");
if (maxDistance == 0) maxDistance = 4096f;
Vector startPos = new(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z + playerPawn.ViewOffset.Z);
Vector endPos = startPos + SkillUtils.GetForwardVector(playerPawn.EyeAngles) * maxDistance;
return TraceShape(player, startPos, endPos);
}
public static CustomTraceResult? TraceHullShape(Vector startPos, Vector endPos, CCSPlayerController player, Vector? mins = null, Vector? maxs = null, ulong? mask = null, ulong? contents = null, QAngle? angle = null)
{
if (player == null || !player.IsValid) return null;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null ||
!playerPawn.IsValid ||
playerPawn.Handle == IntPtr.Zero ||
playerPawn.Collision == null ||
playerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE ||
playerPawn.CBodyComponent?.SceneNode == null)
return null;
CRayTraceInterface? rayTrace;
try { rayTrace = RayTraceInterface.Get(); }
catch { return null; }
if (rayTrace == null)
return null;
Vector safeMins = mins ?? playerPawn.Collision.Mins;
Vector safeMaxs = maxs ?? playerPawn.Collision.Maxs;
ulong safeMask = mask ?? playerPawn.Collision.CollisionAttribute.InteractsWith;
ulong safeContents = contents ?? 0;
bool drawBeam = Config.LoadedConfig.TraceRayBeam;
TraceResult result = default;
TraceOptions options = new()
{
InteractsWith = safeMask,
InteractsExclude = safeContents,
DrawBeam = drawBeam == true ? 1 : 0,
};
CEntityInstance? entityToIgnore = (playerPawn.LifeState == (byte)LifeState_t.LIFE_ALIVE)
? playerPawn
: null;
try
{
rayTrace.TraceHullShape(startPos, endPos, safeMins, safeMaxs, entityToIgnore, options, out result);
}
catch (Exception)
{
return null;
}
if (drawBeam)
{
angle ??= new(0, playerPawn.EyeAngles.Y, 0);
DrawBoxEdges(startPos, endPos, angle, safeMins, safeMaxs, Color.Green);
}
return new CustomTraceResult(result, startPos, safeMask, safeContents, drawBeam);
}
private static void DrawBoxEdges(Vector start, Vector end, QAngle angles, Vector mins, Vector maxs, Color color)
{
AngleVectors(angles, out Vector forward, out Vector right, out Vector up);
float halfLength = (maxs.X - mins.X) / 2.0f;
Vector visualStart = start - (forward * halfLength);
Vector visualEnd = end + (forward * halfLength);
Vector GetVertex(Vector center, float rx, float ux)
{
return center + (right * rx) + (up * ux);
}
Vector[] s = [
GetVertex(visualStart, mins.Y, mins.Z),
GetVertex(visualStart, maxs.Y, mins.Z),
GetVertex(visualStart, maxs.Y, maxs.Z),
GetVertex(visualStart, mins.Y, maxs.Z)
];
Vector[] e = [
GetVertex(visualEnd, mins.Y, mins.Z),
GetVertex(visualEnd, maxs.Y, mins.Z),
GetVertex(visualEnd, maxs.Y, maxs.Z),
GetVertex(visualEnd, mins.Y, maxs.Z)
];
for (int i = 0; i < 4; i++)
{
int next = (i + 1) % 4;
CreateBeamLine(s[i], s[next], color);
CreateBeamLine(e[i], e[next], color);
CreateBeamLine(s[i], e[i], color);
}
}
private static void AngleVectors(QAngle angles, out Vector forward, out Vector right, out Vector up)
{
float sp, sy, cp, cy, sr, cr;
float pitch = angles.X * (MathF.PI / 180.0f);
float yaw = angles.Y * (MathF.PI / 180.0f);
float roll = angles.Z * (MathF.PI / 180.0f);
sp = MathF.Sin(pitch); cp = MathF.Cos(pitch);
sy = MathF.Sin(yaw); cy = MathF.Cos(yaw);
sr = MathF.Sin(roll); cr = MathF.Cos(roll);
forward = new Vector(cp * cy, cp * sy, -sp);
right = new Vector(-1 * sr * sp * cy + cr * sy, -1 * sr * sp * sy - cr * cy, -1 * sr * cp);
up = new Vector(cr * sp * cy + sr * sy, cr * sp * sy - sr * cy, cr * cp);
}
private static void CreateBeamLine(Vector start, Vector end, Color color)
{
var beam = Utilities.CreateEntityByName<CBeam>("env_beam");
if (beam == null || !beam.IsValid) return;
beam.Render = color;
beam.Width = 1.3f;
beam.Teleport(start, new QAngle(0, 0, 0), new Vector(0, 0, 0));
beam.EndPos.X = end.X;
beam.EndPos.Y = end.Y;
beam.EndPos.Z = end.Z;
beam.DispatchSpawn();
}
public static float Distance(this CustomTraceResult result)
{
return Vector3.Distance(result.StartPos, result.EndPos);
}
public static Vector3 Direction(this CustomTraceResult result)
{
return Vector3.Normalize(result.EndPos - result.Normal);
}
public static bool HitEntityByDesignerName<T>(this CustomTraceResult result, out T? entity, string designerName, DesignerNameMatchType matchType = DesignerNameMatchType.Equals) where T : CEntityInstance
{
T? val = (T?)Activator.CreateInstance(typeof(T), result.HitEntity);
if ((object?)val != null && matchType switch
{
DesignerNameMatchType.Equals => val.DesignerName == designerName,
DesignerNameMatchType.StartsWith => val.DesignerName.StartsWith(designerName, StringComparison.OrdinalIgnoreCase),
DesignerNameMatchType.EndsWith => val.DesignerName.EndsWith(designerName, StringComparison.OrdinalIgnoreCase),
_ => false,
})
{
entity = val;
return true;
}
entity = null;
return false;
}
public static bool HitEntity(this CustomTraceResult result, out CBaseEntity? entity)
{
CEntityInstance entityInstance = new(result.HitEntity);
if (string.IsNullOrEmpty(entityInstance.DesignerName))
{
entity = null;
return false;
}
entity = entityInstance.As<CBaseEntity>();
return entity != null;
}
public static bool HitPlayer(this CustomTraceResult result, out CCSPlayerController? player)
{
if (result.HitEntityByDesignerName<CCSPlayerPawn>(out CCSPlayerPawn? entity, "player"))
{
player = entity?.OriginalController.Value;
return player != null;
}
player = null;
return false;
}
public static bool HitWeapon(this CustomTraceResult result, out CBasePlayerWeapon? weapon)
{
return result.HitEntityByDesignerName<CBasePlayerWeapon>(out weapon, "weapon_", DesignerNameMatchType.StartsWith);
}
public static bool HitChicken(this CustomTraceResult result, out CChicken? chicken)
{
return result.HitEntityByDesignerName<CChicken>(out chicken, "chicken");
}
public static bool HitButton(this CustomTraceResult result, out CBaseButton? button)
{
return result.HitEntityByDesignerName<CBaseButton>(out button, "func_door");
}
public static bool HitBuyzone(this CustomTraceResult result, out CBuyZone? buyzone)
{
return result.HitEntityByDesignerName<CBuyZone>(out buyzone, "func_buyzone");
}
public static bool HitSky(this CustomTraceResult result, out CEnvSky? sky)
{
return result.HitEntityByDesignerName<CEnvSky>(out sky, "env_sky");
}
public static bool HitDoor(this CustomTraceResult result, out CBaseDoor? door)
{
return result.HitEntityByDesignerName<CBaseDoor>(out door, "func_door");
}
public static bool HitDoor(this CustomTraceResult result, out CRotDoor? door)
{
return result.HitEntityByDesignerName<CRotDoor>(out door, "func_door_rotating");
}
public static bool HitLadder(this CustomTraceResult result, out CFuncLadder? ladder)
{
return result.HitEntityByDesignerName<CFuncLadder>(out ladder, "func_ladder");
}
public static bool HitGrenade(this CustomTraceResult result, out CBaseCSGrenade? grenade)
{
return result.HitEntityByDesignerName<CBaseCSGrenade>(out grenade, "grenade");
}
public static bool HitPlantedC4(this CustomTraceResult result, out CPlantedC4? c4)
{
return result.HitEntityByDesignerName<CPlantedC4>(out c4, "planted_c4");
}
public static bool HitPointWorldText(this CustomTraceResult result, out CPointWorldText? pointWorldText)
{
return result.HitEntityByDesignerName<CPointWorldText>(out pointWorldText, "point_worldtext");
}
public static bool HitC4(this CustomTraceResult result, out CC4? c4)
{
return result.HitEntityByDesignerName<CC4>(out c4, "weapon_c4");
}
public static bool HitWorld(this CustomTraceResult result, out CWorld? world)
{
return result.HitEntityByDesignerName<CWorld>(out world, "worldent");
}
public enum DesignerNameMatchType
{
Equals,
StartsWith,
EndsWith
}
}
}