Raised This Month: $51 Target: $400
 12% 

Need some help with weapons


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
TommyV
Member
Join Date: Nov 2005
Old 04-24-2006 , 13:24   Need some help with weapons
Reply With Quote #1

Can anyone suggest a way I can find out what weapons a player has at round start in CSS. I've tried everything I can think of and nothing seems to work.

What I have tried is getting the base entity of a player and then downcasting to a CBaseCombatCharacter to call

CBaseCombatWeapon CBaseCombatCharacter::Weapon_GetSlot(int) const

Which would be great but it crashes all the time (I'm guessing due to the headers)

IPlayerInfo only gives me the current weapon they are using, and even if run I IVServerEngine::ClientCommand to try and force the client to use the weapons I am interested in, IPlayerInfo still returns the previous weapon, even though it switches the client on the server (client lag?)

What I would like to do is manually call, rather than hook, the function Weapon_GetSlot by it's offset (which I can see in the CCSPlayer offset table). The only way I can see of doing this using SourceMM would be by making a CallClass, but as far as I can tell the CallClass requires a named pointer to the function, which would put me back to square one with headers. Is it possible to make 'manual' call to a CallClass? Or does anyone have any other ideas about how I could get at the players primary in CSS?
TommyV is offline
Mani
Veteran Member
Join Date: Dec 2004
Location: UK
Old 04-24-2006 , 14:00  
Reply With Quote #2

I used some code from PM that he uses in SourceHook for calling virtual functions, I've since converted it into macros for easy use.

You will need to tweak the macros to use what ever kind code you yourself use to supply vfunc offsets. The macros use a similar kind of style to SourceMM in declaring the number of parameters and whether it's a void return type. This works on both linux and windows though the vfunc indexes tend to differ by 1 between the two, I can't remember off hand which way round it is.

Mani

Code:
.h file

extern const QAngle &CBaseEntity_EyeAngles(CBaseEntity *pThisPtr);
extern void CBaseEntity_Teleport(CBaseEntity *pThisPtr, const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity);
extern Vector CBaseEntity_EyePosition (CBaseEntity *pThisPtr);
extern void CBaseEntity_GetVelocity(CBaseEntity *pThisPtr, Vector *vVelocity, AngularImpulse *vAngVelocity = NULL);
extern CBaseCombatCharacter *CBaseEntity_MyCombatCharacterPointer(CBaseEntity *pThisPtr);
extern void CBaseEntity_SetModelIndex(CBaseEntity *pThisPtr, int iIndex);
extern void CBasePlayer_Ignite(CBasePlayer *pThisPtr, float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false );
extern bool CBasePlayer_RemovePlayerItem(CBasePlayer *pThisPtr, CBaseCombatWeapon *pItem);
extern void CBasePlayer_WeaponDrop(CBasePlayer *pThisPtr, CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL);
extern CBaseEntity *CBasePlayer_GiveNamedItem(CBasePlayer *pThisPtr, const char *szName, int iSubType = 0 );
extern int  CBaseCombatWeapon_GetPrimaryAmmoType(CBaseCombatWeapon *pThisPtr);
extern int  CBaseCombatWeapon_GetSecondaryAmmoType(CBaseCombatWeapon *pThisPtr);
extern const char *CBaseCombatWeapon_GetName(CBaseCombatWeapon *pThisPtr);
extern CBaseCombatWeapon *CBaseCombatCharacter_Weapon_GetSlot(CBaseCombatCharacter *pThisPtr, int slot);
extern void CBaseCombatCharacter_Weapon_Switch(CBaseCombatCharacter *pThisPtr, CBaseCombatWeapon *pWeapon, int viewmodelindex = 0);
extern void CBaseCombatCharacter_GiveAmmo(CBaseCombatCharacter *pThisPtr, int iCount, int iAmmoIndex, bool bSuppressSound = false );
Code:
.cpp file

class ManiEmptyClass {};

#ifdef __linux__
#define VFUNC_OS_DEP void *addr;	} u; 	u.addr = func;
#else
#define VFUNC_OS_DEP struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
#endif

#define VFUNC_SETUP_PTR(_vfunc_index)  \
{ \
	void **this_ptr = *(void ***)&pThisPtr; \
	void **vtable = *(void ***)pThisPtr; \
	void *func = vtable[gpManiGameType->GetVFuncIndex(_vfunc_index)]

// Macros for defining functions to call vfuncs via offset.

#define VFUNC_CALL0(_vfunc_index, _return_type, _class_type, _func_name ) \
	_return_type _func_name(_class_type *pThisPtr) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)();} 

#define VFUNC_CALL1(_vfunc_index, _return_type, _class_type, _func_name, _param1) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1);} 

#define VFUNC_CALL2(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2);} 

#define VFUNC_CALL3(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3);} 

#define VFUNC_CALL4(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4);} 

