Compare commits

...

7 Commits
v1.0.68 ... v73

Author SHA1 Message Date
Roflmuffin
8d1891a3a8 Merge branch 'main' of github.com:roflmuffin/CounterStrikeSharp 2023-11-26 13:19:54 +10:00
Roflmuffin
6bc43444f7 feat: add trigger touch start and end hooks 2023-11-26 13:19:40 +10:00
miguno
f0c7869f4a Check if userid is valid before accessing its fields, and explain why (#133) 2023-11-26 10:03:20 +10:00
Robert
3e38ed3c77 feat: Added ability to GiveNamedItem using the new CsItem Enum (#105) 2023-11-25 10:40:49 +10:00
Roflmuffin
7e9e7c6665 fix: wrong chat colors 2023-11-24 21:21:03 +10:00
Roflmuffin
9a018f295b feat: add player pawn post think signature 2023-11-24 21:04:22 +10:00
Michael Wilson
8b725d435f Dynamic Hooks (#78) 2023-11-24 19:59:47 +10:00
31 changed files with 1695 additions and 270 deletions

6
.gitmodules vendored
View File

@@ -17,3 +17,9 @@
[submodule "libraries/GameTracking-CS2"]
path = libraries/GameTracking-CS2
url = https://github.com/SteamDatabase/GameTracking-CS2
[submodule "libraries/DynoHook"]
path = libraries/DynoHook
url = git@github.com:qubka/DynoHook.git
[submodule "libraries/asmjit"]
path = libraries/asmjit
url = git@github.com:asmjit/asmjit.git

View File

@@ -8,7 +8,9 @@ include("makefiles/shared.cmake")
add_subdirectory(libraries/spdlog)
add_subdirectory(libraries/dyncall)
add_subdirectory(libraries/funchook)
add_subdirectory(libraries/DynoHook)
set_property(TARGET dynohook PROPERTY DYNO_ARCH_X86 64)
set_property(TARGET funchook-static PROPERTY POSITION_INDEPENDENT_CODE ON)
SET(SOURCE_FILES
@@ -81,6 +83,7 @@ SET(SOURCE_FILES
src/core/managers/server_manager.h
src/scripting/natives/natives_server.cpp
libraries/nlohmann/json.hpp
src/scripting/natives/natives_dynamichooks.cpp
)

View File

@@ -39,6 +39,13 @@
"linux": "\\x8B\\x8F\\x40\\x0E\\x00\\x00\\x83\\xF9\\xFF\\x0F\\x84\\xD9\\x01"
}
},
"CCSPlayerPawnBase_PostThink": {
"signatures": {
"library": "server",
"windows": "\\x48\\x8B\\xC4\\x48\\x89\\x48\\x08\\x55\\x53\\x56\\x57\\x41\\x56\\x48\\x8D\\xA8\\xD8\\xFE\\xFF\\xFF",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x49\\x89\\xFF\\x41\\x56\\x41\\x55\\x41\\x54\\x53\\x48\\x81\\xEC\\x2A\\x2A\\x2A\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x4C"
}
},
"GiveNamedItem": {
"signatures": {
"library": "server",
@@ -125,6 +132,27 @@
"linux": 147
}
},
"CBaseEntity_TakeDamageOld": {
"signatures": {
"library": "server",
"windows": "\\x40\\x56\\x57\\x48\\x83\\xEC\\x58\\x48\\x8B\\x41\\x10",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x83\\xEC\\x38\\x4C\\x8D\\x2D\\x2A\\x2A\\x2A\\x2A\\x49\\x8B\\x7D\\x00\\x48\\x85\\xFF\\x0F\\x84\\x2A\\x2A\\x2A\\x2A"
}
},
"CBaseTrigger_StartTouch": {
"signatures": {
"library": "server",
"windows": "\\x41\\x56\\x41\\x57\\x48\\x83\\xEC\\x58\\x48\\x8B\\x01",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x49\\x89\\xFD\\x41\\x54\\x53\\xBB"
}
},
"CBaseTrigger_EndTouch": {
"signatures": {
"library": "server",
"windows": "\\x40\\x53\\x57\\x41\\x55\\x48\\x83\\xEC\\x40",
"linux": "\\x55\\xBA\\xFF\\xFF\\xFF\\xFF\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x49"
}
},
"GameEntitySystem": {
"offsets": {
"windows": 88,

View File

@@ -17,8 +17,13 @@ The first parameter type must be a subclass of the `GameEvent` class. The names
[GameEventHandler]
public HookResult OnPlayerConnect(EventPlayerConnect @event, GameEventInfo info)
{
// Userid will give you a reference to a CCSPlayerController class
Logger.LogInformation("Player {Name} has connected!", @event.Userid.PlayerName);
// Userid will give you a reference to a CCSPlayerController class.
// Before accessing any of its fields, you must first check if the Userid
// handle is actually valid, otherwise you may run into runtime exceptions.
// See the documentation section on Referencing Players for details.
if (@event.Userid.IsValid) {
Logger.LogInformation("Player {Name} has connected!", @event.Userid.PlayerName);
}
return HookResult.Continue;
}

1
libraries/DynoHook Submodule

Submodule libraries/DynoHook added at d7f8ebb059

1
libraries/asmjit Submodule

Submodule libraries/asmjit added at 0dd16b0a98

View File

@@ -16,14 +16,16 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -Wno-reorder")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics -v -fvisibility=default")
set(COUNTER_STRIKE_SHARP_LINK_LIBRARIES
${SOURCESDK_LIB}/linux64/libtier0.so
${SOURCESDK_LIB}/linux64/tier1.a
${SOURCESDK_LIB}/linux64/interfaces.a
${SOURCESDK_LIB}/linux64/mathlib.a
spdlog
dynload_s
dyncall_s
distorm
funchook-static
SET(
COUNTER_STRIKE_SHARP_LINK_LIBRARIES
${SOURCESDK_LIB}/linux64/libtier0.so
${SOURCESDK_LIB}/linux64/tier1.a
${SOURCESDK_LIB}/linux64/interfaces.a
${SOURCESDK_LIB}/linux64/mathlib.a
spdlog
dynload_s
dyncall_s
distorm
funchook-static
dynohook
)

View File

@@ -14,6 +14,8 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
# TODO: Use C++20 instead.
set(CMAKE_CXX_STANDARD 17)
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
Set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
set(CMAKE_STATIC_LIBRARY_PREFIX "")
set(SOURCESDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2)
@@ -45,6 +47,7 @@ include_directories(
libraries/spdlog/include
libraries/tl
libraries/funchook/include
libraries/DynoHook/src
libraries
)

View File

@@ -17,4 +17,5 @@ set(COUNTER_STRIKE_SHARP_LINK_LIBRARIES
dyncall_s
distorm
funchook-static
dynohook
)

View File

@@ -157,6 +157,56 @@ namespace CounterStrikeSharp.API.Core
}
}
public static T DynamicHookGetReturn<T>(IntPtr hook, int datatype){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(hook);
ScriptContext.GlobalScriptContext.Push(datatype);
ScriptContext.GlobalScriptContext.SetIdentifier(0x4F5B80D0);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (T)ScriptContext.GlobalScriptContext.GetResult(typeof(T));
}
}
public static void DynamicHookSetReturn<T>(IntPtr hook, int datatype, T value){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(hook);
ScriptContext.GlobalScriptContext.Push(datatype);
ScriptContext.GlobalScriptContext.Push(value);
ScriptContext.GlobalScriptContext.SetIdentifier(0xDB297E44);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static T DynamicHookGetParam<T>(IntPtr hook, int datatype, int paramindex){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(hook);
ScriptContext.GlobalScriptContext.Push(datatype);
ScriptContext.GlobalScriptContext.Push(paramindex);
ScriptContext.GlobalScriptContext.SetIdentifier(0x5F5ABDD5);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (T)ScriptContext.GlobalScriptContext.GetResult(typeof(T));
}
}
public static void DynamicHookSetParam<T>(IntPtr hook, int datatype, int paramindex, T value){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(hook);
ScriptContext.GlobalScriptContext.Push(datatype);
ScriptContext.GlobalScriptContext.Push(paramindex);
ScriptContext.GlobalScriptContext.Push(value);
ScriptContext.GlobalScriptContext.SetIdentifier(0xA96CFBC1);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static string GetMapName(){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -803,6 +853,30 @@ namespace CounterStrikeSharp.API.Core
}
}
public static void HookFunction(IntPtr function, InputArgument hook, bool post){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(function);
ScriptContext.GlobalScriptContext.Push((InputArgument)hook);
ScriptContext.GlobalScriptContext.Push(post);
ScriptContext.GlobalScriptContext.SetIdentifier(0xA6C8BA9B);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static void UnhookFunction(IntPtr function, InputArgument hook, bool post){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(function);
ScriptContext.GlobalScriptContext.Push((InputArgument)hook);
ScriptContext.GlobalScriptContext.Push(post);
ScriptContext.GlobalScriptContext.SetIdentifier(0x2051B00);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static T ExecuteVirtualFunction<T>(IntPtr function, object[] arguments){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();

View File

@@ -1,4 +1,5 @@
using System;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
@@ -24,6 +25,17 @@ public partial class CCSPlayerController
return VirtualFunctions.GiveNamedItem(PlayerPawn.Value.ItemServices.Handle, item, 0, 0, 0, 0);
}
public IntPtr GiveNamedItem(CsItem item)
{
string? itemString = EnumUtils.GetEnumMemberAttributeValue(item);
if (string.IsNullOrWhiteSpace(itemString))
{
return IntPtr.Zero;
}
return this.GiveNamedItem(itemString);
}
public void PrintToConsole(string message)
{
NativeAPI.PrintToConsole((int)EntityIndex.Value.Value, $"{message}\n\0");

View File

@@ -0,0 +1,8 @@
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Core;
public partial class CPlayerPawnComponent
{
public PointerTo<CBasePlayerPawn> Pawn => new PointerTo<CBasePlayerPawn>(this.Handle + 0x30);
}

View File

@@ -19806,6 +19806,63 @@ public partial class CTablet : CCSWeaponBase
}
public partial class CTakeDamageInfo : NativeObject
{
public CTakeDamageInfo (IntPtr pointer) : base(pointer) {}
// m_vecDamageForce
public Vector DamageForce => Schema.GetDeclaredClass<Vector>(this.Handle, "CTakeDamageInfo", "m_vecDamageForce");
// m_vecDamagePosition
public Vector DamagePosition => Schema.GetDeclaredClass<Vector>(this.Handle, "CTakeDamageInfo", "m_vecDamagePosition");
// m_vecReportedPosition
public Vector ReportedPosition => Schema.GetDeclaredClass<Vector>(this.Handle, "CTakeDamageInfo", "m_vecReportedPosition");
// m_vecDamageDirection
public Vector DamageDirection => Schema.GetDeclaredClass<Vector>(this.Handle, "CTakeDamageInfo", "m_vecDamageDirection");
// m_hInflictor
public CHandle<CBaseEntity> Inflictor => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CTakeDamageInfo", "m_hInflictor");
// m_hAttacker
public CHandle<CBaseEntity> Attacker => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CTakeDamageInfo", "m_hAttacker");
// m_hAbility
public CHandle<CBaseEntity> Ability => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CTakeDamageInfo", "m_hAbility");
// m_flDamage
public ref float Damage => ref Schema.GetRef<float>(this.Handle, "CTakeDamageInfo", "m_flDamage");
// m_bitsDamageType
public ref Int32 BitsDamageType => ref Schema.GetRef<Int32>(this.Handle, "CTakeDamageInfo", "m_bitsDamageType");
// m_iDamageCustom
public ref Int32 DamageCustom => ref Schema.GetRef<Int32>(this.Handle, "CTakeDamageInfo", "m_iDamageCustom");
// m_iAmmoType
public ref byte AmmoType => ref Schema.GetRef<byte>(this.Handle, "CTakeDamageInfo", "m_iAmmoType");
// m_flOriginalDamage
public ref float OriginalDamage => ref Schema.GetRef<float>(this.Handle, "CTakeDamageInfo", "m_flOriginalDamage");
// m_bShouldBleed
public ref bool ShouldBleed => ref Schema.GetRef<bool>(this.Handle, "CTakeDamageInfo", "m_bShouldBleed");
// m_bShouldSpark
public ref bool ShouldSpark => ref Schema.GetRef<bool>(this.Handle, "CTakeDamageInfo", "m_bShouldSpark");
// m_nDamageFlags
public ref TakeDamageFlags_t DamageFlags => ref Schema.GetRef<TakeDamageFlags_t>(this.Handle, "CTakeDamageInfo", "m_nDamageFlags");
// m_nNumObjectsPenetrated
public ref Int32 NumObjectsPenetrated => ref Schema.GetRef<Int32>(this.Handle, "CTakeDamageInfo", "m_nNumObjectsPenetrated");
// m_bInTakeDamageFlow
public ref bool InTakeDamageFlow => ref Schema.GetRef<bool>(this.Handle, "CTakeDamageInfo", "m_bInTakeDamageFlow");
}
public partial class CTankTargetChange : CPointEntity
{
public CTankTargetChange (IntPtr pointer) : base(pointer) {}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace CounterStrikeSharp.API.Modules.Entities.Constants
{
public enum CsItem
{
//-----------------------------------------
//EQUIPMENT
//-----------------------------------------
[EnumMember(Value = "item_kevlar")]
Kevlar = 000,
[EnumMember(Value = "item_assaultsuit")]
AssaultSuit = 001,
KevlarHelmet = AssaultSuit,
[EnumMember(Value = "weapon_taser")]
Taser = 002,
Zeus = Taser,
[EnumMember(Value = "weapon_snowball")]
Snowball = 003,
[EnumMember(Value = "weapon_shield")]
Shield = 004,
[EnumMember(Value = "weapon_c4")]
C4 = 005,
Bomb = C4,
[EnumMember(Value = "weapon_healthshot")]
Healthshot = 006,
[EnumMember(Value = "weapon_breachcharge")]
BreachCharge = 007,
[EnumMember(Value = "weapon_tablet")]
Tablet = 008,
[EnumMember(Value = "weapon_bumpmine")]
Bumpmine = 009,
//-----------------------------------------
//GRENADES
//-----------------------------------------
[EnumMember(Value = "weapon_smokegrenade")]
Smoke = 100,
SmokeGrenade = Smoke,
[EnumMember(Value = "weapon_flashbang")]
Flashbang = 101,
FlashbangGrenade = Flashbang,
[EnumMember(Value = "weapon_hegrenade")]
HighExplosive = 102,
HE = HighExplosive,
HighExplosiveGrenade = HighExplosive,
HEGrenade = HighExplosive,
[EnumMember(Value = "weapon_molotov")]
Molotov = 103,
[EnumMember(Value = "weapon_incgrenade")]
Incendiary = 104,
IncGrenade = Incendiary,
IncendiaryGrenade = Incendiary,
[EnumMember(Value = "weapon_decoy")]
Decoy = 105,
DecoyGrenade = Decoy,
//XRay-Grenade
[EnumMember(Value = "weapon_tagrenade")]
TacticalAwareness = 106,
TAGrenade = TacticalAwareness,
XRayGrenade = TacticalAwareness,
//Dangerzone: Better HighExplosive
[EnumMember(Value = "weapon_frag")]
Frag = 107,
FragGrenade = Frag,
//Dangerzone: Better Molotov
[EnumMember(Value = "weapon_firebomb")]
Firebomb = 108,
//Dangerzone: Decoy but Footsteps instead of gun sounds
[EnumMember(Value = "weapon_diversion")]
Diversion = 109,
//-----------------------------------------
//PISTOLS
//-----------------------------------------
[EnumMember(Value = "weapon_deagle")]
Deagle = 200,
DesertEagle = Deagle,
[EnumMember(Value = "weapon_glock")]
Glock = 201,
Glock18 = Glock,
[EnumMember(Value = "weapon_usp_silencer")]
USPS = 202,
USP = USPS,
[EnumMember(Value = "weapon_hkp2000")]
HKP2000 = 203,
P2000 = HKP2000,
P2K = HKP2000,
[EnumMember(Value = "weapon_elite")]
Elite = 204,
DualBerettas = Elite,
Dualies = Elite,
[EnumMember(Value = "weapon_tec9")]
Tec9 = 205,
[EnumMember(Value = "weapon_p250")]
P250 = 206,
[EnumMember(Value = "weapon_cz75a")]
CZ = 207,
CZ75 = CZ,
[EnumMember(Value = "weapon_fiveseven")]
FiveSeven = 208,
[EnumMember(Value = "weapon_revolver")]
Revolver = 209,
R8 = Revolver,
//-----------------------------------------
//MID-TIER
//-----------------------------------------
[EnumMember(Value = "weapon_mac10")]
Mac10 = 300,
[EnumMember(Value = "weapon_mp9")]
MP9 = 301,
[EnumMember(Value = "weapon_mp7")]
MP7 = 302,
[EnumMember(Value = "weapon_p90")]
P90 = 303,
[EnumMember(Value = "weapon_mp5sd")]
MP5SD = 304,
MP5 = MP5SD,
[EnumMember(Value = "weapon_bizon")]
Bizon = 305,
PPBizon = Bizon,
[EnumMember(Value = "weapon_ump45")]
UMP45 = 306,
UMP = UMP45,
[EnumMember(Value = "weapon_xm1014")]
XM1014 = 307,
[EnumMember(Value = "weapon_nova")]
Nova = 308,
[EnumMember(Value = "weapon_mag7")]
MAG7 = 309,
[EnumMember(Value = "weapon_sawedoff")]
SawedOff = 310,
[EnumMember(Value = "weapon_m249")]
M249 = 311,
[EnumMember(Value = "weapon_negev")]
Negev = 312,
//-----------------------------------------
//RIFLES
//-----------------------------------------
[EnumMember(Value = "weapon_ak47")]
AK47 = 400,
[EnumMember(Value = "weapon_m4a1_silencer")]
M4A1S = 401,
SilencedM4 = M4A1S,
[EnumMember(Value = "weapon_m4a1")]
M4A1 = 402,
M4A4 = M4A1,
[EnumMember(Value = "weapon_galilar")]
GalilAR = 403,
Galil = GalilAR,
[EnumMember(Value = "weapon_famas")]
Famas = 404,
[EnumMember(Value = "weapon_sg556")]
SG556 = 405,
SG553 = SG556,
Krieg = SG556,
[EnumMember(Value = "weapon_awp")]
AWP = 406,
[EnumMember(Value = "weapon_aug")]
AUG = 407,
[EnumMember(Value = "weapon_ssg08")]
SSG08 = 408,
Scout = SSG08,
[EnumMember(Value = "weapon_scar20")]
SCAR20 = 409,
AutoSniperCT = SCAR20,
[EnumMember(Value = "weapon_g3sg1")]
G3SG1 = 410,
AutoSniperT = G3SG1,
//-----------------------------------------
//KNIFE
//-----------------------------------------
[EnumMember(Value = "weapon_knife_t")]
DefaultKnifeT = 500,
KnifeT = DefaultKnifeT,
[EnumMember(Value = "weapon_knife")]
DefaultKnifeCT = 501,
KnifeCT = DefaultKnifeCT,
Knife = DefaultKnifeCT,
}
}

View File

@@ -77,5 +77,22 @@ namespace CounterStrikeSharp.API.Modules.Memory
return null;
}
public static DataType ToValidDataType(this Type type)
{
if (types.ContainsKey(type)) return types[type];
if (typeof(NativeObject).IsAssignableFrom(type))
{
return DataType.DATA_TYPE_POINTER;
}
if (type.IsEnum && types.ContainsKey(Enum.GetUnderlyingType(type)))
{
return types[Enum.GetUnderlyingType(type)];
}
throw new NotSupportedException("Data type not supported:" + type.FullName);
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CounterStrikeSharp.API.Core;
namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
public abstract class BaseMemoryFunction : NativeObject
{
private static Dictionary<string, IntPtr> _createdFunctions = new();
private static IntPtr CreateValveFunctionBySignature(string signature, DataType returnType,
DataType[] argumentTypes)
{
if (!_createdFunctions.TryGetValue(signature, out var function))
{
try
{
function = NativeAPI.CreateVirtualFunctionBySignature(IntPtr.Zero, Addresses.ServerPath, signature,
argumentTypes.Length, (int)returnType, argumentTypes.Cast<object>().ToArray());
_createdFunctions[signature] = function;
}
catch (Exception)
{
}
}
return function;
}
public BaseMemoryFunction(string signature, DataType returnType, DataType[] parameters) : base(
CreateValveFunctionBySignature(signature, returnType, parameters))
{
}
public void Hook(Func<DynamicHook, HookResult> handler, HookMode mode)
{
NativeAPI.HookFunction(Handle, handler, mode == HookMode.Post);
}
public void Unhook(Func<DynamicHook, HookResult> handler, HookMode mode)
{
NativeAPI.UnhookFunction(Handle, handler, mode == HookMode.Post);
}
protected T InvokeInternal<T>(params object[] args)
{
return NativeAPI.ExecuteVirtualFunction<T>(Handle, args);
}
protected void InvokeInternalVoid(params object[] args)
{
NativeAPI.ExecuteVirtualFunction<object>(Handle, args);
}
}

View File

@@ -0,0 +1,31 @@
using System;
using CounterStrikeSharp.API.Core;
namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
public class DynamicHook : NativeObject
{
public DynamicHook(IntPtr pointer) : base(pointer)
{
}
public T GetParam<T>(int index)
{
return NativeAPI.DynamicHookGetParam<T>(Handle, (int)typeof(T).ToValidDataType(), index);
}
public T GetReturn<T>(int index)
{
return NativeAPI.DynamicHookGetReturn<T>(Handle, (int)typeof(T).ToValidDataType());
}
public void SetParam<T>(int index, T value)
{
NativeAPI.DynamicHookSetParam(Handle, (int)typeof(T).ToValidDataType(), index, value);
}
public void SetReturn<T>(T value)
{
NativeAPI.DynamicHookSetReturn(Handle, (int)typeof(T).ToValidDataType(), value);
}
}

View File

@@ -0,0 +1,185 @@
using System;
namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
public class MemoryFunctionVoid : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID, Array.Empty<DataType>())
{
}
public void Invoke()
{
InvokeInternalVoid();
}
}
public class MemoryFunctionVoid<T1> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[] { typeof(T1).ToValidDataType() })
{
}
public void Invoke(T1 arg1)
{
InvokeInternalVoid(arg1);
}
}
public class MemoryFunctionVoid<T1, T2> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType() })
{
}
public void Invoke(T1 arg1, T2 arg2)
{
InvokeInternalVoid(arg1, arg2);
}
}
public class MemoryFunctionVoid<T1, T2, T3> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType() })
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3)
{
InvokeInternalVoid(arg1, arg2, arg3);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4, T5> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8, T9> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(),
typeof(T9).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
}
public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(),
typeof(T9).ToValidDataType(), typeof(T10).ToValidDataType()
})
{
}
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}
}

View File

@@ -0,0 +1,179 @@
using System;
namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
public class MemoryFunctionWithReturn<TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
Array.Empty<DataType>())
{
}
public TResult Invoke()
{
return InvokeInternal<TResult>();
}
}
public class MemoryFunctionWithReturn<T1, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[] { typeof(T1).ToValidDataType() })
{
}
public TResult Invoke(T1 arg1)
{
return InvokeInternal<TResult>(arg1);
}
}
public class MemoryFunctionWithReturn<T1, T2, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType() })
{
}
public TResult Invoke(T1 arg1, T2 arg2)
{
return InvokeInternal<TResult>(arg1, arg2);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType() })
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3)
{
return InvokeInternal<TResult>(arg1, arg2, arg3);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, T8, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(), typeof(T9).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
}
public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> : BaseMemoryFunction
{
public MemoryFunctionWithReturn(string signature) : base(signature, typeof(TResult).ToValidDataType(),
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(), typeof(T9).ToValidDataType(),
typeof(T10).ToValidDataType()
})
{
}
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10)
{
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}
}

View File

@@ -1,41 +1,79 @@
using System;
using System.Reflection.Metadata;
using System.Collections.Generic;
using System.Linq;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Modules.Memory;
public static class VirtualFunctions
{
public static Action<IntPtr, HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrint =
VirtualFunction.CreateVoid<IntPtr, HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr>(
public static MemoryFunctionVoid<IntPtr, HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrintFunc =
new(
GameData.GetSignature("ClientPrint"));
public static Action<IntPtr, HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrint =
ClientPrintFunc.Invoke;
public static MemoryFunctionVoid<HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrintAllFunc =
new(GameData.GetSignature("UTIL_ClientPrintAll"));
public static Action<HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrintAll =
VirtualFunction.CreateVoid<HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr>(
GameData.GetSignature("UTIL_ClientPrintAll"));
ClientPrintAllFunc.Invoke;
// void (*FnGiveNamedItem)(void* itemService,const char* pchName, void* iSubType,void* pScriptItem, void* a5,void* a6) = nullptr;
public static Func<IntPtr, string, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr> GiveNamedItem =
VirtualFunction.Create<IntPtr, string, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr>(
GameData.GetSignature("GiveNamedItem"));
public static MemoryFunctionWithReturn<IntPtr, string, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr> GiveNamedItemFunc =
new(GameData.GetSignature("GiveNamedItem"));
public static Action<IntPtr, byte> SwitchTeam =
VirtualFunction.CreateVoid<IntPtr, byte>(GameData.GetSignature("CCSPlayerController_SwitchTeam"));
public static Func<IntPtr, string, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr> GiveNamedItem = GiveNamedItemFunc.Invoke;
public static MemoryFunctionVoid<IntPtr, byte> SwitchTeamFunc =
new(GameData.GetSignature("CCSPlayerController_SwitchTeam"));
public static Action<IntPtr, byte> SwitchTeam = SwitchTeamFunc.Invoke;
// void(*UTIL_Remove)(CEntityInstance*);
public static Action<IntPtr> UTIL_Remove = VirtualFunction.CreateVoid<IntPtr>(GameData.GetSignature("UTIL_Remove"));
public static MemoryFunctionVoid<IntPtr> UTIL_RemoveFunc =
new(GameData.GetSignature("UTIL_Remove"));
public static Action<IntPtr> UTIL_Remove = UTIL_RemoveFunc.Invoke;
// void(*CBaseModelEntity_SetModel)(CBaseModelEntity*, const char*);
public static Action<IntPtr, string> SetModel = VirtualFunction.CreateVoid<IntPtr, string>(GameData.GetSignature("CBaseModelEntity_SetModel"));
public static MemoryFunctionVoid<IntPtr, string> SetModelFunc =
new(GameData.GetSignature("CBaseModelEntity_SetModel"));
public static Action<IntPtr, RoundEndReason, float> TerminateRound = VirtualFunction.CreateVoid<nint, RoundEndReason, float>(GameData.GetSignature("CCSGameRules_TerminateRound"));
public static Action<IntPtr, string> SetModel = SetModelFunc.Invoke;
public static Func<string, int, IntPtr> UTIL_CreateEntityByName = VirtualFunction.Create<string, int, IntPtr>(GameData.GetSignature("UTIL_CreateEntityByName"));
public static MemoryFunctionVoid<nint, RoundEndReason, float> TerminateRoundFunc =
new(GameData.GetSignature("CCSGameRules_TerminateRound"));
public static Action<IntPtr, IntPtr> CBaseEntity_DispatchSpawn = VirtualFunction.CreateVoid<IntPtr, IntPtr>(GameData.GetSignature("CBaseEntity_DispatchSpawn"));
public static Action<IntPtr, RoundEndReason, float> TerminateRound = TerminateRoundFunc.Invoke;
public static Action<IntPtr> CCSPlayerPawn_Respawn = VirtualFunction.CreateVoid<IntPtr>(GameData.GetSignature("CCSPlayerPawn_Respawn"));
public static MemoryFunctionWithReturn<string, int, IntPtr> UTIL_CreateEntityByNameFunc =
new(GameData.GetSignature("UTIL_CreateEntityByName"));
public static Func<string, int, IntPtr> UTIL_CreateEntityByName = UTIL_CreateEntityByNameFunc.Invoke;
public static MemoryFunctionVoid<IntPtr, IntPtr> CBaseEntity_DispatchSpawnFunc =
new(GameData.GetSignature("CBaseEntity_DispatchSpawn"));
public static Action<IntPtr, IntPtr> CBaseEntity_DispatchSpawn = CBaseEntity_DispatchSpawnFunc.Invoke;
public static MemoryFunctionVoid<IntPtr> CCSPlayerPawn_RespawnFunc = new(GameData.GetSignature("CCSPlayerPawn_Respawn"));
public static Action<IntPtr> CCSPlayerPawn_Respawn = CCSPlayerPawn_RespawnFunc.Invoke;
public static MemoryFunctionVoid<CEntityInstance, CTakeDamageInfo> CBaseEntity_TakeDamageOldFunc = new (GameData.GetSignature("CBaseEntity_TakeDamageOld"));
public static Action<CEntityInstance, CTakeDamageInfo> CBaseEntity_TakeDamageOld = CBaseEntity_TakeDamageOldFunc.Invoke;
public static MemoryFunctionVoid<CCSPlayerPawnBase> CCSPlayerPawnBase_PostThinkFunc = new (GameData.GetSignature("CCSPlayerPawnBase_PostThink"));
public static Action<CCSPlayerPawnBase> CCSPlayerPawnBase_PostThink = CCSPlayerPawnBase_PostThinkFunc.Invoke;
public static MemoryFunctionVoid<CBaseTrigger, CBaseEntity> CBaseTrigger_StartTouchFunc = new (GameData.GetSignature("CBaseTrigger_StartTouch"));
public static Action<CBaseTrigger, CBaseEntity> CBaseTrigger_StartTouch = CBaseTrigger_StartTouchFunc.Invoke;
public static MemoryFunctionVoid<CBaseTrigger, CBaseEntity> CBaseTrigger_EndTouchFunc = new (GameData.GetSignature("CBaseTrigger_EndTouch"));
public static Action<CBaseTrigger, CBaseEntity> CBaseTrigger_EndTouch = CBaseTrigger_EndTouchFunc.Invoke;
}

View File

@@ -22,19 +22,20 @@ namespace CounterStrikeSharp.API.Modules.Utils
public static char White = '\x01';
public static char Darkred = '\x02';
public static char Green = '\x04';
public static char LightYellow = '\x03';
public static char LightBlue = '\x03';
public static char LightYellow = '\x09';
public static char LightBlue = '\x0B';
public static char Olive = '\x05';
public static char Lime = '\x06';
public static char Red = '\x07';
public static char Purple = '\x03';
public static char LightPurple = '\x03';
public static char Purple = '\x0E';
public static char Grey = '\x08';
public static char Yellow = '\x09';
public static char Gold = '\x10';
public static char Silver = '\x0A';
public static char Blue = '\x0B';
public static char DarkBlue = '\x0C';
public static char BlueGrey = '\x0D';
public static char BlueGrey = '\x0A';
public static char Magenta = '\x0E';
public static char LightRed = '\x0F';
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Linq;
using System.Runtime.Serialization;
namespace CounterStrikeSharp.API.Modules.Utils
{
public static class EnumUtils
{
public static string? GetEnumMemberAttributeValue<T>(T enumValue)
{
var enumType = typeof(T);
if(!enumType.IsEnum || enumValue == null)
{
return null;
}
var enumString = enumValue.ToString();
if(string.IsNullOrWhiteSpace(enumString))
{
return null;
}
var memberInfo = enumType.GetMember(enumString);
var enumMemberAttribute = memberInfo.FirstOrDefault()?.GetCustomAttributes(false).OfType<EnumMemberAttribute>().FirstOrDefault();
if (enumMemberAttribute != null)
{
return enumMemberAttribute.Value;
}
return null;
}
}
}

View File

@@ -157,6 +157,9 @@ internal static partial class Program
WriteEnum(builder, enumName, schemaEnum);
}
// Manually whitelist some classes
visited.Add("CTakeDamageInfo");
var visitedClassNames = new HashSet<string>();
foreach (var (className, schemaClass) in allClasses)
{

View File

@@ -26,6 +26,11 @@ public record SchemaFieldType
this.Category = SchemaTypeCategory.Builtin;
this.Name = "int32";
}
else if (this.Name == "AmmoIndex_t")
{
this.Category = SchemaTypeCategory.Builtin;
this.Name = "uint8";
}
else if (this.Name == "CBitVec< 64 >")
{
this.Category = SchemaTypeCategory.FixedArray;
@@ -68,6 +73,7 @@ public record SchemaFieldType
"uint32" => "UInt32",
"uint64" => "UInt64",
"bool" => "bool",
"char" => "char",
_ => throw new ArgumentOutOfRangeException(nameof(name), name, $"Unknown built-in: {name}")
};
@@ -85,6 +91,7 @@ public record SchemaFieldType
SchemaAtomicCategory.T => $"{name.Split('<')[0]}<{inner!.CsTypeName}>",
SchemaAtomicCategory.Collection => $"NetworkedVector<{inner!.CsTypeName}>",
SchemaAtomicCategory.Unknown => "CBitVec",
SchemaAtomicCategory.TT => "Unknown",
_ => throw new ArgumentOutOfRangeException(nameof(atomic), atomic, $"Unsupported atomic: {atomic}")
};

