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
35 changes: 30 additions & 5 deletions managed/CounterStrikeSharp.API/BaseNative.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -15,22 +15,47 @@
*/

using System;
using System.Text;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;

namespace CounterStrikeSharp.API
{
public abstract class NativeObject
{
public IntPtr Handle { get; internal set; }
private IntPtr _handle;

public IntPtr Handle
{
get
{
if (_handle == IntPtr.Zero)
{
EnsureNativeHandle();
}

return _handle;
}
internal set => _handle = value;
}

internal IntPtr RawHandle => _handle;

protected NativeObject(IntPtr pointer)
{
Handle = pointer;
_handle = pointer;
}


protected void SetHandle(IntPtr pointer)
{
_handle = pointer;
}

protected virtual void EnsureNativeHandle()
{
}

/// <summary>
/// Returns a new instance of the specified type using the pointer from the passed in object.
/// </summary>
Expand All @@ -42,7 +67,7 @@
/// <returns></returns>
public T As<T>() where T : NativeObject
{
return (T)Activator.CreateInstance(typeof(T), this.Handle);

Check warning on line 70 in managed/CounterStrikeSharp.API/BaseNative.cs

View workflow job for this annotation

GitHub Actions / build_managed

Possible null reference return.

Check warning on line 70 in managed/CounterStrikeSharp.API/BaseNative.cs

View workflow job for this annotation

GitHub Actions / build_managed

Converting null literal or possible null value to non-nullable type.

Check warning on line 70 in managed/CounterStrikeSharp.API/BaseNative.cs

View workflow job for this annotation

GitHub Actions / build_managed

Possible null reference return.

Check warning on line 70 in managed/CounterStrikeSharp.API/BaseNative.cs

View workflow job for this annotation

GitHub Actions / build_managed

Converting null literal or possible null value to non-nullable type.
}
}
}
256 changes: 123 additions & 133 deletions managed/CounterStrikeSharp.API/Core/Model/CBaseEntity.cs
Original file line number Diff line number Diff line change
@@ -1,133 +1,123 @@
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">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 ArgumentException("At least one parameter must be specified");

nint _position = position?.Handle ?? 0;
nint _angles = angles?.Handle ?? 0;
nint _velocity = velocity?.Handle ?? 0;
nint _handle = Handle;

VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(_handle, GameData.GetOffset("CBaseEntity_Teleport"))(_handle, _position,
_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(CEntityKeyValues? keyValues)
{
Guard.IsValidEntity(this);

NativeAPI.DispatchSpawn(Handle, keyValues?.Handle ?? IntPtr.Zero);
}

public void DispatchSpawn()
{
Guard.IsValidEntity(this);
NativeAPI.DispatchSpawn(Handle, IntPtr.Zero);
}

/// <summary>
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsOrigin;
/// </summary>
public Vector? AbsOrigin => CBodyComponent?.SceneNode?.AbsOrigin;

/// <summary>
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsRotation;
/// </summary>
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public QAngle? AbsRotation => CBodyComponent?.SceneNode?.AbsRotation;

public T? GetVData<T>() where T : CEntitySubclassVDataBase
{
Guard.IsValidEntity(this);

return (T)Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
}

/// <summary>
/// Emit a soundevent to all players.
/// </summary>
/// <param name="soundEventName">The name of the soundevent to emit.</param>
/// <param name="recipients">The recipients of the soundevent.</param>
/// <param name="volume">The volume of the soundevent.</param>
/// <param name="pitch">The pitch of the soundevent.</param>
/// <returns>The sound event guid.</returns>
public uint EmitSound(string soundEventName, RecipientFilter? recipients = null, float volume = 1f, float pitch = 0)
{
Guard.IsValidEntity(this);

if (recipients == null)
{
recipients = new RecipientFilter();
recipients.AddAllPlayers();
}

return NativeAPI.EmitSoundFilter(recipients.GetRecipientMask(), this.Index, soundEventName, volume, pitch);
}

/// <summary>
/// Returns true if the entity is a player pawn.
/// </summary>
public bool IsPlayerPawn()
{
Guard.IsValidEntity(this);

return VirtualFunction.Create<IntPtr, bool>(Handle, GameData.GetOffset("CBaseEntity_IsPlayerPawn"))(Handle);
}
}
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">At least one parameter must be specified</exception>
public void Teleport(Vector? position = null, QAngle? angles = null, Vector? velocity = null)
{
Teleport(position == null ? null : (Vector3)position, angles == null ? null : (Vector3)angles,
velocity == null ? null : (Vector3)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(CEntityKeyValues? keyValues)
{
Guard.IsValidEntity(this);

NativeAPI.DispatchSpawn(Handle, keyValues?.Handle ?? IntPtr.Zero);
}

public void DispatchSpawn()
{
Guard.IsValidEntity(this);
NativeAPI.DispatchSpawn(Handle, IntPtr.Zero);
}

/// <summary>
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsOrigin;
/// </summary>
public Vector? AbsOrigin => CBodyComponent?.SceneNode?.AbsOrigin;

/// <summary>
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsRotation;
/// </summary>
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public QAngle? AbsRotation => CBodyComponent?.SceneNode?.AbsRotation;

public T? GetVData<T>() where T : CEntitySubclassVDataBase
{
Guard.IsValidEntity(this);

return (T)Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
}

/// <summary>
/// Emit a soundevent to all players.
/// </summary>
/// <param name="soundEventName">The name of the soundevent to emit.</param>
/// <param name="recipients">The recipients of the soundevent.</param>
/// <param name="volume">The volume of the soundevent.</param>
/// <param name="pitch">The pitch of the soundevent.</param>
/// <returns>The sound event guid.</returns>
public uint EmitSound(string soundEventName, RecipientFilter? recipients = null, float volume = 1f, float pitch = 0)
{
Guard.IsValidEntity(this);

if (recipients == null)
{
recipients = new RecipientFilter();
recipients.AddAllPlayers();
}

return NativeAPI.EmitSoundFilter(recipients.GetRecipientMask(), this.Index, soundEventName, volume, pitch);
}

/// <summary>
/// Returns true if the entity is a player pawn.
/// </summary>
public bool IsPlayerPawn()
{
Guard.IsValidEntity(this);

return VirtualFunction.Create<IntPtr, bool>(Handle, GameData.GetOffset("CBaseEntity_IsPlayerPawn"))(Handle);
}
}
Loading
Loading