#define VFUNC_CALL5(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5);} 

#define VFUNC_CALL6(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6);} 

#define VFUNC_CALL7(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7);} 

#define VFUNC_CALL8(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8);} 

#define VFUNC_CALL9(_vfunc_index, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8, _param9) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { _return_type (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8, p9);} 

#define VFUNC_CALL0_void(_vfunc_index, _class_type, _func_name ) \
	void _func_name(_class_type *pThisPtr) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)();} 

#define VFUNC_CALL1_void(_vfunc_index, _class_type, _func_name, _param1) \
	void _func_name(_class_type *pThisPtr, _param1 p1) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1);} 

#define VFUNC_CALL2_void(_vfunc_index, _class_type, _func_name, _param1, _param2) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2);} 

#define VFUNC_CALL3_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3);} 

#define VFUNC_CALL4_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3, _param4) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4);} 

#define VFUNC_CALL5_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5);} 

#define VFUNC_CALL6_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6);} 

#define VFUNC_CALL7_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7);} 

#define VFUNC_CALL8_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8);} 

#define VFUNC_CALL9_void(_vfunc_index, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8, _param9) \
	VFUNC_SETUP_PTR(_vfunc_index); \
	union { void (ManiEmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<ManiEmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8, p9);} 

// Actual use of the macros.

// virtual const QAngle &EyeAngles( void );
VFUNC_CALL0(MANI_VFUNC_EYE_ANGLES, const QAngle &, CBaseEntity, CBaseEntity_EyeAngles)

// virtual void	Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
VFUNC_CALL3_void(MANI_VFUNC_TELEPORT, CBaseEntity, CBaseEntity_Teleport, const Vector *, const QAngle *, const Vector *)

// virtual Vector	EyePosition( void );
VFUNC_CALL0(MANI_VFUNC_EYE_POSITION, Vector, CBaseEntity, CBaseEntity_EyePosition)

//virtual void	GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity = NULL);
VFUNC_CALL2_void(MANI_VFUNC_GET_VELOCITY, CBaseEntity, CBaseEntity_GetVelocity, Vector *, AngularImpulse *)

// virtual CBaseCombatCharacter *MyCombatCharacterPointer( void );
VFUNC_CALL0(MANI_VFUNC_MY_COMBAT_CHARACTER, CBaseCombatCharacter *, CBaseEntity, CBaseEntity_MyCombatCharacterPointer)

// virtual void SetModelIndex( int index );
VFUNC_CALL1_void(MANI_VFUNC_SET_MODEL_INDEX, CBaseEntity, CBaseEntity_SetModelIndex, int)

// virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false );
VFUNC_CALL4_void(MANI_VFUNC_IGNITE, CBasePlayer, CBasePlayer_Ignite, float, bool, float, bool)

// virtual bool	RemovePlayerItem( CBaseCombatWeapon *pItem )
VFUNC_CALL1(MANI_VFUNC_REMOVE_PLAYER_ITEM, bool, CBasePlayer, CBasePlayer_RemovePlayerItem, CBaseCombatWeapon *)

// virtual void	Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL );
VFUNC_CALL3_void(MANI_VFUNC_WEAPON_DROP, CBasePlayer, CBasePlayer_WeaponDrop, CBaseCombatWeapon *, const Vector *, const Vector *)

// virtual CBaseEntity	*GiveNamedItem( const char *szName, int iSubType = 0 );
VFUNC_CALL2(MANI_VFUNC_GIVE_ITEM, CBaseEntity *, CBasePlayer, CBasePlayer_GiveNamedItem, const char *, int)

// virtual CBaseCombatWeapon *Weapon_GetSlot( int slot ) const;
VFUNC_CALL1(MANI_VFUNC_GET_WEAPON_SLOT, CBaseCombatWeapon *, CBaseCombatCharacter, CBaseCombatCharacter_Weapon_GetSlot, int)

// virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0 );
VFUNC_CALL2_void(MANI_VFUNC_WEAPON_SWITCH, CBaseCombatCharacter, CBaseCombatCharacter_Weapon_Switch, CBaseCombatWeapon *, int)

// virtual int GiveAmmo( int iCount, int iAmmoIndex, bool bSuppressSound = false );
VFUNC_CALL3_void(MANI_VFUNC_GIVE_AMMO, CBaseCombatCharacter, CBaseCombatCharacter_GiveAmmo, int, int, bool)

// virtual int	GetPrimaryAmmoType( void );
VFUNC_CALL0(MANI_VFUNC_GET_PRIMARY_AMMO_TYPE, int, CBaseCombatWeapon, CBaseCombatWeapon_GetPrimaryAmmoType)

// virtual int	GetSecondaryAmmoType( void );
VFUNC_CALL0(MANI_VFUNC_GET_SECONDARY_AMMO_TYPE, int, CBaseCombatWeapon, CBaseCombatWeapon_GetSecondaryAmmoType)