View File

@@ -26,10 +26,10 @@ using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Cvars;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Events;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Menu;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging;
@@ -74,6 +74,12 @@ namespace TestPlugin
$"Test Plugin has been loaded, and the hot reload flag was {hotReload}, path is {ModulePath}");
Logger.LogWarning($"Max Players: {Server.MaxPlayers}");
VirtualFunctions.SwitchTeamFunc.Hook(hook =>
{
Logger.LogInformation("Switch team func called");
return HookResult.Continue;
}, HookMode.Pre);
SetupConvars();
SetupGameEvents();
@@ -98,6 +104,57 @@ namespace TestPlugin
var virtualFunc = VirtualFunction.Create<IntPtr>(server.Pointer, 91);
var result = virtualFunc() - 8;
Logger.LogInformation("Result of virtual func call is {Pointer:X}", result);
VirtualFunctions.CBaseTrigger_StartTouchFunc.Hook(h =>
{
var trigger = h.GetParam<CBaseTrigger>(0);
var entity = h.GetParam<CBaseEntity>(1);
Logger.LogInformation("Trigger {Trigger} touched by {Entity}", trigger.DesignerName, entity.DesignerName);
return HookResult.Continue;
}, HookMode.Post);
VirtualFunctions.CBaseTrigger_EndTouchFunc.Hook(h =>
{
var trigger = h.GetParam<CBaseTrigger>(0);
var entity = h.GetParam<CBaseEntity>(1);
Logger.LogInformation("Trigger left {Trigger} by {Entity}", trigger.DesignerName, entity.DesignerName);
return HookResult.Continue;
}, HookMode.Post);
VirtualFunctions.UTIL_RemoveFunc.Hook(hook =>
{
var entityInstance = hook.GetParam<CEntityInstance>(0);
Logger.LogInformation("Removed entity {EntityIndex}", entityInstance.EntityIndex.Value.Value);
return HookResult.Continue;
}, HookMode.Post);
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook((h =>
{
var victim = h.GetParam<CEntityInstance>(0);
var damageInfo = h.GetParam<CTakeDamageInfo>(1);
if (damageInfo.Inflictor.Value.DesignerName == "inferno")
{
var inferno = new CInferno(damageInfo.Inflictor.Value.Handle);
Logger.LogInformation("Owner of inferno is {Owner}", inferno.OwnerEntity);
if (victim == inferno.OwnerEntity.Value)
{
damageInfo.Damage = 0;
}
else
{
damageInfo.Damage = 150;
}
}
return HookResult.Continue;
}), HookMode.Pre);
}
private void SetupConvars()
@@ -385,6 +442,18 @@ namespace TestPlugin
command.ReplyToCommand(weapon.Value.DesignerName);
}
}
[ConsoleCommand("css_colors", "List Chat Colors")]
public void OnCommandColors(CCSPlayerController? player, CommandInfo command)
{
if (player == null) return;
if (!player.PlayerPawn.IsValid) return;
for (int i = 0; i < 16; i++)
{
command.ReplyToCommand($" {(char)i}Color 0x{i:x}");
}
}
[ConsoleCommand("css_pause", "Pause Game")]
public void OnCommandPause(CCSPlayerController? player, CommandInfo command)
@@ -400,6 +469,30 @@ namespace TestPlugin
player.GiveNamedItem(command.ArgByIndex(1));
}
[ConsoleCommand("css_giveenum", "giveenum")]
public void OnCommandGiveEnum(CCSPlayerController? player, CommandInfo command)
{
if (player == null) return;
if (!player.IsValid) return;
player.GiveNamedItem(CsItem.M4A1);
player.GiveNamedItem(CsItem.HEGrenade);
player.GiveNamedItem(CsItem.Kevlar);
player.GiveNamedItem(CsItem.Tec9);
}
[ConsoleCommand("css_give", "give")]
public void OnCommandGiveItems(CCSPlayerController? player, CommandInfo command)
{
if (player == null) return;
if (!player.IsValid) return;
player.GiveNamedItem("weapon_m4a1");
player.GiveNamedItem("weapon_hegrenade");
player.GiveNamedItem("item_kevlar");
player.GiveNamedItem("weapon_tec9");
}
private HookResult GenericEventHandler<T>(T @event, GameEventInfo info) where T : GameEvent
{
Logger.LogInformation("Event found {Pointer:X}, event name: {EventName}, dont broadcast: {DontBroadcast}",

View File

@@ -32,41 +32,47 @@
#include "core/log.h"
#include "dyncall/dyncall/dyncall.h"
#include "pch.h"
#include "dynohook/core.h"
#include "dynohook/manager.h"
#include "dynohook/conventions/x64/x64SystemVcall.h"
namespace counterstrikesharp {
DCCallVM* g_pCallVM = dcNewCallVM(4096);
std::map<dyno::Hook*, ValveFunction*> g_HookMap;
// ============================================================================
// >> GetDynCallConvention
// ============================================================================
int GetDynCallConvention(Convention_t eConv) {
int GetDynCallConvention(Convention_t eConv)
{
switch (eConv) {
case CONV_CUSTOM:
return -1;
case CONV_CDECL:
return DC_CALL_C_DEFAULT;
case CONV_THISCALL:
case CONV_CUSTOM:
return -1;
case CONV_CDECL:
return DC_CALL_C_DEFAULT;
case CONV_THISCALL:
#ifdef _WIN32
return DC_CALL_C_X86_WIN32_THIS_MS;
return DC_CALL_C_X86_WIN32_THIS_MS;
#else
return DC_CALL_C_X86_WIN32_THIS_GNU;
return DC_CALL_C_X86_WIN32_THIS_GNU;
#endif
#ifdef _WIN32
case CONV_STDCALL:
return DC_CALL_C_X86_WIN32_STD;
case CONV_FASTCALL:
return DC_CALL_C_X86_WIN32_FAST_MS;
case CONV_STDCALL:
return DC_CALL_C_X86_WIN32_STD;
case CONV_FASTCALL:
return DC_CALL_C_X86_WIN32_FAST_MS;
#endif
}
return -1;
}
ValveFunction::ValveFunction(void* ulAddr,
Convention_t callingConvention,
std::vector<DataType_t> args,
DataType_t returnType)
: m_ulAddr(ulAddr) {
ValveFunction::ValveFunction(void* ulAddr, Convention_t callingConvention,
std::vector<DataType_t> args, DataType_t returnType)
: m_ulAddr(ulAddr)
{
m_Args = args;
m_eReturnType = returnType;
@@ -76,11 +82,8 @@ ValveFunction::ValveFunction(void* ulAddr,
m_iCallingConvention = GetDynCallConvention(m_eCallingConvention);
}
ValveFunction::ValveFunction(void* ulAddr,
Convention_t callingConvention,
DataType_t* args,
int argCount,
DataType_t returnType)
ValveFunction::ValveFunction(void* ulAddr, Convention_t callingConvention, DataType_t* args,
int argCount, DataType_t returnType)
: m_ulAddr(ulAddr)
{
@@ -93,26 +96,14 @@ ValveFunction::ValveFunction(void* ulAddr,
ValveFunction::~ValveFunction() {}
bool ValveFunction::IsCallable() {
bool ValveFunction::IsCallable()
{
return (m_eCallingConvention != CONV_CUSTOM) && (m_iCallingConvention != -1);
}
// bool ValveFunction::IsHookable() { return m_pCallingConvention != NULL; }
//
// bool ValveFunction::IsHooked() { return GetHookManager()->FindHook((void*)m_ulAddr) != NULL; }
//
// CHook* ValveFunction::GetHook() { return GetHookManager()->FindHook((void*)m_ulAddr); }
// ValveFunction* ValveFunction::GetTrampoline() {
// CHook* pHook = GetHookManager()->FindHook((void*)m_ulAddr);
// if (!pHook) return nullptr;
//
// return new ValveFunction((unsigned long)pHook->m_pTrampoline, m_eCallingConvention, m_Args,
// m_eReturnType);
// }
template <class ReturnType, class Function>
ReturnType CallHelper(Function func, DCCallVM* vm, void* addr) {
ReturnType CallHelper(Function func, DCCallVM* vm, void* addr)
{
ReturnType result;
result = (ReturnType)func(vm, (void*)addr);
return result;
@@ -120,8 +111,10 @@ ReturnType CallHelper(Function func, DCCallVM* vm, void* addr) {
void CallHelperVoid(DCCallVM* vm, void* addr) { dcCallVoid(vm, (void*)addr); }
void ValveFunction::Call(ScriptContext& script_context, int offset) {
if (!IsCallable()) return;
void ValveFunction::Call(ScriptContext& script_context, int offset)
{
if (!IsCallable())
return;
dcReset(g_pCallVM);
dcMode(g_pCallVM, m_iCallingConvention);
@@ -129,148 +122,195 @@ void ValveFunction::Call(ScriptContext& script_context, int offset) {
for (size_t i = 0; i < m_Args.size(); i++) {
int contextIndex = i + offset;
switch (m_Args[i]) {
case DATA_TYPE_BOOL:
dcArgBool(g_pCallVM, script_context.GetArgument<bool>(contextIndex));
break;
case DATA_TYPE_CHAR:
dcArgChar(g_pCallVM, script_context.GetArgument<char>(contextIndex));
break;
case DATA_TYPE_UCHAR:
dcArgChar(g_pCallVM, script_context.GetArgument<unsigned char>(contextIndex));
break;
case DATA_TYPE_SHORT:
dcArgShort(g_pCallVM, script_context.GetArgument<short>(contextIndex));
break;
case DATA_TYPE_USHORT:
dcArgShort(g_pCallVM, script_context.GetArgument<unsigned short>(contextIndex));
break;
case DATA_TYPE_INT:
dcArgInt(g_pCallVM, script_context.GetArgument<int>(contextIndex));
break;
case DATA_TYPE_UINT:
dcArgInt(g_pCallVM, script_context.GetArgument<unsigned int>(contextIndex));
break;
case DATA_TYPE_LONG:
dcArgLong(g_pCallVM, script_context.GetArgument<long>(contextIndex));
break;
case DATA_TYPE_ULONG:
dcArgLong(g_pCallVM, script_context.GetArgument<unsigned long>(contextIndex));
break;
case DATA_TYPE_LONG_LONG:
dcArgLongLong(g_pCallVM, script_context.GetArgument<long long>(contextIndex));
break;
case DATA_TYPE_ULONG_LONG:
dcArgLongLong(g_pCallVM,
script_context.GetArgument<unsigned long long>(contextIndex));
break;
case DATA_TYPE_FLOAT:
dcArgFloat(g_pCallVM, script_context.GetArgument<float>(contextIndex));
break;
case DATA_TYPE_DOUBLE:
dcArgDouble(g_pCallVM, script_context.GetArgument<double>(contextIndex));
break;
case DATA_TYPE_POINTER:
dcArgPointer(g_pCallVM, script_context.GetArgument<void*>(contextIndex));
break;
case DATA_TYPE_STRING:
dcArgPointer(g_pCallVM,
(void*)script_context.GetArgument<const char*>(contextIndex));
break;
default:
assert(!"Unknown function parameter type!");
break;
case DATA_TYPE_BOOL:
dcArgBool(g_pCallVM, script_context.GetArgument<bool>(contextIndex));
break;
case DATA_TYPE_CHAR:
dcArgChar(g_pCallVM, script_context.GetArgument<char>(contextIndex));
break;
case DATA_TYPE_UCHAR:
dcArgChar(g_pCallVM, script_context.GetArgument<unsigned char>(contextIndex));
break;
case DATA_TYPE_SHORT:
dcArgShort(g_pCallVM, script_context.GetArgument<short>(contextIndex));
break;
case DATA_TYPE_USHORT:
dcArgShort(g_pCallVM, script_context.GetArgument<unsigned short>(contextIndex));
break;
case DATA_TYPE_INT:
dcArgInt(g_pCallVM, script_context.GetArgument<int>(contextIndex));
break;
case DATA_TYPE_UINT:
dcArgInt(g_pCallVM, script_context.GetArgument<unsigned int>(contextIndex));
break;
case DATA_TYPE_LONG:
dcArgLong(g_pCallVM, script_context.GetArgument<long>(contextIndex));
break;
case DATA_TYPE_ULONG:
dcArgLong(g_pCallVM, script_context.GetArgument<unsigned long>(contextIndex));
break;
case DATA_TYPE_LONG_LONG:
dcArgLongLong(g_pCallVM, script_context.GetArgument<long long>(contextIndex));
break;
case DATA_TYPE_ULONG_LONG:
dcArgLongLong(g_pCallVM, script_context.GetArgument<unsigned long long>(contextIndex));
break;
case DATA_TYPE_FLOAT:
dcArgFloat(g_pCallVM, script_context.GetArgument<float>(contextIndex));
break;
case DATA_TYPE_DOUBLE:
dcArgDouble(g_pCallVM, script_context.GetArgument<double>(contextIndex));
break;
case DATA_TYPE_POINTER:
dcArgPointer(g_pCallVM, script_context.GetArgument<void*>(contextIndex));
break;
case DATA_TYPE_STRING:
dcArgPointer(g_pCallVM, (void*)script_context.GetArgument<const char*>(contextIndex));
break;
default:
assert(!"Unknown function parameter type!");
break;
}
}
switch (m_eReturnType) {
case DATA_TYPE_VOID:
CallHelperVoid(g_pCallVM, m_ulAddr);
break;
case DATA_TYPE_BOOL:
script_context.SetResult(CallHelper<bool>(dcCallBool, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_CHAR:
script_context.SetResult(CallHelper<char>(dcCallChar, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_UCHAR:
script_context.SetResult(CallHelper<unsigned char>(dcCallChar, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_SHORT:
script_context.SetResult(CallHelper<short>(dcCallShort, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_USHORT:
script_context.SetResult(CallHelper<unsigned short>(dcCallShort, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_INT:
script_context.SetResult(CallHelper<int>(dcCallInt, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_UINT:
script_context.SetResult(CallHelper<unsigned int>(dcCallInt, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_LONG:
script_context.SetResult(CallHelper<long>(dcCallLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_ULONG:
script_context.SetResult(CallHelper<unsigned long>(dcCallLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_LONG_LONG:
script_context.SetResult(CallHelper<long long>(dcCallLongLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_ULONG_LONG:
script_context.SetResult(
CallHelper<unsigned long long>(dcCallLongLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_FLOAT:
script_context.SetResult(CallHelper<float>(dcCallFloat, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_DOUBLE:
script_context.SetResult(CallHelper<double>(dcCallDouble, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_POINTER:
script_context.SetResult(CallHelper<void*>(dcCallPointer, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_STRING:
script_context.SetResult(CallHelper<const char*>(dcCallPointer, g_pCallVM, m_ulAddr));
break;
default:
assert(!"Unknown function return type!");
break;
case DATA_TYPE_VOID:
CallHelperVoid(g_pCallVM, m_ulAddr);
break;
case DATA_TYPE_BOOL:
script_context.SetResult(CallHelper<bool>(dcCallBool, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_CHAR:
script_context.SetResult(CallHelper<char>(dcCallChar, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_UCHAR:
script_context.SetResult(CallHelper<unsigned char>(dcCallChar, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_SHORT:
script_context.SetResult(CallHelper<short>(dcCallShort, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_USHORT:
script_context.SetResult(CallHelper<unsigned short>(dcCallShort, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_INT:
script_context.SetResult(CallHelper<int>(dcCallInt, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_UINT:
script_context.SetResult(CallHelper<unsigned int>(dcCallInt, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_LONG:
script_context.SetResult(CallHelper<long>(dcCallLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_ULONG:
script_context.SetResult(CallHelper<unsigned long>(dcCallLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_LONG_LONG:
script_context.SetResult(CallHelper<long long>(dcCallLongLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_ULONG_LONG:
script_context.SetResult(
CallHelper<unsigned long long>(dcCallLongLong, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_FLOAT:
script_context.SetResult(CallHelper<float>(dcCallFloat, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_DOUBLE:
script_context.SetResult(CallHelper<double>(dcCallDouble, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_POINTER:
script_context.SetResult(CallHelper<void*>(dcCallPointer, g_pCallVM, m_ulAddr));
break;
case DATA_TYPE_STRING:
script_context.SetResult(CallHelper<const char*>(dcCallPointer, g_pCallVM, m_ulAddr));
break;
default:
assert(!"Unknown function return type!");
break;
}
}
//
// CHook* HookFunctionHelper(void* addr, ICallingConvention* pConv) {
// CHook* result;
// result = GetHookManager()->HookFunction(addr, pConv);
// return result;
//}
//
// void ValveFunction::DeleteHook() {
// CHook* pHook = GetHookManager()->FindHook((void*)m_ulAddr);
// if (!pHook) return;
//
// // Set the calling convention to NULL, because DynamicHooks will delete it
// // otherwise.
// pHook->m_pCallingConvention = NULL;
// GetHookManager()->UnhookFunction((void*)m_ulAddr);
//}
//
// CHook* ValveFunction::AddHook(HookType_t eType, void* callable) {
// if (!IsHookable()) return nullptr;
//
// CHook* pHook = GetHookManager()->FindHook((void*)m_ulAddr);
//
// if (!pHook) {
// pHook = HookFunctionHelper((void*)m_ulAddr, m_pCallingConvention);
//
// // DynamicHooks will handle our convention from there, regardless if we
// // allocated it or not.
// m_bAllocatedCallingConvention = false;
// }
//
// // Add the hook handler. If it's already added, it won't be added twice
// pHook->AddCallback(eType, (HookHandlerFn*)(void*)callable);
//
// return pHook;
//}
} // namespace counterstrikesharp
dyno::ReturnAction HookHandler(dyno::HookType hookType, dyno::Hook& hook)
{
auto vf = g_HookMap[&hook];
auto callback = hookType == dyno::HookType::Pre ? vf->m_precallback : vf->m_postcallback;
if (callback == nullptr) {
return dyno::ReturnAction::Ignored;
}
callback->Reset();
callback->ScriptContext().Push(&hook);
for (auto fnMethodToCall : callback->GetFunctions()) {
if (!fnMethodToCall)
continue;
fnMethodToCall(&callback->ScriptContextStruct());
auto result = callback->ScriptContext().GetResult<HookResult>();
CSSHARP_CORE_TRACE("Received hook callback result of {}, hook mode {}", result,
(int)hookType);
if (result >= HookResult::Handled) {
return dyno::ReturnAction::Supercede;
}
}
return dyno::ReturnAction::Ignored;
}
std::vector<dyno::DataObject> ConvertArgsToDynoHook(const std::vector<DataType_t>& dataTypes)
{
std::vector<dyno::DataObject> converted;
converted.reserve(dataTypes.size());
for (DataType_t dt : dataTypes) {
converted.push_back(dyno::DataObject(static_cast<dyno::DataType>(dt)));
}
return converted;
}
void ValveFunction::AddHook(CallbackT callable, bool post)
{
dyno::HookManager& manager = dyno::HookManager::Get();
dyno::Hook* hook = manager.hook((void*)m_ulAddr, [this] {
return new dyno::x64SystemVcall(ConvertArgsToDynoHook(m_Args),
static_cast<dyno::DataType>(this->m_eReturnType));
});
g_HookMap[hook] = this;
hook->addCallback(dyno::HookType::Post, (dyno::HookHandler*)&HookHandler);
hook->addCallback(dyno::HookType::Pre, (dyno::HookHandler*)&HookHandler);
if (post) {
if (m_postcallback == nullptr) {
m_postcallback = globals::callbackManager.CreateCallback("");
}
m_postcallback->AddListener(callable);
} else {
if (m_precallback == nullptr) {
m_precallback = globals::callbackManager.CreateCallback("");
}
m_precallback->AddListener(callable);
}
}
void ValveFunction::RemoveHook(CallbackT callable, bool post) {
dyno::HookManager& manager = dyno::HookManager::Get();
dyno::Hook* hook = manager.hook((void*)m_ulAddr, [this] {
return new dyno::x64SystemVcall(ConvertArgsToDynoHook(m_Args),
static_cast<dyno::DataType>(this->m_eReturnType));
});
g_HookMap[hook] = this;
if (post) {
if (m_postcallback != nullptr) {
m_postcallback->RemoveListener(callable);
}
} else {
if (m_precallback != nullptr) {
m_precallback->RemoveListener(callable);
}
}
}
} // namespace counterstrikesharp

View File

@@ -32,6 +32,11 @@
#include "scripting/callback_manager.h"
#include "scripting/script_engine.h"
#include <map>
namespace dyno {
class Hook;
}
namespace counterstrikesharp {
@@ -81,19 +86,13 @@ public:
~ValveFunction();
bool IsCallable();
// bool IsHookable();
// bool IsHooked();
// CHook* GetHook();
// ValveFunction* GetTrampoline();
void SetOffset(int offset) { m_offset = offset; }
void SetSignature(const char* signature) { m_signature = signature; }
void Call(ScriptContext& args, int offset = 0);
// CHook* AddHook(HookType_t eType, void* callable);
// void DeleteHook();
void AddHook(CallbackT callable, bool post);
void RemoveHook(CallbackT callable, bool post);
void* m_ulAddr;
std::vector<DataType_t> m_Args;
@@ -107,6 +106,8 @@ public:
int m_offset;
const char* m_signature;
ScriptCallback* m_precallback = nullptr;
ScriptCallback* m_postcallback = nullptr;
};
} // namespace counterstrikesharp

View File

@@ -0,0 +1,283 @@
/*
* 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 <https://www.gnu.org/licenses/>. *
*/
// clang-format off
#include "mm_plugin.h"
#include "core/timer_system.h"
#include "scripting/autonative.h"
#include "scripting/script_engine.h"
#include "core/function.h"
#include "pch.h"
#include "dynohook/core.h"
#include "dynohook/manager.h"
// clang-format on
namespace counterstrikesharp {
void DHookGetReturn(ScriptContext& script_context)
{
auto hook = script_context.GetArgument<dyno::Hook*>(0);
auto dataType = script_context.GetArgument<DataType_t>(1);
if (hook == nullptr) {
script_context.ThrowNativeError("Invalid hook");
}
switch (dataType) {
case DATA_TYPE_BOOL:
script_context.SetResult(hook->getReturnValue<bool>());
break;
case DATA_TYPE_CHAR:
script_context.SetResult(hook->getReturnValue<char>());
break;
case DATA_TYPE_UCHAR:
script_context.SetResult(hook->getReturnValue<unsigned char>());
break;
case DATA_TYPE_SHORT:
script_context.SetResult(hook->getReturnValue<short>());
break;
case DATA_TYPE_USHORT:
script_context.SetResult(hook->getReturnValue<unsigned short>());
break;
case DATA_TYPE_INT:
script_context.SetResult(hook->getReturnValue<int>());
break;
case DATA_TYPE_UINT:
script_context.SetResult(hook->getReturnValue<unsigned int>());
break;
case DATA_TYPE_LONG:
script_context.SetResult(hook->getReturnValue<long>());
break;
case DATA_TYPE_ULONG:
script_context.SetResult(hook->getReturnValue<unsigned long>());
break;
case DATA_TYPE_LONG_LONG:
script_context.SetResult(hook->getReturnValue<long long>());
break;
case DATA_TYPE_ULONG_LONG:
script_context.SetResult(hook->getReturnValue<unsigned long long>());
break;
case DATA_TYPE_FLOAT:
script_context.SetResult(hook->getReturnValue<float>());
break;
case DATA_TYPE_DOUBLE:
script_context.SetResult(hook->getReturnValue<double>());
break;
case DATA_TYPE_POINTER:
script_context.SetResult(hook->getReturnValue<void*>());
break;
case DATA_TYPE_STRING:
script_context.SetResult(hook->getReturnValue<const char*>());
break;
default:
assert(!"Unknown function parameter type!");
break;
}
}
void DHookSetReturn(ScriptContext& script_context)
{
auto hook = script_context.GetArgument<dyno::Hook*>(0);
auto dataType = script_context.GetArgument<DataType_t>(1);
if (hook == nullptr) {
script_context.ThrowNativeError("Invalid hook");
}
auto valueIndex = 2;
switch (dataType) {
case DATA_TYPE_BOOL:
hook->setReturnValue(script_context.GetArgument<bool>(valueIndex));
break;
case DATA_TYPE_CHAR:
hook->setReturnValue(script_context.GetArgument<char>(valueIndex));
break;
case DATA_TYPE_UCHAR:
hook->setReturnValue(script_context.GetArgument<unsigned char>(valueIndex));
break;
case DATA_TYPE_SHORT:
hook->setReturnValue(script_context.GetArgument<short>(valueIndex));
break;
case DATA_TYPE_USHORT:
hook->setReturnValue(script_context.GetArgument<unsigned short>(valueIndex));
break;
case DATA_TYPE_INT:
hook->setReturnValue(script_context.GetArgument<int>(valueIndex));
break;
case DATA_TYPE_UINT:
hook->setReturnValue(script_context.GetArgument<unsigned int>(valueIndex));
break;
case DATA_TYPE_LONG:
hook->setReturnValue(script_context.GetArgument<long>(valueIndex));
break;
case DATA_TYPE_ULONG:
hook->setReturnValue(script_context.GetArgument<unsigned long>(valueIndex));
break;
case DATA_TYPE_LONG_LONG:
hook->setReturnValue(script_context.GetArgument<long long>(valueIndex));
break;
case DATA_TYPE_ULONG_LONG:
hook->setReturnValue(script_context.GetArgument<unsigned long long>(valueIndex));
break;
case DATA_TYPE_FLOAT:
hook->setReturnValue(script_context.GetArgument<float>(valueIndex));
break;
case DATA_TYPE_DOUBLE:
hook->setReturnValue(script_context.GetArgument<double>(valueIndex));
break;
case DATA_TYPE_POINTER:
hook->setReturnValue(script_context.GetArgument<void*>(valueIndex));
break;
case DATA_TYPE_STRING:
hook->setReturnValue(script_context.GetArgument<const char*>(valueIndex));
break;
default:
assert(!"Unknown function parameter type!");
break;
}
}
void DHookGetParam(ScriptContext& script_context)
{
auto hook = script_context.GetArgument<dyno::Hook*>(0);
auto dataType = script_context.GetArgument<DataType_t>(1);
auto paramIndex = script_context.GetArgument<int>(2);
if (hook == nullptr) {
script_context.ThrowNativeError("Invalid hook");
}
switch (dataType) {
case DATA_TYPE_BOOL:
script_context.SetResult(hook->getArgument<bool>(paramIndex));
break;
case DATA_TYPE_CHAR:
script_context.SetResult(hook->getArgument<char>(paramIndex));
break;
case DATA_TYPE_UCHAR:
script_context.SetResult(hook->getArgument<unsigned char>(paramIndex));
break;
case DATA_TYPE_SHORT:
script_context.SetResult(hook->getArgument<short>(paramIndex));
break;
case DATA_TYPE_USHORT:
script_context.SetResult(hook->getArgument<unsigned short>(paramIndex));
break;
case DATA_TYPE_INT:
script_context.SetResult(hook->getArgument<int>(paramIndex));
break;
case DATA_TYPE_UINT:
script_context.SetResult(hook->getArgument<unsigned int>(paramIndex));
break;
case DATA_TYPE_LONG:
script_context.SetResult(hook->getArgument<long>(paramIndex));
break;
case DATA_TYPE_ULONG:
script_context.SetResult(hook->getArgument<unsigned long>(paramIndex));
break;
case DATA_TYPE_LONG_LONG:
script_context.SetResult(hook->getArgument<long long>(paramIndex));
break;
case DATA_TYPE_ULONG_LONG:
script_context.SetResult(hook->getArgument<unsigned long long>(paramIndex));
break;
case DATA_TYPE_FLOAT:
script_context.SetResult(hook->getArgument<float>(paramIndex));
break;
case DATA_TYPE_DOUBLE:
script_context.SetResult(hook->getArgument<double>(paramIndex));
break;
case DATA_TYPE_POINTER:
script_context.SetResult(hook->getArgument<void*>(paramIndex));
break;
case DATA_TYPE_STRING:
script_context.SetResult(hook->getArgument<const char*>(paramIndex));
break;
default:
assert(!"Unknown function parameter type!");
break;
}
}
void DHookSetParam(ScriptContext& script_context)
{
auto hook = script_context.GetArgument<dyno::Hook*>(0);
auto dataType = script_context.GetArgument<DataType_t>(1);
auto paramIndex = script_context.GetArgument<int>(2);
if (hook == nullptr) {
script_context.ThrowNativeError("Invalid hook");
}
auto valueIndex = 3;
switch (dataType) {
case DATA_TYPE_BOOL:
hook->setArgument(paramIndex, script_context.GetArgument<bool>(valueIndex));
break;
case DATA_TYPE_CHAR:
hook->setArgument(paramIndex, script_context.GetArgument<char>(valueIndex));
break;
case DATA_TYPE_UCHAR:
hook->setArgument(paramIndex, script_context.GetArgument<unsigned char>(valueIndex));
break;
case DATA_TYPE_SHORT:
hook->setArgument(paramIndex, script_context.GetArgument<short>(valueIndex));
break;
case DATA_TYPE_USHORT:
hook->setArgument(paramIndex, script_context.GetArgument<unsigned short>(valueIndex));
break;
case DATA_TYPE_INT:
hook->setArgument(paramIndex, script_context.GetArgument<int>(valueIndex));
break;
case DATA_TYPE_UINT:
hook->setArgument(paramIndex, script_context.GetArgument<unsigned int>(valueIndex));
break;
case DATA_TYPE_LONG:
hook->setArgument(paramIndex, script_context.GetArgument<long>(valueIndex));
break;
case DATA_TYPE_ULONG:
hook->setArgument(paramIndex, script_context.GetArgument<unsigned long>(valueIndex));
break;
case DATA_TYPE_LONG_LONG:
hook->setArgument(paramIndex, script_context.GetArgument<long long>(valueIndex));
break;
case DATA_TYPE_ULONG_LONG:
hook->setArgument(paramIndex, script_context.GetArgument<unsigned long long>(valueIndex));
break;
case DATA_TYPE_FLOAT:
hook->setArgument(paramIndex, script_context.GetArgument<float>(valueIndex));
break;
case DATA_TYPE_DOUBLE:
hook->setArgument(paramIndex, script_context.GetArgument<double>(valueIndex));
break;
case DATA_TYPE_POINTER:
hook->setArgument(paramIndex, script_context.GetArgument<void*>(valueIndex));
break;
case DATA_TYPE_STRING:
hook->setArgument(paramIndex, script_context.GetArgument<const char*>(valueIndex));
break;
default:
assert(!"Unknown function parameter type!");
break;
}
}
REGISTER_NATIVES(dynamichooks, {
ScriptEngine::RegisterNativeHandler("DYNAMIC_HOOK_GET_RETURN", DHookGetReturn);
ScriptEngine::RegisterNativeHandler("DYNAMIC_HOOK_SET_RETURN", DHookSetReturn);
ScriptEngine::RegisterNativeHandler("DYNAMIC_HOOK_GET_PARAM", DHookGetParam);
ScriptEngine::RegisterNativeHandler("DYNAMIC_HOOK_SET_PARAM", DHookSetParam);
})
} // namespace counterstrikesharp

View File

@@ -0,0 +1,4 @@
DYNAMIC_HOOK_GET_RETURN: hook:pointer, datatype:int -> any
DYNAMIC_HOOK_SET_RETURN: hook:pointer, datatype:int, value:any -> void
DYNAMIC_HOOK_GET_PARAM: hook:pointer, datatype:int, paramIndex:int -> any
DYNAMIC_HOOK_SET_PARAM: hook:pointer, datatype:int, paramIndex:int, value:any -> void

View File

@@ -24,11 +24,12 @@
#include "core/log.h"
namespace counterstrikesharp {
std::vector<ValveFunction *> m_managed_ptrs;
std::vector<ValveFunction*> m_managed_ptrs;
byte *ConvertToByteArray(const char *str, size_t *outLength) {
size_t len = strlen(str) / 4; // Every byte is represented as \xHH
byte *result = (byte *)malloc(len);
byte* ConvertToByteArray(const char* str, size_t* outLength)
{
size_t len = strlen(str) / 4; // Every byte is represented as \xHH
byte* result = (byte*)malloc(len);
for (size_t i = 0, j = 0; i < len; ++i, j += 4) {
sscanf(str + j, "\\x%2hhx", &result[i]);
@@ -38,24 +39,26 @@ byte *ConvertToByteArray(const char *str, size_t *outLength) {
return result;
}
void *FindSignatureNative(ScriptContext &scriptContext) {
auto moduleName = scriptContext.GetArgument<const char *>(0);
auto bytesStr = scriptContext.GetArgument<const char *>(1);
void* FindSignatureNative(ScriptContext& scriptContext)
{
auto moduleName = scriptContext.GetArgument<const char*>(0);
auto bytesStr = scriptContext.GetArgument<const char*>(1);
return FindSignature(moduleName, bytesStr);
}
ValveFunction *CreateVirtualFunctionBySignature(ScriptContext &script_context) {
ValveFunction* CreateVirtualFunctionBySignature(ScriptContext& script_context)
{
auto ptr = script_context.GetArgument<unsigned long>(0);
auto binary_name = script_context.GetArgument<const char *>(1);
auto signature_hex_string = script_context.GetArgument<const char *>(2);
auto binary_name = script_context.GetArgument<const char*>(1);
auto signature_hex_string = script_context.GetArgument<const char*>(2);
auto num_arguments = script_context.GetArgument<int>(3);
auto return_type = script_context.GetArgument<DataType_t>(4);
auto* function_addr = FindSignature(binary_name, signature_hex_string);
if (function_addr == nullptr) {
script_context.ThrowNativeError("Could not find signature");
script_context.ThrowNativeError("Could not find signature %s", signature_hex_string);
return nullptr;
}
@@ -67,19 +70,21 @@ ValveFunction *CreateVirtualFunctionBySignature(ScriptContext &script_context) {
auto function = new ValveFunction(function_addr, CONV_CDECL, args, return_type);
function->SetSignature(signature_hex_string);
CSSHARP_CORE_TRACE("Created virtual function, pointer found at {}, signature {}", function_addr, signature_hex_string);
CSSHARP_CORE_TRACE("Created virtual function, pointer found at {}, signature {}", function_addr,
signature_hex_string);
m_managed_ptrs.push_back(function);
return function;
}
ValveFunction *CreateVirtualFunction(ScriptContext &script_context) {
auto ptr = script_context.GetArgument<void *>(0);
ValveFunction* CreateVirtualFunction(ScriptContext& script_context)
{
auto ptr = script_context.GetArgument<void*>(0);
auto vtable_offset = script_context.GetArgument<int>(1);
auto num_arguments = script_context.GetArgument<int>(2);
auto return_type = script_context.GetArgument<DataType_t>(3);
void **vtable = *(void ***)ptr;
void** vtable = *(void***)ptr;
if (!vtable) {
script_context.ThrowNativeError("Failed to get the virtual function table.");
return nullptr;
@@ -99,8 +104,37 @@ ValveFunction *CreateVirtualFunction(ScriptContext &script_context) {
return function;
}
void ExecuteVirtualFunction(ScriptContext &script_context) {
auto function = script_context.GetArgument<ValveFunction *>(0);
void HookFunction(ScriptContext& script_context)
{
auto function = script_context.GetArgument<ValveFunction*>(0);
auto callback = script_context.GetArgument<CallbackT>(1);
auto post = script_context.GetArgument<bool>(2);
if (!function) {
script_context.ThrowNativeError("Invalid function pointer");
return;
}
function->AddHook(callback, post);
}
void UnhookFunction(ScriptContext& script_context)
{
auto function = script_context.GetArgument<ValveFunction*>(0);
auto callback = script_context.GetArgument<CallbackT>(1);
auto post = script_context.GetArgument<bool>(2);
if (!function) {
script_context.ThrowNativeError("Invalid function pointer");
return;
}
function->RemoveHook(callback, post);
}
void ExecuteVirtualFunction(ScriptContext& script_context)
{
auto function = script_context.GetArgument<ValveFunction*>(0);
if (!function) {
script_context.ThrowNativeError("Invalid function pointer");
@@ -110,41 +144,15 @@ void ExecuteVirtualFunction(ScriptContext &script_context) {
function->Call(script_context, 1);
}
// void HookFunction(ScriptContext& script_context) {
// auto function = script_context.GetArgument<ValveFunction*>(0);
// auto entity_index = script_context.GetArgument<int>(1);
// auto post = script_context.GetArgument<bool>(2);
// auto callback = script_context.GetArgument<CallbackT>(3);
//
// if (!function) {
// script_context.ThrowNativeError("Invalid function pointer");
// return;
// }
//
// globals::hook_manager.AddHook(function, entity_index, callback, post);
// }
//
// void UnhookFunction(ScriptContext& script_context) {
// auto function = script_context.GetArgument<ValveFunction*>(0);
// auto entity_index = script_context.GetArgument<int>(1);
// auto post = script_context.GetArgument<bool>(2);
// auto callback = script_context.GetArgument<CallbackT>(3);
//
// if (!function) {
// script_context.ThrowNativeError("Invalid function pointer");
// return;
// }
//
// globals::hook_manager.Unhook(function, entity_index, callback, post);
// }
int GetNetworkVectorSize(ScriptContext &script_context) {
int GetNetworkVectorSize(ScriptContext& script_context)
{
auto vec = script_context.GetArgument<CUtlVector<void*>*>(0);
return vec->Count();
}
void* GetNetworkVectorElementAt(ScriptContext &script_context) {
void* GetNetworkVectorElementAt(ScriptContext& script_context)
{
auto vec = script_context.GetArgument<CUtlVector<CEntityHandle>*>(0);
auto index = script_context.GetArgument<int>(1);
@@ -156,10 +164,10 @@ REGISTER_NATIVES(memory, {
ScriptEngine::RegisterNativeHandler("CREATE_VIRTUAL_FUNCTION_BY_SIGNATURE",
CreateVirtualFunctionBySignature);
ScriptEngine::RegisterNativeHandler("EXECUTE_VIRTUAL_FUNCTION", ExecuteVirtualFunction);
// ScriptEngine::RegisterNativeHandler("HOOK_FUNCTION", HookFunction);
// ScriptEngine::RegisterNativeHandler("UNHOOK_FUNCTION", UnhookFunction);
ScriptEngine::RegisterNativeHandler("HOOK_FUNCTION", HookFunction);
ScriptEngine::RegisterNativeHandler("UNHOOK_FUNCTION", UnhookFunction);
ScriptEngine::RegisterNativeHandler("FIND_SIGNATURE", FindSignatureNative);
ScriptEngine::RegisterNativeHandler("GET_NETWORK_VECTOR_SIZE", GetNetworkVectorSize);
ScriptEngine::RegisterNativeHandler("GET_NETWORK_VECTOR_ELEMENT_AT", GetNetworkVectorElementAt);
})
} // namespace counterstrikesharp
} // namespace counterstrikesharp

View File

@@ -1,5 +1,7 @@
CREATE_VIRTUAL_FUNCTION: pointer:pointer,vtableOffset:int,numArguments:int,returnType:int,arguments:object[] -> pointer
CREATE_VIRTUAL_FUNCTION_BY_SIGNATURE: pointer:pointer,binaryName:string,signature:string,numArguments:int,returnType:int,arguments:object[] -> pointer
HOOK_FUNCTION: function:pointer, hook:callback, post:bool -> void
UNHOOK_FUNCTION: function:pointer, hook:callback, post:bool -> void
EXECUTE_VIRTUAL_FUNCTION: function:pointer,arguments:object[] -> any
FIND_SIGNATURE: modulePath:string, signature:string -> pointer
GET_NETWORK_VECTOR_SIZE: vec:pointer -> int