diff options
Diffstat (limited to 'sourcemod/scripting/momsurffix')
| -rw-r--r-- | sourcemod/scripting/momsurffix/baseplayer.sp | 189 | ||||
| -rw-r--r-- | sourcemod/scripting/momsurffix/gamemovement.sp | 411 | ||||
| -rw-r--r-- | sourcemod/scripting/momsurffix/gametrace.sp | 480 | ||||
| -rw-r--r-- | sourcemod/scripting/momsurffix/utils.sp | 279 |
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 |