// virtual char const *GetName( void );
VFUNC_CALL0(MANI_VFUNC_WEAPON_GET_NAME, const char *, CBaseCombatWeapon, CBaseCombatWeapon_GetName)
__________________
Installation files, documentation and help can be found at: -

www.mani-admin-plugin.com
Mani is offline
TommyV
Member
Join Date: Nov 2005
Old 04-25-2006 , 03:09  
Reply With Quote #3

Thanks Mani,

I guess there is no easy way to get at the good stuff then

Do you use this method for all function calls that aren't standard interfaces then? I do call some CBaseCombatWeapon functions that seem to work ok, should I switch everything to this kind of offset calling?
TommyV is offline
Mani
Veteran Member
Join Date: Dec 2004
Location: UK
Old 04-25-2006 , 11:37  
Reply With Quote #4

Quote:
Originally Posted by TommyV
Thanks Mani,

I guess there is no easy way to get at the good stuff then

Do you use this method for all function calls that aren't standard interfaces then? I do call some CBaseCombatWeapon functions that seem to work ok, should I switch everything to this kind of offset calling?
I started work on removing dependancy on the SDK baseentity, etc header definitions a couple of weeks before Valve did the update that removed the header consistency with CSS (though I still hadn't quite got there). At that point I was using function typdefs for linux and inline assembler for the windows calls. PM made it a lot easier with his version which I've used for a while now. It was only maybe a month or so ago I decided to update it to a macro version which makes it even simpler to create functions that can call vfuncs by index.

For any virtual functions that are not part of the 'standard' interfaces I use these. They also can be tweaked to run non-virtual class functions. Of course for vfuncs you need to know the vtable index and for non-virtual functions you need to know the address of the function via a sig scan.

Mani
__________________
Installation files, documentation and help can be found at: -

www.mani-admin-plugin.com
Mani is offline
TommyV
Member
Join Date: Nov 2005
Old 04-25-2006 , 12:22  
Reply With Quote #5

Mani you are a star.

I spent so long trying to figure out a way to do this, I was just about to throw in the towel. That method is so simple and it works a treat

I suppose I should learn how to get the offsets myself now rather than relying on other people to post them, but for now I have all I need, ty.
TommyV is offline
[email protected]
Member
Join Date: Dec 2005
Old 04-25-2006 , 12:46  
Reply With Quote #6

Just thought I'd show you guys another approach to this. Yet another method to call the virtual functions. It's very similar to Mani's and PM's methods, but I templated it out so it's pretty easy to use. I wrote this assuming that you're using MSVC .NET 2003 for windows, and GCC for Linux. The general sytax is like this:
Code:
VFunc<void ( )> CCSPlayer_CommitSuicide;
CCSPlayer_CommitSuicide.Get( pPlayer, iCommitSuicide_vtable_index );
...
CCSPlayer_CommitSuicide( player );
...
...
// Other functions
VFunc<bool ( )> CBasePlayer_CanBreatheUnderwater;
VFunc<CBaseCombatWeapon * ( int )> CBasePlayer_Weapon_GetSlot;
// etc etc
You can test to see if they're initialized (you do this by using the Get( ) function, passing it a valid pointer and the offset of the function you want.) using the ! operator or the safe bool idiom
Code:
if ( CCSPlayer_CommitSuicide )
    Msg( "VFunc is already initialized\n" );
else
    Msg( "VFunc is not initialized\n" );
...
if ( !CCSPlayer_CommitSuicide )
    Msg( "Cannot use the admin slay command, required vfunc is not initialized." );
You can also call non-virtual functions using this, provided you have the address of the function:
Code:
void *addr = SigScan( CCSPlayer_RoundRespawn );   // Some signature scanning function that will return the address for you
VFunc<void ( )> RoundRespawn;
RoundRespawn.Set( addr );
...
RoundRespawn( pPlayer );
Anyway, this is basically stuff I learned from PM's posts about MSVC's 4 types of member function pointers, Don Clugston's artical about FastDelegates (again, PM pointed me in the direction to that article) and some tinkering around with templates that i did. There is no vararg version, however. This should work fine with multiple inheritance cases, but I havent tested it, seeing as there's not really any mulitple inheritance classes int the SDK...

P.S: one thing to note is that I already took into account the vtable index difference between linux and windows. Linux is 1 higher than windows, and I already coded that into the class (use the windows offset - for example, use 332 for CCSPlayer::CommitSuicide). If for some reason you found a case where that wasnt' the case, you could just go in and redefine VFUNC_ADJ to 0 for linux, and use the *real* offsets.
Attached Files
File Type: h vfunchook.h (13.1 KB, 184 views)
Lojo.jacob@gmail.com is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 17:57.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode