diff --git a/managed/CounterStrikeSharp.API/Core/API.cs b/managed/CounterStrikeSharp.API/Core/API.cs index 94c794624..9e30d8ae2 100644 --- a/managed/CounterStrikeSharp.API/Core/API.cs +++ b/managed/CounterStrikeSharp.API/Core/API.cs @@ -780,6 +780,68 @@ public static void AddEntityIoEvent(IntPtr ptarget, string inputname, IntPtr act } } + public static void DispatchSpawn(IntPtr entity, IntPtr keyvalues){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.Push(entity); + ScriptContext.GlobalScriptContext.Push(keyvalues); + ScriptContext.GlobalScriptContext.SetIdentifier(0xAE01E931); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + } + } + + public static IntPtr EntityKeyValuesNew(){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.SetIdentifier(0x445FE212); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr)); + } + } + + public static T EntityKeyValuesGetValue(IntPtr keyvalues, string key, uint type){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.Push(keyvalues); + ScriptContext.GlobalScriptContext.Push(key); + ScriptContext.GlobalScriptContext.Push(type); + ScriptContext.GlobalScriptContext.SetIdentifier(0xA9A569AC); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (T)ScriptContext.GlobalScriptContext.GetResult(typeof(T)); + } + } + + public static void EntityKeyValuesSetValue(IntPtr keyvalues, string key, uint type, object[] arguments){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.Push(keyvalues); + ScriptContext.GlobalScriptContext.Push(key); + ScriptContext.GlobalScriptContext.Push(type); + foreach (var obj in arguments) + { + ScriptContext.GlobalScriptContext.Push(obj); + } + ScriptContext.GlobalScriptContext.SetIdentifier(0x60234AB8); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + } + } + + public static bool EntityKeyValuesHasValue(IntPtr keyvalues, string key){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.Push(keyvalues); + ScriptContext.GlobalScriptContext.Push(key); + ScriptContext.GlobalScriptContext.SetIdentifier(0xD3E04DA0); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (bool)ScriptContext.GlobalScriptContext.GetResult(typeof(bool)); + } + } + public static void HookEvent(string name, InputArgument callback, bool ispost){ lock (ScriptContext.GlobalScriptContext.Lock) { ScriptContext.GlobalScriptContext.Reset(); @@ -1657,6 +1719,46 @@ public static IntPtr VectorNew(){ } } + public static IntPtr Vector2dNew(){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.SetIdentifier(0x2CD71169); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr)); + } + } + + public static IntPtr Vector4dNew(){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.SetIdentifier(0x16585EAF); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr)); + } + } + + public static IntPtr Matrix3x4New(){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.SetIdentifier(0xA2E1A42); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr)); + } + } + + public static IntPtr QuaternionNew(){ + lock (ScriptContext.GlobalScriptContext.Lock) { + ScriptContext.GlobalScriptContext.Reset(); + ScriptContext.GlobalScriptContext.SetIdentifier(0xD27D7946); + ScriptContext.GlobalScriptContext.Invoke(); + ScriptContext.GlobalScriptContext.CheckErrors(); + return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr)); + } + } + public static IntPtr AngleNew(){ lock (ScriptContext.GlobalScriptContext.Lock) { ScriptContext.GlobalScriptContext.Reset(); diff --git a/managed/CounterStrikeSharp.API/Core/Model/CBaseEntity.cs b/managed/CounterStrikeSharp.API/Core/Model/CBaseEntity.cs index a759e2bda..135f58e0b 100644 --- a/managed/CounterStrikeSharp.API/Core/Model/CBaseEntity.cs +++ b/managed/CounterStrikeSharp.API/Core/Model/CBaseEntity.cs @@ -26,11 +26,17 @@ public void Teleport(Vector? position = null, QAngle? angles = null, Vector? vel } /// Entity is not valid - public void DispatchSpawn() + public void DispatchSpawn(CEntityKeyValues? keyValues = null) { - Guard.IsValidEntity(this); - - VirtualFunctions.CBaseEntity_DispatchSpawn(Handle, IntPtr.Zero); + Guard.IsValidEntity(this); + + if (keyValues != null) + { + NativeAPI.DispatchSpawn(Handle, keyValues.Handle); + } else + { + VirtualFunctions.CBaseEntity_DispatchSpawn(Handle, IntPtr.Zero); + } } /// diff --git a/managed/CounterStrikeSharp.API/Core/ScriptContext.cs b/managed/CounterStrikeSharp.API/Core/ScriptContext.cs index 11a3bdc6b..2914e782a 100644 --- a/managed/CounterStrikeSharp.API/Core/ScriptContext.cs +++ b/managed/CounterStrikeSharp.API/Core/ScriptContext.cs @@ -23,8 +23,8 @@ * under GNU Lesser General Public License, version 2. */ -using System; using System.Collections.Concurrent; +using System.Drawing; using System.Runtime.InteropServices; using System.Security; using System.Text; @@ -449,6 +449,19 @@ internal unsafe object GetResult(Type type, byte* ptr) return Activator.CreateInstance(type, pointer); } + if (type == typeof(Color)) + { + var pointer = (IntPtr)GetResult(typeof(IntPtr), ptr); + return Marshaling.ColorMarshaler.NativeToManaged(pointer); + } + + // this one only works if the 'Raw'/uint is passed, otherwise big bum + // maybe do this with a marshaler?! + if (type == typeof(CEntityHandle)) + { + return new CEntityHandle((uint)GetResult(typeof(uint), ptr)); + } + if (type == typeof(object)) { // var dataPtr = *(IntPtr*)&ptr[0]; diff --git a/managed/CounterStrikeSharp.API/Modules/Utils/CEntityKeyValues.cs b/managed/CounterStrikeSharp.API/Modules/Utils/CEntityKeyValues.cs new file mode 100644 index 000000000..a853a7cc7 --- /dev/null +++ b/managed/CounterStrikeSharp.API/Modules/Utils/CEntityKeyValues.cs @@ -0,0 +1,364 @@ +/* + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CounterStrikeSharp is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CounterStrikeSharp. If not, see . * + */ + +using System.Drawing; + +namespace CounterStrikeSharp.API.Modules.Utils +{ + /// + /// WARNING: This is intended to be only used with for now! + /// + public enum KeyValuesType : uint + { + TYPE_BOOL, + TYPE_INT, + TYPE_UINT, + TYPE_INT64, + TYPE_UINT64, + TYPE_FLOAT, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_POINTER, + TYPE_STRING_TOKEN, + TYPE_EHANDLE, + TYPE_COLOR, + TYPE_VECTOR, + TYPE_VECTOR2D, + TYPE_VECTOR4D, + TYPE_QUATERNION, + TYPE_QANGLE, + TYPE_MATRIX3X4 + } + + /// + /// WARNING: This is intended to be only used with for now! + /// + public class CEntityKeyValues : NativeObject + { + public CEntityKeyValues() : base(NativeAPI.EntityKeyValuesNew()) + { } + + public CEntityKeyValues(nint pointer) : base(pointer) + { } + + public object? this[string key, KeyValuesType type] + { + get + { + return type switch + { + KeyValuesType.TYPE_BOOL => GetBool(key), + KeyValuesType.TYPE_INT => GetInt(key), + KeyValuesType.TYPE_UINT => GetUInt(key), + KeyValuesType.TYPE_INT64 => GetInt64(key), + KeyValuesType.TYPE_UINT64 => GetUInt64(key), + KeyValuesType.TYPE_FLOAT => GetFloat(key), + KeyValuesType.TYPE_DOUBLE => GetDouble(key), + KeyValuesType.TYPE_STRING => GetString(key), + KeyValuesType.TYPE_POINTER => GetPointer(key), + KeyValuesType.TYPE_STRING_TOKEN => GetStringToken(key), + KeyValuesType.TYPE_EHANDLE => GetEHandle(key), + KeyValuesType.TYPE_COLOR => GetColor(key), + KeyValuesType.TYPE_VECTOR => GetVector(key), + KeyValuesType.TYPE_VECTOR2D => GetVector2D(key), + KeyValuesType.TYPE_VECTOR4D => GetVector4D(key), + KeyValuesType.TYPE_QUATERNION => GetQuaternion(key), + KeyValuesType.TYPE_QANGLE => GetAngle(key), + KeyValuesType.TYPE_MATRIX3X4 => GetMatrix3x4(key), + _ => null + }; + } + + set + { +#pragma warning disable CS8605 // Unboxing a possibly null value. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8604 // Possible null reference argument. + switch (type) + { + case KeyValuesType.TYPE_BOOL: + SetBool(key, (bool)value); + break; + case KeyValuesType.TYPE_INT: + SetInt(key, (int)value); + break; + case KeyValuesType.TYPE_UINT: + SetUInt(key, (uint)value); + break; + case KeyValuesType.TYPE_INT64: + SetInt64(key, (long)value); + break; + case KeyValuesType.TYPE_UINT64: + SetUInt64(key, (ulong)value); + break; + case KeyValuesType.TYPE_FLOAT: + SetFloat(key, (float)value); + break; + case KeyValuesType.TYPE_DOUBLE: + SetDouble(key, (double)value); + break; + case KeyValuesType.TYPE_STRING: + SetString(key, (string)value); + break; + case KeyValuesType.TYPE_POINTER: + SetPointer(key, (nint)value); + break; + case KeyValuesType.TYPE_STRING_TOKEN: + // TODO: use 'CUtlStringToken' once we have it + SetStringToken(key, (uint)value); + break; + case KeyValuesType.TYPE_EHANDLE: + SetEHandle(key, (CEntityHandle)value); + break; + case KeyValuesType.TYPE_COLOR: + SetColor(key, (Color)value); + break; + case KeyValuesType.TYPE_VECTOR: + SetVector(key, (Vector)value); + break; + case KeyValuesType.TYPE_VECTOR2D: + SetVector2D(key, (Vector2D)value); + break; + case KeyValuesType.TYPE_VECTOR4D: + SetVector4D(key, (Vector4D)value); + break; + case KeyValuesType.TYPE_QUATERNION: + SetQuaternion(key, (Quaternion)value); + break; + case KeyValuesType.TYPE_QANGLE: + SetAngle(key, (QAngle)value); + break; + case KeyValuesType.TYPE_MATRIX3X4: + SetMatrix3x4(key, (matrix3x4_t)value); + break; + default: + throw new InvalidOperationException("Unsupported KeyValuesType."); + } +#pragma warning restore CS8605 // Unboxing a possibly null value. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning restore CS8604 // Possible null reference argument. + } + } + +#region GETTER + public bool GetBool(string key, bool defaultValue = false) => GetValue(key, KeyValuesType.TYPE_BOOL, defaultValue); + + public int GetInt(string key, int defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_INT, defaultValue); + + public uint GetUInt(string key, uint defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_UINT, defaultValue); + + public long GetInt64(string key, long defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_INT64, defaultValue); + + public ulong GetUInt64(string key, ulong defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_UINT64, defaultValue); + + public float GetFloat(string key, float defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_FLOAT, defaultValue); + + public double GetDouble(string key, double defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_DOUBLE, defaultValue); + + public string? GetString(string key, string defaultValue = "") => GetValue(key, KeyValuesType.TYPE_STRING, defaultValue); + + public nint GetPointer(string key, nint defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_POINTER, defaultValue); + + // TODO: use 'CUtlStringToken' once we have it + public uint GetStringToken(string key, uint defaultValue = 0) => GetValue(key, KeyValuesType.TYPE_STRING_TOKEN, defaultValue); + + public CEntityHandle? GetEHandle(string key, CEntityHandle? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_EHANDLE, defaultValue); + + public Color GetColor(string key) => GetValue(key, KeyValuesType.TYPE_COLOR, Color.Empty); + + public Vector? GetVector(string key, Vector? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_VECTOR, defaultValue); + + public Vector2D? GetVector2D(string key, Vector2D? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_VECTOR2D, defaultValue); + + public Vector4D? GetVector4D(string key, Vector4D? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_VECTOR4D, defaultValue); + + public Quaternion? GetQuaternion(string key, Quaternion? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_QUATERNION, defaultValue); + + public QAngle? GetAngle(string key, QAngle? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_QANGLE, defaultValue); + + public matrix3x4_t? GetMatrix3x4(string key, matrix3x4_t? defaultValue = null) => GetValue(key, KeyValuesType.TYPE_MATRIX3X4, defaultValue); +#endregion + +#region SETTER + public void SetBool(string key, bool value) => SetValue(key, KeyValuesType.TYPE_BOOL, value); + + public void SetInt(string key, int value) => SetValue(key, KeyValuesType.TYPE_INT, value); + + public void SetUInt(string key, uint value) => SetValue(key, KeyValuesType.TYPE_UINT, value); + + public void SetInt64(string key, long value) => SetValue(key, KeyValuesType.TYPE_INT64, value); + + public void SetUInt64(string key, ulong value) => SetValue(key, KeyValuesType.TYPE_UINT64, value); + + public void SetFloat(string key, float value) => SetValue(key, KeyValuesType.TYPE_FLOAT, value); + + public void SetDouble(string key, double value) => SetValue(key, KeyValuesType.TYPE_DOUBLE, value); + + public void SetString(string key, string value) => SetValue(key, KeyValuesType.TYPE_STRING, value); + + public void SetPointer(string key, nint value) => SetValue(key, KeyValuesType.TYPE_POINTER, value); + + // TODO: use 'CUtlStringToken' once we have it + public void SetStringToken(string key, uint value) => SetValue(key, KeyValuesType.TYPE_STRING_TOKEN, value); + + public void SetEHandle(string key, CEntityHandle value) => SetValue(key, KeyValuesType.TYPE_EHANDLE, value); + + public void SetColor(string key, Color value) => SetValue(key, KeyValuesType.TYPE_COLOR, value); + + public void SetVector(string key, float x, float y, float z) => SetValue(key, KeyValuesType.TYPE_VECTOR, new Vector(x, y, z)); + + public void SetVector(string key, Vector vector) => SetValue(key, KeyValuesType.TYPE_VECTOR, vector); + + public void SetVector2D(string key, float x, float y) => SetValue(key, KeyValuesType.TYPE_VECTOR2D, new Vector2D(x, y)); + + public void SetVector2D(string key, Vector2D value) => SetValue(key, KeyValuesType.TYPE_VECTOR2D, value); + + public void SetVector4D(string key, float x, float y, float z, float w) => SetValue(key, KeyValuesType.TYPE_VECTOR4D, new Vector4D(x, y, z, w)); + + public void SetVector4D(string key, Vector4D value) => SetValue(key, KeyValuesType.TYPE_VECTOR4D, value); + + public void SetQuaternion(string key, float x, float y, float z, float w) => SetValue(key, KeyValuesType.TYPE_QUATERNION, new Quaternion(x, y, z, w)); + + public void SetQuaternion(string key, Quaternion value) => SetValue(key, KeyValuesType.TYPE_QUATERNION, value); + + public void SetAngle(string key, float pitch, float yaw, float roll) => SetValue(key, KeyValuesType.TYPE_QANGLE, new QAngle(pitch, yaw, roll)); + + public void SetAngle(string key, QAngle angle) => SetValue(key, KeyValuesType.TYPE_QANGLE, angle); + + public void SetMatrix3x4(string key, matrix3x4_t value) => SetValue(key, KeyValuesType.TYPE_MATRIX3X4, value); +#endregion + + public bool HasValue(string key) + { + return NativeAPI.EntityKeyValuesHasValue(Handle, key); + } + + internal void SetValue(string key, KeyValuesType type, T value) + { + List arguments = new List(); + + switch (type) + { + case KeyValuesType.TYPE_EHANDLE: + { + if (value is CEntityHandle entityHandle) + { + arguments.Add(entityHandle.Raw); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_COLOR: + { + if (value is Color color) + { + arguments.Add(color.R); + arguments.Add(color.G); + arguments.Add(color.B); + arguments.Add(color.A); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_VECTOR: + { + if (value is Vector vector) + { + arguments.Add(vector.X); + arguments.Add(vector.Y); + arguments.Add(vector.Z); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_VECTOR2D: + { + if (value is Vector2D vector) + { + arguments.Add(vector.X); + arguments.Add(vector.Y); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_VECTOR4D: + { + if (value is Vector4D vector) + { + arguments.Add(vector.X); + arguments.Add(vector.Y); + arguments.Add(vector.Z); + arguments.Add(vector.W); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_QUATERNION: + { + if (value is Quaternion quaternion) + { + arguments.Add(quaternion.X); + arguments.Add(quaternion.Y); + arguments.Add(quaternion.Z); + arguments.Add(quaternion.W); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_QANGLE: + { + if (value is QAngle angle) + { + arguments.Add(angle.X); + arguments.Add(angle.Y); + arguments.Add(angle.Z); + } else { BadTypeHandler(key, type, value); } + } break; + + case KeyValuesType.TYPE_MATRIX3X4: + { + if (value is matrix3x4_t matrix) + { + arguments.Add(matrix.M00); + arguments.Add(matrix.M01); + arguments.Add(matrix.M02); + arguments.Add(matrix.M03); + + arguments.Add(matrix.M10); + arguments.Add(matrix.M11); + arguments.Add(matrix.M12); + arguments.Add(matrix.M13); + + arguments.Add(matrix.M20); + arguments.Add(matrix.M21); + arguments.Add(matrix.M22); + arguments.Add(matrix.M23); + } else { BadTypeHandler(key, type, value); } + } break; + + default: + arguments.Add((object)value!); + break; + } + + NativeAPI.EntityKeyValuesSetValue(Handle, key, (uint)type, arguments.ToArray()); + } + + internal T? GetValue(string key, KeyValuesType type, T? defaultValue) + { + return NativeAPI.EntityKeyValuesGetValue(Handle, key, (uint)type) ?? defaultValue; + } + + internal void BadTypeHandler(string key, KeyValuesType type, T value) + { + throw new ArgumentException($"Bad type for EntityKeyValues: got '{typeof(T)}' expected: '{type}'"); + } + } +} diff --git a/managed/CounterStrikeSharp.API/Modules/Utils/Quaternion.cs b/managed/CounterStrikeSharp.API/Modules/Utils/Quaternion.cs index 84622c298..62d8dcfb0 100644 --- a/managed/CounterStrikeSharp.API/Modules/Utils/Quaternion.cs +++ b/managed/CounterStrikeSharp.API/Modules/Utils/Quaternion.cs @@ -14,18 +14,38 @@ * along with CounterStrikeSharp. If not, see . * */ -using System; using System.Runtime.CompilerServices; -using CounterStrikeSharp.API.Core; namespace CounterStrikeSharp.API.Modules.Utils { public class Quaternion : NativeObject { + // Not sure who made this one? maybe mark it as 'obsolete' to don't break existing plugins but warn them? + public unsafe ref float Value => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 0); + + public unsafe ref float X => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 0); + + public unsafe ref float Y => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 1); + + public unsafe ref float Z => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 2); + + public unsafe ref float W => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 3); + public Quaternion(IntPtr pointer) : base(pointer) { } - public unsafe ref float Value => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 0); + public Quaternion(float? x = null, float? y = null, float? z = null, float? w = null) : this(NativeAPI.QuaternionNew()) + { + this.X = x ?? 0; + this.Y = y ?? 0; + this.Z = z ?? 0; + this.W = w ?? 0; + } + + public override string ToString() + { + return $"{X:n2} {Y:n2} {Z:n2} {W:n2}"; + } } -} \ No newline at end of file +} diff --git a/managed/CounterStrikeSharp.API/Modules/Utils/Vector.cs b/managed/CounterStrikeSharp.API/Modules/Utils/Vector.cs index 7dfe83990..d7fda7872 100644 --- a/managed/CounterStrikeSharp.API/Modules/Utils/Vector.cs +++ b/managed/CounterStrikeSharp.API/Modules/Utils/Vector.cs @@ -48,7 +48,9 @@ public Vector(float? x = null, float? y = null, float? z = null) : this(NativeAP } public unsafe ref float X => ref Unsafe.Add(ref *(float*)Handle, 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); /// diff --git a/managed/CounterStrikeSharp.API/Modules/Utils/Vector2D.cs b/managed/CounterStrikeSharp.API/Modules/Utils/Vector2D.cs index c6047451c..52178228c 100644 --- a/managed/CounterStrikeSharp.API/Modules/Utils/Vector2D.cs +++ b/managed/CounterStrikeSharp.API/Modules/Utils/Vector2D.cs @@ -14,19 +14,29 @@ * along with CounterStrikeSharp. If not, see . * */ -using System; using System.Runtime.CompilerServices; -using CounterStrikeSharp.API.Core; namespace CounterStrikeSharp.API.Modules.Utils { public class Vector2D : NativeObject { + public unsafe ref float X => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 0); + + public unsafe ref float Y => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 1); + public Vector2D(IntPtr pointer) : base(pointer) { } - 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 Vector2D(float? x = null, float? y = null) : this(NativeAPI.Vector2dNew()) + { + this.X = x ?? 0; + this.Y = y ?? 0; + } + + public override string ToString() + { + return $"{X:n2} {Y:n2}"; + } } -} \ No newline at end of file +} diff --git a/managed/CounterStrikeSharp.API/Modules/Utils/Vector4D.cs b/managed/CounterStrikeSharp.API/Modules/Utils/Vector4D.cs index 758719773..c6ce79d06 100644 --- a/managed/CounterStrikeSharp.API/Modules/Utils/Vector4D.cs +++ b/managed/CounterStrikeSharp.API/Modules/Utils/Vector4D.cs @@ -14,21 +14,35 @@ * along with CounterStrikeSharp. If not, see . * */ -using System; using System.Runtime.CompilerServices; -using CounterStrikeSharp.API.Core; namespace CounterStrikeSharp.API.Modules.Utils { public class Vector4D : NativeObject { + public unsafe ref float X => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 0); + + public unsafe ref float Y => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 1); + + public unsafe ref float Z => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 2); + + public unsafe ref float W => ref Unsafe.Add(ref *(float*)Handle.ToPointer(), 3); + public Vector4D(IntPtr pointer) : base(pointer) { } - 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 unsafe ref float W => ref Unsafe.Add(ref *(float*)Handle, 3); + public Vector4D(float? x = null, float? y = null, float? z = null, float? w = null) : this(NativeAPI.Vector4dNew()) + { + this.X = x ?? 0; + this.Y = y ?? 0; + this.Z = z ?? 0; + this.W = w ?? 0; + } + + public override string ToString() + { + return $"{X:n2} {Y:n2} {Z:n2} {W:n2}"; + } } -} \ No newline at end of file +} diff --git a/managed/CounterStrikeSharp.API/Modules/Utils/matrix3x4_t.cs b/managed/CounterStrikeSharp.API/Modules/Utils/matrix3x4_t.cs index 9b40c5be3..caec40f06 100644 --- a/managed/CounterStrikeSharp.API/Modules/Utils/matrix3x4_t.cs +++ b/managed/CounterStrikeSharp.API/Modules/Utils/matrix3x4_t.cs @@ -1,13 +1,80 @@ -using System; +/* + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CounterStrikeSharp is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CounterStrikeSharp. If not, see . * + */ + using System.Runtime.CompilerServices; namespace CounterStrikeSharp.API.Modules.Utils; public partial class matrix3x4_t : NativeObject -{ +{ + public unsafe ref float this[int row, int column] => ref Unsafe.Add(ref *(float*)Handle, row * 4 + column); + + public float M00 => this[0, 0]; + + public float M01 => this[0, 1]; + + public float M02 => this[0, 2]; + + public float M03 => this[0, 3]; + + public float M10 => this[1, 0]; + + public float M11 => this[1, 1]; + + public float M12 => this[1, 2]; + + public float M13 => this[1, 3]; + + public float M20 => this[2, 0]; + + public float M21 => this[2, 1]; + + public float M22 => this[2, 2]; + + public float M23 => this[2, 3]; + public matrix3x4_t(IntPtr pointer) : base(pointer) { + } + + public matrix3x4_t(float? m00 = null, float? m01 = null, float? m02 = null, float? m03 = null, + float? m10 = null, float? m11 = null, float? m12 = null, float? m13 = null, + float? m20 = null, float? m21 = null, float? m22 = null, float? m23 = null) : this(NativeAPI.Matrix3x4New()) + { + this[0, 0] = m00 ?? 0; + this[0, 1] = m01 ?? 0; + this[0, 2] = m02 ?? 0; + this[0, 3] = m03 ?? 0; + + this[1, 0] = m10 ?? 0; + this[1, 1] = m11 ?? 0; + this[1, 2] = m12 ?? 0; + this[1, 3] = m13 ?? 0; + + this[2, 0] = m20 ?? 0; + this[2, 1] = m21 ?? 0; + this[2, 2] = m22 ?? 0; + this[2, 3] = m23 ?? 0; + } + + public override string ToString() + { + return $"{this[0, 0]:n2} {this[0, 1]:n2} {this[0, 2]:n2} {this[0, 3]:n2}\n" + + $"{this[1, 0]:n2} {this[1, 1]:n2} {this[1, 2]:n2} {this[1, 3]:n2}\n" + + $"{this[2, 0]:n2} {this[2, 1]:n2} {this[2, 2]:n2} {this[2, 3]:n2}"; } - - public unsafe ref float this[int row, int column] => ref Unsafe.Add(ref *(float*)Handle, row * 4 + column); -} \ No newline at end of file + +} diff --git a/src/core/managers/entity_manager.cpp b/src/core/managers/entity_manager.cpp index b1e9cfac4..03a6ed2c1 100644 --- a/src/core/managers/entity_manager.cpp +++ b/src/core/managers/entity_manager.cpp @@ -72,6 +72,15 @@ void EntityManager::OnAllInitialized() CSSHARP_CORE_CRITICAL("Failed to find signature for \'CEntitySystem_AddEntityIOEvent\'"); } + CBaseEntity_DispatchSpawn = (decltype(CBaseEntity_DispatchSpawn))( + (modules::server->FindSignature(globals::gameConfig->GetSignature("CBaseEntity_DispatchSpawn")))); + + if (!CBaseEntity_DispatchSpawn) + { + CSSHARP_CORE_CRITICAL("Failed to find signature for \'CBaseEntity_DispatchSpawn\'"); + return; + } + auto m_hook = funchook_create(); funchook_prepare(m_hook, (void**)&m_pFireOutputInternal, (void*)&DetourFireOutputInternal); funchook_install(m_hook, 0); diff --git a/src/core/managers/entity_manager.h b/src/core/managers/entity_manager.h index 84d3ae365..62e85ca35 100644 --- a/src/core/managers/entity_manager.h +++ b/src/core/managers/entity_manager.h @@ -126,6 +126,8 @@ static void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstan static FireOutputInternal m_pFireOutputInternal = nullptr; +inline void (*CBaseEntity_DispatchSpawn)(void* pEntity, CEntityKeyValues* pKeyValues); + // Do it in here because i didn't found a good place to do this inline void (*CEntityInstance_AcceptInput)(CEntityInstance* pThis, const char* pInputName, CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value, int nOutputID); diff --git a/src/scripting/natives/natives_entities.cpp b/src/scripting/natives/natives_entities.cpp index b01ae74ce..7aab34f99 100644 --- a/src/scripting/natives/natives_entities.cpp +++ b/src/scripting/natives/natives_entities.cpp @@ -15,6 +15,7 @@ */ #include +#include "entitykeyvalues.h" #include #include @@ -27,6 +28,27 @@ #include "scripting/script_engine.h" namespace counterstrikesharp { +enum KeyValuesType_t : unsigned int +{ + TYPE_BOOL, + TYPE_INT, + TYPE_UINT, + TYPE_INT64, + TYPE_UINT64, + TYPE_FLOAT, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_POINTER, + TYPE_STRING_TOKEN, + TYPE_EHANDLE, + TYPE_COLOR, + TYPE_VECTOR, + TYPE_VECTOR2D, + TYPE_VECTOR4D, + TYPE_QUATERNION, + TYPE_QANGLE, + TYPE_MATRIX3X4 +}; CEntityInstance* GetEntityFromIndex(ScriptContext& script_context) { @@ -256,6 +278,272 @@ void AddEntityIOEvent(ScriptContext& script_context) CEntitySystem_AddEntityIOEvent(GameEntitySystem(), pTarget, pInputName, pActivator, pCaller, &_value, delay, outputID); } +void DispatchSpawn(ScriptContext& scriptContext) +{ + auto entity = scriptContext.GetArgument(0); + auto keyValues = scriptContext.GetArgument(1); + CBaseEntity_DispatchSpawn(entity, keyValues); +} + +CEntityKeyValues* EntityKeyValuesNew(ScriptContext& script_context) +{ + return new CEntityKeyValues(); +} + +bool EntityKeyValuesHasValue(ScriptContext& script_context) +{ + CEntityKeyValues* keyValues = script_context.GetArgument(0); + const char* key = script_context.GetArgument(1); + return keyValues->HasValue(key); +} + +void EntityKeyValuesSetValue(ScriptContext& script_context) +{ + CEntityKeyValues* keyValues = script_context.GetArgument(0); + const char* key = script_context.GetArgument(1); + KeyValuesType_t type = script_context.GetArgument(2); + + int offset = 3; + + switch (type) { + case counterstrikesharp::TYPE_BOOL: + keyValues->SetBool(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_INT: + keyValues->SetInt(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_UINT: + keyValues->SetUint(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_INT64: + keyValues->SetInt64(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_UINT64: + keyValues->SetUint64(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_FLOAT: + keyValues->SetFloat(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_DOUBLE: + keyValues->SetDouble(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_STRING: + keyValues->SetString(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_POINTER: + keyValues->SetPtr(key, script_context.GetArgument(offset)); + break; + + case counterstrikesharp::TYPE_STRING_TOKEN: + keyValues->SetStringToken(key, CUtlStringToken(script_context.GetArgument(offset))); + break; + + case counterstrikesharp::TYPE_EHANDLE: + keyValues->SetEHandle(key, CEntityHandle(script_context.GetArgument(offset))); + break; + + case counterstrikesharp::TYPE_COLOR: + { + char r = script_context.GetArgument(offset); + char g = script_context.GetArgument(offset + 1); + char b = script_context.GetArgument(offset + 2); + char a = script_context.GetArgument(offset + 3); + keyValues->SetColor(key, Color(r, g, b, a)); + break; + } + + case counterstrikesharp::TYPE_VECTOR: + { + float x = script_context.GetArgument(offset); + float y = script_context.GetArgument(offset + 1); + float z = script_context.GetArgument(offset + 2); + keyValues->SetVector(key, Vector(x, y, z)); + break; + } + + case counterstrikesharp::TYPE_VECTOR2D: + { + float x = script_context.GetArgument(offset); + float y = script_context.GetArgument(offset + 1); + keyValues->SetVector2D(key, Vector2D(x, y)); + break; + } + + case counterstrikesharp::TYPE_VECTOR4D: + { + float x = script_context.GetArgument(offset); + float y = script_context.GetArgument(offset + 1); + float z = script_context.GetArgument(offset + 2); + float w = script_context.GetArgument(offset + 3); + keyValues->SetVector4D(key, Vector4D(x, y, z, w)); + break; + } + + case counterstrikesharp::TYPE_QUATERNION: + { + float x = script_context.GetArgument(offset); + float y = script_context.GetArgument(offset + 1); + float z = script_context.GetArgument(offset + 2); + float w = script_context.GetArgument(offset + 3); + keyValues->SetQuaternion(key, Quaternion(x, y, z, w)); + break; + } + + case counterstrikesharp::TYPE_QANGLE: + { + float x = script_context.GetArgument(offset); + float y = script_context.GetArgument(offset + 1); + float z = script_context.GetArgument(offset + 2); + keyValues->SetQAngle(key, QAngle(x, y, z)); + break; + } + + case counterstrikesharp::TYPE_MATRIX3X4: + { + float m11 = script_context.GetArgument(offset); + float m12 = script_context.GetArgument(offset + 1); + float m13 = script_context.GetArgument(offset + 2); + float m14 = script_context.GetArgument(offset + 3); + + float m21 = script_context.GetArgument(offset + 4); + float m22 = script_context.GetArgument(offset + 5); + float m23 = script_context.GetArgument(offset + 6); + float m24 = script_context.GetArgument(offset + 7); + + float m31 = script_context.GetArgument(offset + 8); + float m32 = script_context.GetArgument(offset + 9); + float m33 = script_context.GetArgument(offset + 10); + float m34 = script_context.GetArgument(offset + 11); + + keyValues->SetMatrix3x4(key, matrix3x4_t(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34)); + break; + } + + default: + script_context.ThrowNativeError("Invalid KeyValues Type! ({})", type); + break; + } +} + +void EntityKeyValuesGetValue(ScriptContext& script_context) +{ + CEntityKeyValues* keyValues = script_context.GetArgument(0); + const char* key = script_context.GetArgument(1); + KeyValuesType_t type = script_context.GetArgument(2); + + switch (type) { + case counterstrikesharp::TYPE_BOOL: + { + script_context.SetResult(keyValues->GetBool(key)); + } break; + + case counterstrikesharp::TYPE_INT: + { + script_context.SetResult(keyValues->GetInt(key)); + } break; + + case counterstrikesharp::TYPE_UINT: + { + script_context.SetResult(keyValues->GetUint(key)); + } break; + + case counterstrikesharp::TYPE_INT64: + { + script_context.SetResult(keyValues->GetInt64(key)); + } break; + + case counterstrikesharp::TYPE_UINT64: + { + script_context.SetResult(keyValues->GetUint64(key)); + } break; + + case counterstrikesharp::TYPE_FLOAT: + { + script_context.SetResult(keyValues->GetFloat(key)); + } break; + + case counterstrikesharp::TYPE_DOUBLE: + { + script_context.SetResult(keyValues->GetDouble(key)); + } break; + + case counterstrikesharp::TYPE_STRING: + { + script_context.SetResult(keyValues->GetString(key)); + } break; + + case counterstrikesharp::TYPE_POINTER: + { + script_context.SetResult(keyValues->GetPtr(key)); + } break; + + case counterstrikesharp::TYPE_STRING_TOKEN: + { + script_context.SetResult(keyValues->GetStringToken(key).GetHashCode()); + } break; + + case counterstrikesharp::TYPE_EHANDLE: + { + script_context.SetResult(keyValues->GetEHandle(key)); + } break; + + case counterstrikesharp::TYPE_COLOR: + { + script_context.SetResult(new Color(keyValues->GetColor(key))); + break; + } + + case counterstrikesharp::TYPE_VECTOR: + { + script_context.SetResult(new Vector(keyValues->GetVector(key))); + break; + } + + case counterstrikesharp::TYPE_VECTOR2D: + { + script_context.SetResult(new Vector2D(keyValues->GetVector2D(key))); + break; + } + + case counterstrikesharp::TYPE_VECTOR4D: + { + script_context.SetResult(new Vector4D(keyValues->GetVector4D(key))); + break; + } + + case counterstrikesharp::TYPE_QUATERNION: + { + script_context.SetResult(new Quaternion(keyValues->GetQuaternion(key))); + break; + } + + case counterstrikesharp::TYPE_QANGLE: + { + script_context.SetResult(new QAngle(keyValues->GetQAngle(key))); + break; + } + + case counterstrikesharp::TYPE_MATRIX3X4: + { + script_context.SetResult(new matrix3x4_t(keyValues->GetMatrix3x4(key))); + break; + } + + default: + { + script_context.ThrowNativeError("Invalid KeyValues Type! ({})", type); + } break; + } +} + REGISTER_NATIVES(entities, { ScriptEngine::RegisterNativeHandler("GET_ENTITY_FROM_INDEX", GetEntityFromIndex); ScriptEngine::RegisterNativeHandler("GET_USERID_FROM_INDEX", GetUserIdFromIndex); @@ -273,5 +561,10 @@ REGISTER_NATIVES(entities, { ScriptEngine::RegisterNativeHandler("UNHOOK_ENTITY_OUTPUT", UnhookEntityOutput); ScriptEngine::RegisterNativeHandler("ACCEPT_INPUT", AcceptInput); ScriptEngine::RegisterNativeHandler("ADD_ENTITY_IO_EVENT", AddEntityIOEvent); + ScriptEngine::RegisterNativeHandler("DISPATCH_SPAWN", DispatchSpawn); + ScriptEngine::RegisterNativeHandler("ENTITY_KEY_VALUES_NEW", EntityKeyValuesNew); + ScriptEngine::RegisterNativeHandler("ENTITY_KEY_VALUES_GET_VALUE", EntityKeyValuesGetValue); + ScriptEngine::RegisterNativeHandler("ENTITY_KEY_VALUES_SET_VALUE", EntityKeyValuesSetValue); + ScriptEngine::RegisterNativeHandler("ENTITY_KEY_VALUES_HAS_VALUE", EntityKeyValuesHasValue); }) } // namespace counterstrikesharp diff --git a/src/scripting/natives/natives_entities.yaml b/src/scripting/natives/natives_entities.yaml index 07b40fbba..1c045ac80 100644 --- a/src/scripting/natives/natives_entities.yaml +++ b/src/scripting/natives/natives_entities.yaml @@ -14,3 +14,8 @@ HOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func, mode:Hoo UNHOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func, mode:HookMode -> void ACCEPT_INPUT: pThis:pointer, inputName:string, activator:pointer, caller:pointer, value:string, outputID:int -> void ADD_ENTITY_IO_EVENT: pTarget:pointer, inputName:string, activator:pointer, caller:pointer, value:string, delay:float, outputID:int -> void +DISPATCH_SPAWN: entity:pointer, keyvalues:pointer -> void +ENTITY_KEY_VALUES_NEW: -> pointer +ENTITY_KEY_VALUES_GET_VALUE: keyvalues:pointer, key:string, type:uint -> any +ENTITY_KEY_VALUES_SET_VALUE: keyvalues:pointer, key:string, type:uint, arguments:object[] -> void +ENTITY_KEY_VALUES_HAS_VALUE: keyvalues:pointer, key:string -> bool \ No newline at end of file diff --git a/src/scripting/natives/natives_vector.cpp b/src/scripting/natives/natives_vector.cpp index 4fca493a8..c7b68b89e 100644 --- a/src/scripting/natives/natives_vector.cpp +++ b/src/scripting/natives/natives_vector.cpp @@ -45,6 +45,26 @@ Vector* VectorNew(ScriptContext& script_context) return vec; } +Vector2D* Vector2DNew(ScriptContext& script_context) +{ + return new Vector2D(); +} + +Vector4D* Vector4DNew(ScriptContext& script_context) +{ + return new Vector4D(); +} + +matrix3x4_t* Matrix3x4New(ScriptContext& script_context) +{ + return new matrix3x4_t(); +} + +Quaternion* QuaternionNew(ScriptContext& script_context) +{ + return new Quaternion(); +} + // TODO: These need to be cleared out somehow std::vector managed_angles; @@ -83,6 +103,10 @@ void NativeAngleVectors(ScriptContext& script_context) REGISTER_NATIVES(vector, { ScriptEngine::RegisterNativeHandler("VECTOR_NEW", VectorNew); + ScriptEngine::RegisterNativeHandler("VECTOR2D_NEW", Vector2DNew); + ScriptEngine::RegisterNativeHandler("VECTOR4D_NEW", Vector4DNew); + ScriptEngine::RegisterNativeHandler("MATRIX3X4_NEW", Matrix3x4New); + ScriptEngine::RegisterNativeHandler("QUATERNION_NEW", QuaternionNew); ScriptEngine::RegisterNativeHandler("ANGLE_NEW", AngleNew); ScriptEngine::RegisterNativeHandler("VECTOR_SET_X", VectorSetX); diff --git a/src/scripting/natives/natives_vector.yaml b/src/scripting/natives/natives_vector.yaml index e594c773b..d315902cb 100644 --- a/src/scripting/natives/natives_vector.yaml +++ b/src/scripting/natives/natives_vector.yaml @@ -1,4 +1,8 @@ VECTOR_NEW: -> pointer +VECTOR2D_NEW: -> pointer +VECTOR4D_NEW: -> pointer +MATRIX3X4_NEW: -> pointer +QUATERNION_NEW: -> pointer ANGLE_NEW: -> pointer VECTOR_GET_X: vector:pointer -> float VECTOR_GET_Y: vector:pointer -> float