Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions managed/CounterStrikeSharp.API/Core/Model/CBaseEntity.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;

namespace CounterStrikeSharp.API.Core;

public partial class CBaseEntity
{
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
/// <exception cref="ArgumentNullException">No valid argument</exception>
/// <exception cref="ArgumentNullException">At least one parameter must be specified</exception>
public void Teleport(Vector? position = null, QAngle? angles = null, Vector? velocity = null)
{
Guard.IsValidEntity(this);

if (position == null && angles == null && velocity == null)
throw new ArgumentNullException("No valid argument");
throw new ArgumentException("At least one parameter must be specified");

nint _position = position?.Handle ?? 0;
nint _angles = angles?.Handle ?? 0;
Expand All @@ -25,6 +27,47 @@ public void Teleport(Vector? position = null, QAngle? angles = null, Vector? vel
_angles, _velocity);
}

/// <summary>
/// Teleports the entity to the specified position, angles, and velocity using Vector3 parameters.
/// This overload is optimized for memory efficiency by directly working with a Vector3 struct.
/// </summary>
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
/// <exception cref="ArgumentException">At least one parameter must be specified</exception>
public void Teleport(Vector3? position = null, Vector3? angles = null, Vector3? velocity = null)
{
Guard.IsValidEntity(this);

if (position == null && angles == null && velocity == null)
throw new ArgumentException("At least one parameter must be specified");

unsafe
{
void* positionPtr = null, anglePtr = null, velocityPtr = null;

if (position.HasValue)
{
var pos = position.Value;
positionPtr = &pos;
}

if (angles.HasValue)
{
var ang = angles.Value;
anglePtr = &ang;
}

if (velocity.HasValue)
{
var vel = velocity.Value;
velocityPtr = &vel;
}

VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(Handle, GameData.GetOffset("CBaseEntity_Teleport"))(Handle,
(nint)positionPtr,
(nint)anglePtr, (nint)velocityPtr);
}
}

/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public void DispatchSpawn()
{
Expand Down Expand Up @@ -62,7 +105,7 @@ public void DispatchSpawn()
public uint EmitSound(string soundEventName, RecipientFilter? recipients = null, float volume = 1f, float pitch = 0)
{
Guard.IsValidEntity(this);

if (recipients == null)
{
recipients = new RecipientFilter();
Expand Down
20 changes: 17 additions & 3 deletions managed/CounterStrikeSharp.API/Modules/Utils/QAngle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/

using System.Numerics;
using System.Runtime.CompilerServices;

namespace CounterStrikeSharp.API.Modules.Utils
{
public class QAngle : NativeObject
{
public static readonly QAngle Zero = new();

public QAngle(IntPtr pointer) : base(pointer)
{
}

public QAngle(float? x = null, float? y = null, float? z = null) : this(NativeAPI.AngleNew())
{
this.X = x ?? 0;
Expand All @@ -36,10 +37,23 @@ public QAngle(float? x = null, float? y = null, float? z = null) : this(NativeAP
public unsafe ref float X => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 0);
public unsafe ref float Y => ref Unsafe.Add(ref *(float*)Handle, 1);
public unsafe ref float Z => ref Unsafe.Add(ref *(float*)Handle, 2);

public override string ToString()
{
return $"{X:n2} {Y:n2} {Z:n2}";
}

public static explicit operator Vector3(QAngle q)
{
unsafe
{
if (q is null)
{
throw new ArgumentNullException(nameof(q), "Input QAngle cannot be null.");
}

return new Vector3(new ReadOnlySpan<float>(q.Handle.ToPointer(), 3));
}
}
}
}
16 changes: 16 additions & 0 deletions managed/CounterStrikeSharp.API/Modules/Utils/Vector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ public void Zero()
NativePINVOKE.Vector_Zero(ptr);
}
*/

#region Operators

public float this[int i]
Expand Down Expand Up @@ -351,12 +352,27 @@ public float this[int i]
{
return new Vector(a.X * b, a.Y * b, a.Z * b);
}

public static Vector operator /(Vector a, float b)
{
return new Vector(a.X / b, a.Y / b, a.Z / b);
}

public static explicit operator Vector3(Vector v)
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit cast operator lacks input validation. Consider adding a null check for the Vector parameter to prevent potential access violations when Handle.ToPointer() is called on a null or invalid Vector.

Copilot uses AI. Check for mistakes.
{
unsafe
{
if (v is null)
{
throw new ArgumentNullException(nameof(v), "Input Vector cannot be null.");
}

return new Vector3(new ReadOnlySpan<float>(v.Handle.ToPointer(), 3));
}
}

#endregion

/*

public override bool Equals(object obj)
Expand Down
Loading