#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
(LoadFromAddress(this.Address + (idx * size), NumberType_Int8)); } public Address Get16(int idx, int size = 4) { ASSERT(idx >= 0); ASSERT(size > 0); return view_as
(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(_x), NumberType_Int32, false); } public get() { return view_as(LoadFromAddress(this.Address, NumberType_Int32)); } } property float y { public set(float _y) { StoreToAddress(this.Address + 4, view_as(_y), NumberType_Int32, false); } public get() { return view_as(LoadFromAddress(this.Address + 4, NumberType_Int32)); } } property float z { public set(float _z) { StoreToAddress(this.Address + 8, view_as(_z), NumberType_Int32, false); } public get() { return view_as(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(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); } }