summaryrefslogtreecommitdiff
path: root/sourcemod/scripting/momsurffix
diff options
context:
space:
mode:
Diffstat (limited to 'sourcemod/scripting/momsurffix')
-rw-r--r--sourcemod/scripting/momsurffix/baseplayer.sp189
-rw-r--r--sourcemod/scripting/momsurffix/gamemovement.sp411
-rw-r--r--sourcemod/scripting/momsurffix/gametrace.sp480
-rw-r--r--sourcemod/scripting/momsurffix/utils.sp279
4 files changed, 1359 insertions, 0 deletions
diff --git a/sourcemod/scripting/momsurffix/baseplayer.sp b/sourcemod/scripting/momsurffix/baseplayer.sp
new file mode 100644
index 0000000..c638773
--- /dev/null
+++ b/sourcemod/scripting/momsurffix/baseplayer.sp
@@ -0,0 +1,189 @@
+#define MAX_EDICT_BITS 11
+#define NUM_ENT_ENTRY_BITS (MAX_EDICT_BITS + 1)
+#define NUM_ENT_ENTRIES (1 << NUM_ENT_ENTRY_BITS)
+#define ENT_ENTRY_MASK (NUM_ENT_ENTRIES - 1)
+#define INVALID_EHANDLE_INDEX 0xFFFFFFFF
+
+enum struct CBasePlayerOffsets
+{
+ //...
+ int m_surfaceFriction;
+ //...
+ int m_hGroundEntity;
+ //...
+ int m_MoveType;
+ //...
+}
+
+enum struct CBaseHandleOffsets
+{
+ int m_Index;
+}
+
+enum struct CEntInfoOffsets
+{
+ int m_pEntity;
+ int m_SerialNumber;
+ //...
+ int size;
+}
+
+enum struct CBaseEntityListOffsets
+{
+ int m_EntPtrArray;
+}
+
+enum struct BasePlayerOffsets
+{
+ CBasePlayerOffsets cbpoffsets;
+ CBaseHandleOffsets cbhoffsets;
+ CEntInfoOffsets ceioffsets;
+ CBaseEntityListOffsets cbeloffsets;
+}
+static BasePlayerOffsets offsets;
+
+methodmap CBasePlayer < AddressBase
+{
+ property float m_surfaceFriction
+ {
+ public get() { return view_as<float>(LoadFromAddress(this.Address + offsets.cbpoffsets.m_surfaceFriction, NumberType_Int32)); }
+ }
+
+ //...
+
+ property Address m_hGroundEntity
+ {
+ public get() { return view_as<Address>(LoadFromAddress(this.Address + offsets.cbpoffsets.m_hGroundEntity, NumberType_Int32)); }
+ }
+
+ //...
+
+ property MoveType m_MoveType
+ {
+ public get() { return view_as<MoveType>(LoadFromAddress(this.Address + offsets.cbpoffsets.m_MoveType, NumberType_Int8)); }
+ }
+}
+
+methodmap CBaseEntityList < AddressBase
+{
+ property PseudoStackArray m_EntPtrArray
+ {
+ public get() { return view_as<PseudoStackArray>(LoadFromAddress(this.Address + offsets.cbeloffsets.m_EntPtrArray, NumberType_Int32)); }
+ }
+}
+
+static CBaseEntityList g_pEntityList;
+
+methodmap CBaseHandle < AddressBase
+{
+ property int m_Index
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cbhoffsets.m_Index, NumberType_Int32); }
+ }
+
+ public CBaseHandle Get()
+ {
+ return LookupEntity(this);
+ }
+
+ public int GetEntryIndex()
+ {
+ return
+ }
+}
+
+methodmap CEntInfo < AddressBase
+{
+ public static int Size()
+ {
+ return offsets.ceioffsets.size;
+ }
+
+ property CBaseHandle m_pEntity
+ {
+ public get() { return view_as<CBaseHandle>(LoadFromAddress(this.Address + offsets.ceioffsets.m_pEntity, NumberType_Int32)); }
+ }
+
+ property int m_SerialNumber
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.ceioffsets.m_SerialNumber, NumberType_Int32); }
+ }
+}
+
+stock bool InitBasePlayer(GameData gd)
+{
+ char buff[128];
+ bool early = false;
+
+ if(gEngineVersion == Engine_CSS)
+ {
+ //g_pEntityList
+ g_pEntityList = view_as<CBaseEntityList>(gd.GetAddress("g_pEntityList"));
+ ASSERT_MSG(g_pEntityList.Address != Address_Null, "Can't get \"g_pEntityList\" address from gamedata. Gamedata needs an update.");
+
+ //CBaseEntityList
+ ASSERT_FMT(gd.GetKeyValue("CBaseEntityList::m_EntPtrArray", buff, sizeof(buff)), "Can't get \"CBaseEntityList::m_EntPtrArray\" offset from gamedata.");
+ offsets.cbeloffsets.m_EntPtrArray = StringToInt(buff);
+
+ //CEntInfo
+ ASSERT_FMT(gd.GetKeyValue("CEntInfo::m_pEntity", buff, sizeof(buff)), "Can't get \"CEntInfo::m_pEntity\" offset from gamedata.");
+ offsets.ceioffsets.m_pEntity = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CEntInfo::m_SerialNumber", buff, sizeof(buff)), "Can't get \"CEntInfo::m_SerialNumber\" offset from gamedata.");
+ offsets.ceioffsets.m_SerialNumber = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CEntInfo::size", buff, sizeof(buff)), "Can't get \"CEntInfo::size\" offset from gamedata.");
+ offsets.ceioffsets.size = StringToInt(buff);
+
+ //CBaseHandle
+ ASSERT_FMT(gd.GetKeyValue("CBaseHandle::m_Index", buff, sizeof(buff)), "Can't get \"CBaseHandle::m_Index\" offset from gamedata.");
+ offsets.cbhoffsets.m_Index = StringToInt(buff);
+
+ //CBasePlayer
+ ASSERT_FMT(gd.GetKeyValue("CBasePlayer::m_surfaceFriction", buff, sizeof(buff)), "Can't get \"CBasePlayer::m_surfaceFriction\" offset from gamedata.");
+ int offs = StringToInt(buff);
+ int prop_offs = FindSendPropInfo("CBasePlayer", "m_szLastPlaceName");
+ ASSERT_FMT(prop_offs > 0, "Can't get \"CBasePlayer::m_szLastPlaceName\" offset from FindSendPropInfo().");
+ offsets.cbpoffsets.m_surfaceFriction = prop_offs + offs;
+ }
+ else if(gEngineVersion == Engine_CSGO)
+ {
+ //CBasePlayer
+ ASSERT_FMT(gd.GetKeyValue("CBasePlayer::m_surfaceFriction", buff, sizeof(buff)), "Can't get \"CBasePlayer::m_surfaceFriction\" offset from gamedata.");
+ int offs = StringToInt(buff);
+ int prop_offs = FindSendPropInfo("CBasePlayer", "m_ubEFNoInterpParity");
+ ASSERT_FMT(prop_offs > 0, "Can't get \"CBasePlayer::m_ubEFNoInterpParity\" offset from FindSendPropInfo().");
+ offsets.cbpoffsets.m_surfaceFriction = prop_offs - offs;
+ }
+
+ offsets.cbpoffsets.m_hGroundEntity = FindSendPropInfo("CBasePlayer", "m_hGroundEntity");
+ ASSERT_FMT(offsets.cbpoffsets.m_hGroundEntity > 0, "Can't get \"CBasePlayer::m_hGroundEntity\" offset from FindSendPropInfo().");
+
+ if(IsValidEntity(0))
+ {
+ offsets.cbpoffsets.m_MoveType = FindDataMapInfo(0, "m_MoveType");
+ ASSERT_FMT(offsets.cbpoffsets.m_MoveType != -1, "Can't get \"CBasePlayer::m_MoveType\" offset from FindDataMapInfo().");
+ }
+ else
+ early = true;
+
+ return early;
+}
+
+stock void LateInitBasePlayer(GameData gd)
+{
+ ASSERT(IsValidEntity(0));
+ offsets.cbpoffsets.m_MoveType = FindDataMapInfo(0, "m_MoveType");
+ ASSERT_FMT(offsets.cbpoffsets.m_MoveType != -1, "Can't get \"CBasePlayer::m_MoveType\" offset from FindDataMapInfo().");
+}
+
+stock CBaseHandle LookupEntity(CBaseHandle handle)
+{
+ if(handle.m_Index == INVALID_EHANDLE_INDEX)
+ return view_as<CBaseHandle>(0);
+
+ CEntInfo pInfo = view_as<CEntInfo>(g_pEntityList.m_EntPtrArray.Get32(handle.m_Index & ENT_ENTRY_MASK, CEntInfo.Size()));
+
+ if(pInfo.m_SerialNumber == (handle.m_Index >> NUM_ENT_ENTRY_BITS))
+ return pInfo.m_pEntity;
+ else
+ return view_as<CBaseHandle>(0);
+} \ No newline at end of file
diff --git a/sourcemod/scripting/momsurffix/gamemovement.sp b/sourcemod/scripting/momsurffix/gamemovement.sp
new file mode 100644
index 0000000..a51beeb
--- /dev/null
+++ b/sourcemod/scripting/momsurffix/gamemovement.sp
@@ -0,0 +1,411 @@
+enum struct CGameMovementOffsets
+{
+ int player;
+ int mv;
+ //...
+ int m_pTraceListData;
+ int m_nTraceCount;
+}
+
+enum struct CMoveDataOffsets
+{
+ int m_nPlayerHandle;
+ //...
+ int m_vecVelocity;
+ //...
+ int m_vecAbsOrigin;
+}
+
+enum struct GameMoventOffsets
+{
+ CGameMovementOffsets cgmoffsets;
+ CMoveDataOffsets cmdoffsets;
+}
+static GameMoventOffsets offsets;
+
+methodmap CMoveData < AddressBase
+{
+ property CBaseHandle m_nPlayerHandle
+ {
+ public get() { return view_as<CBaseHandle>(this.Address + offsets.cmdoffsets.m_nPlayerHandle); }
+ }
+
+ //...
+
+ property Vector m_vecVelocity
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.cmdoffsets.m_vecVelocity); }
+ }
+
+ //...
+
+ property Vector m_vecAbsOrigin
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.cmdoffsets.m_vecAbsOrigin); }
+ }
+}
+
+methodmap CGameMovement < AddressBase
+{
+ property CBasePlayer player
+ {
+ public get() { return view_as<CBasePlayer>(LoadFromAddress(this.Address + offsets.cgmoffsets.player, NumberType_Int32)); }
+ }
+
+ property CMoveData mv
+ {
+ public get() { return view_as<CMoveData>(LoadFromAddress(this.Address + offsets.cgmoffsets.mv, NumberType_Int32)); }
+ }
+
+ //...
+
+ property ITraceListData m_pTraceListData
+ {
+ public get() { return view_as<ITraceListData>(LoadFromAddress(this.Address + offsets.cgmoffsets.m_pTraceListData, NumberType_Int32)); }
+ }
+
+ property int m_nTraceCount
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cgmoffsets.m_nTraceCount, NumberType_Int32); }
+ public set(int _tracecount) { StoreToAddress(this.Address + offsets.cgmoffsets.m_nTraceCount, _tracecount, NumberType_Int32, false); }
+ }
+}
+
+static Handle gAddToTouched;
+
+methodmap IMoveHelper < AddressBase
+{
+ public bool AddToTouched(CGameTrace trace, Vector vec)
+ {
+ return SDKCall(gAddToTouched, this.Address, trace, vec);
+ }
+}
+
+enum //Collision_Group_t
+{
+ COLLISION_GROUP_NONE = 0,
+ COLLISION_GROUP_DEBRIS, // Collides with nothing but world and static stuff
+ COLLISION_GROUP_DEBRIS_TRIGGER, // Same as debris, but hits triggers
+ COLLISION_GROUP_INTERACTIVE_DEBRIS, // Collides with everything except other interactive debris or debris
+ COLLISION_GROUP_INTERACTIVE, // Collides with everything except interactive debris or debris
+ COLLISION_GROUP_PLAYER,
+ COLLISION_GROUP_BREAKABLE_GLASS,
+ COLLISION_GROUP_VEHICLE,
+ COLLISION_GROUP_PLAYER_MOVEMENT, // For HL2, same as Collision_Group_Player, for
+ // TF2, this filters out other players and CBaseObjects
+ COLLISION_GROUP_NPC, // Generic NPC group
+ COLLISION_GROUP_IN_VEHICLE, // for any entity inside a vehicle
+ COLLISION_GROUP_WEAPON, // for any weapons that need collision detection
+ COLLISION_GROUP_VEHICLE_CLIP, // vehicle clip brush to restrict vehicle movement
+ COLLISION_GROUP_PROJECTILE, // Projectiles!
+ COLLISION_GROUP_DOOR_BLOCKER, // Blocks entities not permitted to get near moving doors
+ COLLISION_GROUP_PASSABLE_DOOR, // Doors that the player shouldn't collide with
+ COLLISION_GROUP_DISSOLVING, // Things that are dissolving are in this group
+ COLLISION_GROUP_PUSHAWAY, // Nonsolid on client and server, pushaway in player code
+
+ COLLISION_GROUP_NPC_ACTOR, // Used so NPCs in scripts ignore the player.
+ COLLISION_GROUP_NPC_SCRIPTED, // USed for NPCs in scripts that should not collide with each other
+
+ LAST_SHARED_COLLISION_GROUP
+};
+
+static Handle gClipVelocity, gLockTraceFilter, gUnlockTraceFilter, gGetPlayerMins, gGetPlayerMaxs, gTracePlayerBBox;
+static IMoveHelper sm_pSingleton;
+
+stock void InitGameMovement(GameData gd)
+{
+ char buff[128];
+
+ //CGameMovement
+ ASSERT_FMT(gd.GetKeyValue("CGameMovement::player", buff, sizeof(buff)), "Can't get \"CGameMovement::player\" offset from gamedata.");
+ offsets.cgmoffsets.player = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameMovement::mv", buff, sizeof(buff)), "Can't get \"CGameMovement::mv\" offset from gamedata.");
+ offsets.cgmoffsets.mv = StringToInt(buff);
+
+ if(gEngineVersion == Engine_CSGO)
+ {
+ ASSERT_FMT(gd.GetKeyValue("CGameMovement::m_pTraceListData", buff, sizeof(buff)), "Can't get \"CGameMovement::m_pTraceListData\" offset from gamedata.");
+ offsets.cgmoffsets.m_pTraceListData = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameMovement::m_nTraceCount", buff, sizeof(buff)), "Can't get \"CGameMovement::m_nTraceCount\" offset from gamedata.");
+ offsets.cgmoffsets.m_nTraceCount = StringToInt(buff);
+ }
+
+ //CMoveData
+ if(gEngineVersion == Engine_CSS)
+ {
+ ASSERT_FMT(gd.GetKeyValue("CMoveData::m_nPlayerHandle", buff, sizeof(buff)), "Can't get \"CMoveData::m_nPlayerHandle\" offset from gamedata.");
+ offsets.cmdoffsets.m_nPlayerHandle = StringToInt(buff);
+ }
+
+ ASSERT_FMT(gd.GetKeyValue("CMoveData::m_vecVelocity", buff, sizeof(buff)), "Can't get \"CMoveData::m_vecVelocity\" offset from gamedata.");
+ offsets.cmdoffsets.m_vecVelocity = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CMoveData::m_vecAbsOrigin", buff, sizeof(buff)), "Can't get \"CMoveData::m_vecAbsOrigin\" offset from gamedata.");
+ offsets.cmdoffsets.m_vecAbsOrigin = StringToInt(buff);
+
+ if(gEngineVersion == Engine_CSGO)
+ {
+ //sm_pSingleton
+ sm_pSingleton = view_as<IMoveHelper>(gd.GetAddress("sm_pSingleton"));
+ ASSERT_MSG(sm_pSingleton.Address != Address_Null, "Can't get \"sm_pSingleton\" address from gamedata. Gamedata needs an update.");
+ }
+ else
+ {
+ //sm_pSingleton for late loading
+ sm_pSingleton = view_as<IMoveHelper>(gd.GetAddress("sm_pSingleton"));
+
+ //CMoveHelperServer::CMoveHelperServer
+ Handle dhook = DHookCreateDetour(Address_Null, CallConv_CDECL, ReturnType_Int, ThisPointer_Ignore);
+ ASSERT_MSG(DHookSetFromConf(dhook, gd, SDKConf_Signature, "CMoveHelperServer::CMoveHelperServer"), "Failed to get \"CMoveHelperServer::CMoveHelperServer\" signature. Gamedata needs an update.");
+ DHookAddParam(dhook, HookParamType_Int);
+ DHookEnableDetour(dhook, true, CMoveHelperServer_Dhook);
+ }
+
+ //AddToTouched
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("AddToTouched"));
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain);
+
+ gAddToTouched = EndPrepSDKCall();
+ ASSERT(gAddToTouched);
+
+ if(gEngineVersion == Engine_CSGO)
+ {
+ //ClipVelocity
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("ClipVelocity"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gClipVelocity = EndPrepSDKCall();
+ ASSERT(gClipVelocity);
+
+ //LockTraceFilter
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("LockTraceFilter"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gLockTraceFilter = EndPrepSDKCall();
+ ASSERT(gLockTraceFilter);
+
+ //UnlockTraceFilter
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("UnlockTraceFilter"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer);
+
+ gUnlockTraceFilter = EndPrepSDKCall();
+ ASSERT(gUnlockTraceFilter);
+ }
+ else if(gEngineVersion == Engine_CSS && gOSType == OSLinux)
+ {
+ //ClipVelocity
+ StartPrepSDKCall(SDKCall_Static);
+
+ ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CGameMovement::ClipVelocity"), "Failed to get \"CGameMovement::ClipVelocity\" signature. Gamedata needs an update.");
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gClipVelocity = EndPrepSDKCall();
+ ASSERT(gClipVelocity);
+ }
+
+ if(gEngineVersion == Engine_CSGO || gOSType == OSWindows)
+ {
+ //GetPlayerMins
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("GetPlayerMins"));
+
+ if(gEngineVersion == Engine_CSS)
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gGetPlayerMins = EndPrepSDKCall();
+ ASSERT(gGetPlayerMins);
+
+ //GetPlayerMaxs
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("GetPlayerMaxs"));
+
+ if(gEngineVersion == Engine_CSS)
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gGetPlayerMaxs = EndPrepSDKCall();
+ ASSERT(gGetPlayerMaxs);
+ }
+ else
+ {
+ //GetPlayerMins
+ StartPrepSDKCall(SDKCall_Static);
+
+ ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CGameMovement::GetPlayerMins"), "Failed to get \"CGameMovement::GetPlayerMins\" signature. Gamedata needs an update.");
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gGetPlayerMins = EndPrepSDKCall();
+ ASSERT(gGetPlayerMins);
+
+ //GetPlayerMaxs
+ StartPrepSDKCall(SDKCall_Static);
+
+ ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CGameMovement::GetPlayerMaxs"), "Failed to get \"CGameMovement::GetPlayerMaxs\" signature. Gamedata needs an update.");
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gGetPlayerMaxs = EndPrepSDKCall();
+ ASSERT(gGetPlayerMaxs);
+ }
+
+ //TracePlayerBBox
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("TracePlayerBBox"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gTracePlayerBBox = EndPrepSDKCall();
+ ASSERT(gTracePlayerBBox);
+}
+
+public MRESReturn CMoveHelperServer_Dhook(Handle hReturn, Handle hParams)
+{
+ if(sm_pSingleton.Address == Address_Null)
+ {
+ if(gOSType == OSLinux)
+ {
+ GameData gd = new GameData(GAME_DATA_FILE);
+
+ sm_pSingleton = view_as<IMoveHelper>(gd.GetAddress("sm_pSingleton"));
+ ASSERT_MSG(sm_pSingleton.Address != Address_Null, "Can't get \"sm_pSingleton\" address from gamedata. Gamedata needs an update.");
+
+ delete gd;
+ }
+ else
+ {
+ sm_pSingleton = view_as<IMoveHelper>(DHookGetReturn(hReturn));
+ ASSERT_MSG(sm_pSingleton.Address != Address_Null, "Can't get \"sm_pSingleton\" address from \"CMoveHelperServer::CMoveHelperServer\" dhook.");
+ }
+ }
+
+ return MRES_Ignored;
+}
+
+stock void TracePlayerBBox(CGameMovement pThis, Vector start, Vector end, int mask, int collisionGroup, CGameTrace trace)
+{
+ SDKCall(gTracePlayerBBox, pThis, start, end, mask, collisionGroup, trace);
+}
+
+stock CTraceFilterSimple LockTraceFilter(CGameMovement pThis, int collisionGroup)
+{
+ ASSERT(pThis.Address != Address_Null);
+ return SDKCall(gLockTraceFilter, pThis.Address, collisionGroup);
+}
+
+stock void UnlockTraceFilter(CGameMovement pThis, CTraceFilterSimple filter)
+{
+ ASSERT(pThis.Address != Address_Null);
+ SDKCall(gUnlockTraceFilter, pThis.Address, filter.Address);
+}
+
+stock int ClipVelocity(CGameMovement pThis, Vector invec, Vector normal, Vector out, float overbounce)
+{
+ if(gEngineVersion == Engine_CSGO)
+ {
+ ASSERT(pThis.Address != Address_Null);
+ return SDKCall(gClipVelocity, pThis.Address, invec.Address, normal.Address, out.Address, overbounce);
+ }
+ else if (gEngineVersion == Engine_CSS && gOSType == OSLinux)
+ {
+ return SDKCall(gClipVelocity, pThis.Address, invec.Address, normal.Address, out.Address, overbounce);
+ }
+ else
+ {
+ float backoff, angle, adjust;
+ int blocked;
+
+ angle = normal.z;
+
+ if(angle > 0.0)
+ blocked |= 0x01;
+ if(CloseEnoughFloat(angle, 0.0))
+ blocked |= 0x02;
+
+ backoff = invec.Dot(VectorToArray(normal)) * overbounce;
+
+ out.x = invec.x - (normal.x * backoff);
+ out.y = invec.y - (normal.y * backoff);
+ out.z = invec.z - (normal.z * backoff);
+
+ adjust = out.Dot(VectorToArray(normal));
+ if(adjust < 0.0)
+ {
+ out.x -= (normal.x * adjust);
+ out.y -= (normal.y * adjust);
+ out.z -= (normal.z * adjust);
+ }
+
+ return blocked;
+ }
+}
+
+stock Vector GetPlayerMinsCSS(CGameMovement pThis, Vector vec)
+{
+ if(gOSType == OSLinux)
+ {
+ SDKCall(gGetPlayerMins, vec.Address, pThis.Address);
+ return vec;
+ }
+ else
+ return SDKCall(gGetPlayerMins, pThis.Address, vec.Address);
+}
+
+stock Vector GetPlayerMaxsCSS(CGameMovement pThis, Vector vec)
+{
+ if(gOSType == OSLinux)
+ {
+ SDKCall(gGetPlayerMaxs, vec.Address, pThis.Address);
+ return vec;
+ }
+ else
+ return SDKCall(gGetPlayerMaxs, pThis.Address, vec.Address);
+}
+
+stock Vector GetPlayerMins(CGameMovement pThis)
+{
+ return SDKCall(gGetPlayerMins, pThis.Address);
+}
+
+stock Vector GetPlayerMaxs(CGameMovement pThis)
+{
+ return SDKCall(gGetPlayerMaxs, pThis.Address);
+}
+
+stock IMoveHelper MoveHelper()
+{
+ return sm_pSingleton;
+} \ No newline at end of file
diff --git a/sourcemod/scripting/momsurffix/gametrace.sp b/sourcemod/scripting/momsurffix/gametrace.sp
new file mode 100644
index 0000000..e8db1ad
--- /dev/null
+++ b/sourcemod/scripting/momsurffix/gametrace.sp
@@ -0,0 +1,480 @@
+enum struct cplane_tOffsets
+{
+ int normal;
+ int dist;
+ int type;
+ int signbits;
+}
+
+enum struct csurface_tOffsets
+{
+ int name;
+ int surfaceProps;
+ int flags;
+}
+
+enum struct CGameTraceOffsets
+{
+ //CBaseTrace
+ int startpos;
+ int endpos;
+ int plane;
+ int fraction;
+ int contents;
+ int dispFlags;
+ int allsolid;
+ int startsolid;
+ //CGameTrace
+ int fractionleftsolid;
+ int surface;
+ int hitgroup;
+ int physicsbone;
+ int m_pEnt;
+ int hitbox;
+ int size;
+}
+
+enum struct Ray_tOffsets
+{
+ int m_Start;
+ int m_Delta;
+ int m_StartOffset;
+ int m_Extents;
+ int m_pWorldAxisTransform;
+ int m_IsRay;
+ int m_IsSwept;
+ int size;
+}
+
+enum struct CTraceFilterSimpleOffsets
+{
+ int vptr;
+ int m_pPassEnt;
+ int m_collisionGroup;
+ int m_pExtraShouldHitCheckFunction;
+ int size;
+ Address vtable;
+}
+
+enum struct GameTraceOffsets
+{
+ cplane_tOffsets cptoffsets;
+ csurface_tOffsets cstoffsets;
+ CGameTraceOffsets cgtoffsets;
+ Ray_tOffsets rtoffsets;
+ CTraceFilterSimpleOffsets ctfsoffsets;
+}
+static GameTraceOffsets offsets;
+
+methodmap Cplane_t < AddressBase
+{
+ property Vector normal
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.cptoffsets.normal); }
+ }
+
+ property float dist
+ {
+ public get() { return view_as<float>(LoadFromAddress(this.Address + offsets.cptoffsets.dist, NumberType_Int32)); }
+ }
+
+ property char type
+ {
+ public get() { return view_as<char>(LoadFromAddress(this.Address + offsets.cptoffsets.type, NumberType_Int8)); }
+ }
+
+ property char signbits
+ {
+ public get() { return view_as<char>(LoadFromAddress(this.Address + offsets.cptoffsets.signbits, NumberType_Int8)); }
+ }
+}
+
+methodmap Csurface_t < AddressBase
+{
+ property Address name
+ {
+ public get() { return view_as<Address>(LoadFromAddress(this.Address + offsets.cstoffsets.name, NumberType_Int32)); }
+ }
+
+ property int surfaceProps
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cstoffsets.surfaceProps, NumberType_Int16); }
+ }
+
+ property int flags
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cstoffsets.flags, NumberType_Int16); }
+ }
+}
+
+methodmap CGameTrace < AllocatableBase
+{
+ public static int Size()
+ {
+ return offsets.cgtoffsets.size;
+ }
+
+ property Vector startpos
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.cgtoffsets.startpos); }
+ }
+
+ property Vector endpos
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.cgtoffsets.endpos); }
+ }
+
+ property Cplane_t plane
+ {
+ public get() { return view_as<Cplane_t>(this.Address + offsets.cgtoffsets.plane); }
+ }
+
+ property float fraction
+ {
+ public get() { return view_as<float>(LoadFromAddress(this.Address + offsets.cgtoffsets.fraction, NumberType_Int32)); }
+ }
+
+ property int contents
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cgtoffsets.contents, NumberType_Int32); }
+ }
+
+ property int dispFlags
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cgtoffsets.dispFlags, NumberType_Int16); }
+ }
+
+ property bool allsolid
+ {
+ public get() { return view_as<bool>(LoadFromAddress(this.Address + offsets.cgtoffsets.allsolid, NumberType_Int8)); }
+ }
+
+ property bool startsolid
+ {
+ public get() { return view_as<bool>(LoadFromAddress(this.Address + offsets.cgtoffsets.startsolid, NumberType_Int8)); }
+ }
+
+ property float fractionleftsolid
+ {
+ public get() { return view_as<float>(LoadFromAddress(this.Address + offsets.cgtoffsets.fractionleftsolid, NumberType_Int32)); }
+ }
+
+ property Csurface_t surface
+ {
+ public get() { return view_as<Csurface_t>(this.Address + offsets.cgtoffsets.surface); }
+ }
+
+ property int hitgroup
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cgtoffsets.hitgroup, NumberType_Int32); }
+ }
+
+ property int physicsbone
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cgtoffsets.physicsbone, NumberType_Int16); }
+ }
+
+ property Address m_pEnt
+ {
+ public get() { return view_as<Address>(LoadFromAddress(this.Address + offsets.cgtoffsets.m_pEnt, NumberType_Int32)); }
+ }
+
+ property int hitbox
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.cgtoffsets.hitbox, NumberType_Int32); }
+ }
+
+ public CGameTrace()
+ {
+ return MALLOC(CGameTrace);
+ }
+}
+
+methodmap Ray_t < AllocatableBase
+{
+ public static int Size()
+ {
+ return offsets.rtoffsets.size;
+ }
+
+ property Vector m_Start
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.rtoffsets.m_Start); }
+ }
+
+ property Vector m_Delta
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.rtoffsets.m_Delta); }
+ }
+
+ property Vector m_StartOffset
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.rtoffsets.m_StartOffset); }
+ }
+
+ property Vector m_Extents
+ {
+ public get() { return view_as<Vector>(this.Address + offsets.rtoffsets.m_Extents); }
+ }
+
+ property Address m_pWorldAxisTransform
+ {
+ public get() { return view_as<Address>(LoadFromAddress(this.Address + offsets.rtoffsets.m_pWorldAxisTransform, NumberType_Int32)); }
+ public set(Address _worldaxistransform) { StoreToAddress(this.Address + offsets.rtoffsets.m_pWorldAxisTransform, view_as<int>(_worldaxistransform), NumberType_Int32, false); }
+ }
+
+ property bool m_IsRay
+ {
+ public get() { return view_as<bool>(LoadFromAddress(this.Address + offsets.rtoffsets.m_IsRay, NumberType_Int8)); }
+ public set(bool _isray) { StoreToAddress(this.Address + offsets.rtoffsets.m_IsRay, _isray, NumberType_Int8, false); }
+ }
+
+ property bool m_IsSwept
+ {
+ public get() { return view_as<bool>(LoadFromAddress(this.Address + offsets.rtoffsets.m_IsSwept, NumberType_Int8)); }
+ public set(bool _isswept) { StoreToAddress(this.Address + offsets.rtoffsets.m_IsSwept, _isswept, NumberType_Int8, false); }
+ }
+
+ public Ray_t()
+ {
+ return MALLOC(Ray_t);
+ }
+
+ //That function is quite heavy, linux builds have it inlined, so can't use it!
+ //Replacing this function with lighter alternative may increase speed by ~4 times!
+ //From my testings the main performance killer here is StoreToAddress()....
+ public void Init(float start[3], float end[3], float mins[3], float maxs[3])
+ {
+ float buff[3], buff2[3];
+
+ SubtractVectors(end, start, buff);
+ this.m_Delta.FromArray(buff);
+
+ if(gEngineVersion == Engine_CSGO)
+ this.m_pWorldAxisTransform = Address_Null;
+ this.m_IsSwept = (this.m_Delta.LengthSqr() != 0.0);
+
+ SubtractVectors(maxs, mins, buff);
+ ScaleVector(buff, 0.5);
+ this.m_Extents.FromArray(buff);
+
+ this.m_IsRay = (this.m_Extents.LengthSqr() < 1.0e-6);
+
+ AddVectors(mins, maxs, buff);
+ ScaleVector(buff, 0.5);
+ AddVectors(start, buff, buff2);
+ this.m_Start.FromArray(buff2);
+ NegateVector(buff);
+ this.m_StartOffset.FromArray(buff);
+ }
+}
+
+methodmap CTraceFilterSimple < AllocatableBase
+{
+ public static int Size()
+ {
+ return offsets.ctfsoffsets.size;
+ }
+
+ property Address vptr
+ {
+ public get() { return view_as<Address>(LoadFromAddress(this.Address + offsets.ctfsoffsets.vptr, NumberType_Int32)); }
+ public set(Address _vtbladdr) { StoreToAddress(this.Address + offsets.ctfsoffsets.vptr, view_as<int>(_vtbladdr), NumberType_Int32, false); }
+ }
+
+ property CBaseHandle m_pPassEnt
+ {
+ public get() { return view_as<CBaseHandle>(LoadFromAddress(this.Address + offsets.ctfsoffsets.m_pPassEnt, NumberType_Int32)); }
+ public set(CBaseHandle _passent) { StoreToAddress(this.Address + offsets.ctfsoffsets.m_pPassEnt, view_as<int>(_passent), NumberType_Int32, false); }
+ }
+
+ property int m_collisionGroup
+ {
+ public get() { return LoadFromAddress(this.Address + offsets.ctfsoffsets.m_collisionGroup, NumberType_Int32); }
+ public set(int _collisiongroup) { StoreToAddress(this.Address + offsets.ctfsoffsets.m_collisionGroup, _collisiongroup, NumberType_Int32, false); }
+ }
+
+ property Address m_pExtraShouldHitCheckFunction
+ {
+ public get() { return view_as<Address>(LoadFromAddress(this.Address + offsets.ctfsoffsets.m_pExtraShouldHitCheckFunction, NumberType_Int32)); }
+ public set(Address _checkfnc) { StoreToAddress(this.Address + offsets.ctfsoffsets.m_pExtraShouldHitCheckFunction, view_as<int>(_checkfnc), NumberType_Int32, false); }
+ }
+
+ public CTraceFilterSimple()
+ {
+ CTraceFilterSimple addr = MALLOC(CTraceFilterSimple);
+ addr.vptr = offsets.ctfsoffsets.vtable;
+ return addr;
+ }
+
+ public void Init(CBaseHandle passentity, int collisionGroup, Address pExtraShouldHitCheckFn = Address_Null)
+ {
+ this.m_pPassEnt = passentity;
+ this.m_collisionGroup = collisionGroup;
+ this.m_pExtraShouldHitCheckFunction = pExtraShouldHitCheckFn;
+ }
+}
+
+static Handle gCanTraceRay;
+
+methodmap ITraceListData < AddressBase
+{
+ public bool CanTraceRay(Ray_t ray)
+ {
+ return SDKCall(gCanTraceRay, this.Address, ray.Address);
+ }
+}
+
+static Handle gTraceRay, gTraceRayAgainstLeafAndEntityList;
+static Address gEngineTrace;
+
+stock void InitGameTrace(GameData gd)
+{
+ char buff[128];
+
+ //cplane_t
+ ASSERT_FMT(gd.GetKeyValue("cplane_t::normal", buff, sizeof(buff)), "Can't get \"cplane_t::normal\" offset from gamedata.");
+ offsets.cptoffsets.normal = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("cplane_t::dist", buff, sizeof(buff)), "Can't get \"cplane_t::dist\" offset from gamedata.");
+ offsets.cptoffsets.dist = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("cplane_t::type", buff, sizeof(buff)), "Can't get \"cplane_t::type\" offset from gamedata.");
+ offsets.cptoffsets.type = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("cplane_t::signbits", buff, sizeof(buff)), "Can't get \"cplane_t::signbits\" offset from gamedata.");
+ offsets.cptoffsets.signbits = StringToInt(buff);
+
+ //csurface_t
+ ASSERT_FMT(gd.GetKeyValue("csurface_t::name", buff, sizeof(buff)), "Can't get \"csurface_t::name\" offset from gamedata.");
+ offsets.cstoffsets.name = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("csurface_t::surfaceProps", buff, sizeof(buff)), "Can't get \"csurface_t::surfaceProps\" offset from gamedata.");
+ offsets.cstoffsets.surfaceProps = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("csurface_t::flags", buff, sizeof(buff)), "Can't get \"csurface_t::flags\" offset from gamedata.");
+ offsets.cstoffsets.flags = StringToInt(buff);
+
+ //CGameTrace
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::startpos", buff, sizeof(buff)), "Can't get \"CGameTrace::startpos\" offset from gamedata.");
+ offsets.cgtoffsets.startpos = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::endpos", buff, sizeof(buff)), "Can't get \"CGameTrace::endpos\" offset from gamedata.");
+ offsets.cgtoffsets.endpos = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::plane", buff, sizeof(buff)), "Can't get \"CGameTrace::plane\" offset from gamedata.");
+ offsets.cgtoffsets.plane = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::fraction", buff, sizeof(buff)), "Can't get \"CGameTrace::fraction\" offset from gamedata.");
+ offsets.cgtoffsets.fraction = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::contents", buff, sizeof(buff)), "Can't get \"CGameTrace::contents\" offset from gamedata.");
+ offsets.cgtoffsets.contents = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::dispFlags", buff, sizeof(buff)), "Can't get \"CGameTrace::dispFlags\" offset from gamedata.");
+ offsets.cgtoffsets.dispFlags = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::allsolid", buff, sizeof(buff)), "Can't get \"CGameTrace::allsolid\" offset from gamedata.");
+ offsets.cgtoffsets.allsolid = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::startsolid", buff, sizeof(buff)), "Can't get \"CGameTrace::startsolid\" offset from gamedata.");
+ offsets.cgtoffsets.startsolid = StringToInt(buff);
+
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::fractionleftsolid", buff, sizeof(buff)), "Can't get \"CGameTrace::fractionleftsolid\" offset from gamedata.");
+ offsets.cgtoffsets.fractionleftsolid = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::surface", buff, sizeof(buff)), "Can't get \"CGameTrace::surface\" offset from gamedata.");
+ offsets.cgtoffsets.surface = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::hitgroup", buff, sizeof(buff)), "Can't get \"CGameTrace::hitgroup\" offset from gamedata.");
+ offsets.cgtoffsets.hitgroup = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::physicsbone", buff, sizeof(buff)), "Can't get \"CGameTrace::physicsbone\" offset from gamedata.");
+ offsets.cgtoffsets.physicsbone = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::m_pEnt", buff, sizeof(buff)), "Can't get \"CGameTrace::m_pEnt\" offset from gamedata.");
+ offsets.cgtoffsets.m_pEnt = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::hitbox", buff, sizeof(buff)), "Can't get \"CGameTrace::hitbox\" offset from gamedata.");
+ offsets.cgtoffsets.hitbox = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CGameTrace::size", buff, sizeof(buff)), "Can't get \"CGameTrace::size\" offset from gamedata.");
+ offsets.cgtoffsets.size = StringToInt(buff);
+
+ //Ray_t
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_Start", buff, sizeof(buff)), "Can't get \"Ray_t::m_Start\" offset from gamedata.");
+ offsets.rtoffsets.m_Start = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_Delta", buff, sizeof(buff)), "Can't get \"Ray_t::m_Delta\" offset from gamedata.");
+ offsets.rtoffsets.m_Delta = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_StartOffset", buff, sizeof(buff)), "Can't get \"Ray_t::m_StartOffset\" offset from gamedata.");
+ offsets.rtoffsets.m_StartOffset = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_Extents", buff, sizeof(buff)), "Can't get \"Ray_t::m_Extents\" offset from gamedata.");
+ offsets.rtoffsets.m_Extents = StringToInt(buff);
+
+ if(gEngineVersion == Engine_CSGO)
+ {
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_pWorldAxisTransform", buff, sizeof(buff)), "Can't get \"Ray_t::m_pWorldAxisTransform\" offset from gamedata.");
+ offsets.rtoffsets.m_pWorldAxisTransform = StringToInt(buff);
+ }
+
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_IsRay", buff, sizeof(buff)), "Can't get \"Ray_t::m_IsRay\" offset from gamedata.");
+ offsets.rtoffsets.m_IsRay = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::m_IsSwept", buff, sizeof(buff)), "Can't get \"Ray_t::m_IsSwept\" offset from gamedata.");
+ offsets.rtoffsets.m_IsSwept = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("Ray_t::size", buff, sizeof(buff)), "Can't get \"Ray_t::size\" offset from gamedata.");
+ offsets.rtoffsets.size = StringToInt(buff);
+
+ //CTraceFilterSimple
+ ASSERT_FMT(gd.GetKeyValue("CTraceFilterSimple::vptr", buff, sizeof(buff)), "Can't get \"CTraceFilterSimple::vptr\" offset from gamedata.");
+ offsets.ctfsoffsets.vptr = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CTraceFilterSimple::m_pPassEnt", buff, sizeof(buff)), "Can't get \"CTraceFilterSimple::m_pPassEnt\" offset from gamedata.");
+ offsets.ctfsoffsets.m_pPassEnt = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CTraceFilterSimple::m_collisionGroup", buff, sizeof(buff)), "Can't get \"CTraceFilterSimple::m_collisionGroup\" offset from gamedata.");
+ offsets.ctfsoffsets.m_collisionGroup = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CTraceFilterSimple::m_pExtraShouldHitCheckFunction", buff, sizeof(buff)), "Can't get \"CTraceFilterSimple::m_pExtraShouldHitCheckFunction\" offset from gamedata.");
+ offsets.ctfsoffsets.m_pExtraShouldHitCheckFunction = StringToInt(buff);
+ ASSERT_FMT(gd.GetKeyValue("CTraceFilterSimple::size", buff, sizeof(buff)), "Can't get \"CTraceFilterSimple::size\" offset from gamedata.");
+ offsets.ctfsoffsets.size = StringToInt(buff);
+
+ if(gEngineVersion == Engine_CSS)
+ {
+ offsets.ctfsoffsets.vtable = gd.GetAddress("CTraceFilterSimple::vtable");
+ ASSERT_MSG(offsets.ctfsoffsets.vtable != Address_Null, "Can't get \"CTraceFilterSimple::vtable\" address from gamedata. Gamedata needs an update.");
+ }
+
+ //enginetrace
+ gd.GetKeyValue("CEngineTrace", buff, sizeof(buff));
+ gEngineTrace = CreateInterface(buff);
+ ASSERT_MSG(gEngineTrace != Address_Null, "Can't create \"enginetrace\" from CreateInterface().");
+
+ //RayTrace
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("TraceRay"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gTraceRay = EndPrepSDKCall();
+ ASSERT(gTraceRay);
+
+ if(gEngineVersion == Engine_CSGO)
+ {
+ //TraceRayAgainstLeafAndEntityList
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("TraceRayAgainstLeafAndEntityList"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gTraceRayAgainstLeafAndEntityList = EndPrepSDKCall();
+ ASSERT(gTraceRayAgainstLeafAndEntityList);
+
+ //CanTraceRay
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("CanTraceRay"));
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain);
+
+ gCanTraceRay = EndPrepSDKCall();
+ ASSERT(gCanTraceRay);
+ }
+}
+
+stock void TraceRayAgainstLeafAndEntityList(Ray_t ray, ITraceListData traceData, int mask, CTraceFilterSimple filter, CGameTrace trace)
+{
+ SDKCall(gTraceRayAgainstLeafAndEntityList, gEngineTrace, ray.Address, traceData.Address, mask, filter.Address, trace.Address);
+}
+
+stock void TraceRay(Ray_t ray, int mask, CTraceFilterSimple filter, CGameTrace trace)
+{
+ SDKCall(gTraceRay, gEngineTrace, ray.Address, mask, filter.Address, trace.Address);
+}
diff --git a/sourcemod/scripting/momsurffix/utils.sp b/sourcemod/scripting/momsurffix/utils.sp
new file mode 100644
index 0000000..e68e342
--- /dev/null
+++ b/sourcemod/scripting/momsurffix/utils.sp
@@ -0,0 +1,279 @@
+#define MALLOC(%1) view_as<%1>(AllocatableBase._malloc(%1.Size(), #%1))
+#define MEMORYPOOL_NAME_MAX 128
+
+enum struct MemoryPoolEntry
+{
+ Address addr;
+ char name[MEMORYPOOL_NAME_MAX];
+}
+
+methodmap AllocatableBase < AddressBase
+{
+ public static Address _malloc(int size, const char[] name)
+ {
+ Address addr = Malloc(size, name);
+
+ return addr;
+ }
+
+ public void Free()
+ {
+ Free(this.Address);
+ }
+}
+
+methodmap PseudoStackArray < AddressBase
+{
+ public Address Get8(int idx, int size = 4)
+ {
+ ASSERT(idx >= 0);
+ ASSERT(size > 0);
+
+ return view_as<Address>(LoadFromAddress(this.Address + (idx * size), NumberType_Int8));
+ }
+
+ public Address Get16(int idx, int size = 4)
+ {
+ ASSERT(idx >= 0);
+ ASSERT(size > 0);
+
+ return view_as<Address>(LoadFromAddress(this.Address + (idx * size), NumberType_Int16));
+ }
+
+ public Address Get32(int idx, int size = 4)
+ {
+ ASSERT(idx >= 0);
+ ASSERT(size > 0);
+
+ return this.Address + (idx * size);
+ }
+}
+
+methodmap Vector < AllocatableBase
+{
+ public static int Size()
+ {
+ return 12;
+ }
+
+ public Vector()
+ {
+ return MALLOC(Vector);
+ }
+
+ property float x
+ {
+ public set(float _x) { StoreToAddress(this.Address, view_as<int>(_x), NumberType_Int32, false); }
+ public get() { return view_as<float>(LoadFromAddress(this.Address, NumberType_Int32)); }
+ }
+
+ property float y
+ {
+ public set(float _y) { StoreToAddress(this.Address + 4, view_as<int>(_y), NumberType_Int32, false); }
+ public get() { return view_as<float>(LoadFromAddress(this.Address + 4, NumberType_Int32)); }
+ }
+
+ property float z
+ {
+ public set(float _z) { StoreToAddress(this.Address + 8, view_as<int>(_z), NumberType_Int32, false); }
+ public get() { return view_as<float>(LoadFromAddress(this.Address + 8, NumberType_Int32)); }
+ }
+
+ public void ToArray(float buff[3])
+ {
+ buff[0] = this.x;
+ buff[1] = this.y;
+ buff[2] = this.z;
+ }
+
+ public void FromArray(float buff[3])
+ {
+ this.x = buff[0];
+ this.y = buff[1];
+ this.z = buff[2];
+ }
+
+ public void CopyTo(Vector dst)
+ {
+ dst.x = this.x;
+ dst.y = this.y;
+ dst.z = this.z;
+ }
+
+ public float LengthSqr()
+ {
+ return this.x*this.x + this.y*this.y + this.z*this.z;
+ }
+
+ public float Length()
+ {
+ return SquareRoot(this.LengthSqr());
+ }
+
+ public float Dot(float vec[3])
+ {
+ return this.x*vec[0] + this.y*vec[1] + this.z*vec[2];
+ }
+}
+
+static Address g_pMemAlloc;
+static Handle gMalloc, gFree, gCreateInterface;
+static ArrayList gMemoryPool;
+
+stock void InitUtils(GameData gd)
+{
+ gMemoryPool = new ArrayList(sizeof(MemoryPoolEntry));
+
+ //CreateInterface
+ StartPrepSDKCall(SDKCall_Static);
+
+ ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CreateInterface"), "Failed to get \"CreateInterface\" signature. Gamedata needs an update.");
+
+ PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gCreateInterface = EndPrepSDKCall();
+ ASSERT(gCreateInterface);
+
+ if(gEngineVersion == Engine_CSGO || gOSType == OSWindows)
+ {
+ //g_pMemAlloc
+ g_pMemAlloc = gd.GetAddress("g_pMemAlloc");
+ ASSERT_MSG(g_pMemAlloc != Address_Null, "Can't get \"g_pMemAlloc\" address from gamedata. Gamedata needs an update.");
+
+ //Malloc
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("Malloc"));
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gMalloc = EndPrepSDKCall();
+ ASSERT(gMalloc);
+
+ //Free
+ StartPrepSDKCall(SDKCall_Raw);
+
+ PrepSDKCall_SetVirtual(gd.GetOffset("Free"));
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gFree = EndPrepSDKCall();
+ ASSERT(gFree);
+ }
+ else
+ {
+ //Malloc
+ StartPrepSDKCall(SDKCall_Static);
+ ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "malloc"), "Failed to get \"malloc\" signature. Gamedata needs an update.");
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+
+ gMalloc = EndPrepSDKCall();
+ ASSERT(gMalloc);
+
+ //Free
+ StartPrepSDKCall(SDKCall_Static);
+ ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "free"), "Failed to get \"free\" signature. Gamedata needs an update.");
+
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+ PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
+
+ gFree = EndPrepSDKCall();
+ ASSERT(gFree);
+ }
+}
+
+stock Address CreateInterface(const char[] name)
+{
+ return SDKCall(gCreateInterface, name, 0);
+}
+
+stock Address Malloc(int size, const char[] name)
+{
+ ASSERT(gMemoryPool);
+ ASSERT(size > 0);
+
+ MemoryPoolEntry entry;
+ strcopy(entry.name, sizeof(MemoryPoolEntry::name), name);
+
+ if(gEngineVersion == Engine_CSS && gOSType == OSLinux)
+ entry.addr = SDKCall(gMalloc, 0, size);
+ else
+ entry.addr = SDKCall(gMalloc, g_pMemAlloc, size);
+
+ ASSERT_FMT(entry.addr != Address_Null, "Failed to allocate memory (size: %i)!", size);
+ gMemoryPool.PushArray(entry);
+
+ return entry.addr;
+}
+
+stock void Free(Address addr)
+{
+ ASSERT(addr != Address_Null);
+ ASSERT(gMemoryPool);
+ int idx = gMemoryPool.FindValue(addr, MemoryPoolEntry::addr);
+
+ //Memory wasn't allocated by this plugin, return.
+ if(idx == -1)
+ return;
+
+ gMemoryPool.Erase(idx);
+
+ if(gEngineVersion == Engine_CSS && gOSType == OSLinux)
+ SDKCall(gFree, 0, addr);
+ else
+ SDKCall(gFree, g_pMemAlloc, addr);
+}
+
+stock void AddToMemoryPool(Address addr, const char[] name)
+{
+ ASSERT(addr != Address_Null);
+ ASSERT(gMemoryPool);
+
+ MemoryPoolEntry entry;
+ strcopy(entry.name, sizeof(MemoryPoolEntry::name), name);
+ entry.addr = addr;
+
+ gMemoryPool.PushArray(entry);
+}
+
+stock void CleanUpUtils()
+{
+ if(!gMemoryPool)
+ return;
+
+ MemoryPoolEntry entry;
+
+ for(int i = 0; i < gMemoryPool.Length; i++)
+ {
+ gMemoryPool.GetArray(i, entry, sizeof(MemoryPoolEntry));
+ view_as<AllocatableBase>(entry.addr).Free();
+ }
+
+ delete gMemoryPool;
+}
+
+stock void DumpMemoryUsage()
+{
+ if(!gMemoryPool || (gMemoryPool && gMemoryPool.Length == 0))
+ {
+ PrintToServer(SNAME..."Theres's currently no active pool or it's empty!");
+ return;
+ }
+
+ MemoryPoolEntry entry;
+
+ PrintToServer(SNAME..."Active memory pool (%i):", gMemoryPool.Length);
+ for(int i = 0; i < gMemoryPool.Length; i++)
+ {
+ gMemoryPool.GetArray(i, entry, sizeof(MemoryPoolEntry));
+ PrintToServer(SNAME..."[%i]: 0x%08X \"%s\"", i, entry.addr, entry.name);
+ }
+} \ No newline at end of file