Virtual Offsets (Source Mods)

From AlliedModders Wiki
Revision as of 18:55, 18 May 2006 by Showdax (talk | contribs) (Offset Lists)
Jump to: navigation, search

Calling virtual functions

I got this method from Mani, who I believe got it from Pavol Marko. Thank you!

I hope to expand on an actual explantaion when I have the time (and understand it better). Hopefully, someone can expand on this, but for now I'll just post the examples and a list of the CCSPlayer virtual function table offsets.

Offset Lists

CS:S

DOD:S

HL2:DM

How to use the examples

Basically, this lets you call any virtual function by knowing it's offset. A table is created for each class that lists the address of the function for each virtual function. This method takes advantage of that to call those addresses.

Look at the examples below and edit to match the function you want to call: Use the offset for the function you want to call in this line. (CCSPlayer_offset_list_(SourceMM))

void *func = vtable[m_Off_GiveNamedItem];

Change this line to match your return type and parameters:

union {CBaseEntity *(VfuncEmptyClass::*mfpnew)(const char *, int );

Call the original function with your parameters (change the return type to match the function you're calling):

return (CBaseEntity *) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)(ItemName, iSubType);

You'll need to add an empty class for the union. Something like this:

class VfuncEmptyClass {};

Examples

datamap_t *VFuncs::GetDataDescMap(CBaseEntity *pThisPtr)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_GetDataDescMap]; 
 
	union {datamap_t *(VfuncEmptyClass::*mfpnew)();
#ifndef __linux__
        void *addr;	} u; 	u.addr = func;
#else /* GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 */
			struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
#endif
 
	return (datamap_t *) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)();
 
}
 
void VFuncs::SetModel(CBaseEntity *pThisPtr, const char *ModelName)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_SetModel]; 
 
	union {void (VfuncEmptyClass::*mfpnew)(const char *);
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	(void) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)(ModelName);
 
}
 
void VFuncs::Teleport(CBaseEntity *pThisPtr, const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_Teleport]; 
 
	union {void (VfuncEmptyClass::*mfpnew)(const Vector *, const QAngle *, const Vector *);
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	(void) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)(newPosition, newAngles, newVelocity);
 
}
 
Vector VFuncs::EyePosition( CBaseEntity *pThisPtr )
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_EyePosition]; 
 
	union {Vector (VfuncEmptyClass::*mfpnew)( void );
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	return (Vector) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)( );
 
}
 
QAngle &VFuncs::EyeAngles( CBaseEntity *pThisPtr )
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_EyeAngles]; 
 
	union {QAngle& (VfuncEmptyClass::*mfpnew)( void );
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	return (QAngle&) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)( );
 
}
 
 
void VFuncs::Ignite(CBaseEntity *pThisPtr, float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_Ignite]; 
 
	union {void (VfuncEmptyClass::*mfpnew)(float , bool , float , bool );
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	(void) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)(flFlameLifetime, bNPCOnly, flSize, bCalledByLevelDesigner);
 
}
 
CBaseEntity *VFuncs::GiveNamedItem(CBaseEntity *pThisPtr, const char *ItemName, int iSubType)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_GiveNamedItem]; 
 
	union {CBaseEntity *(VfuncEmptyClass::*mfpnew)(const char *, int );
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	return (CBaseEntity *) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)(ItemName, iSubType);
}
 
void VFuncs::CommitSuicide(CBaseEntity *pThisPtr)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[m_Off_CommitSuicide]; 
 
	union {CBaseEntity *(VfuncEmptyClass::*mfpnew)( void );
	#ifndef __linux__
			void *addr;	} u; 	u.addr = func;
	#else // GCC's member function pointers all contain a this pointer adjustor. You'd probably set it to 0 
				struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
	#endif
 
	(reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)();
}