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

[TF2] Edit weapon props


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
asherkin
SourceMod Developer
Join Date: Aug 2009
Location: OnGameFrame()
Old 12-13-2009 , 11:45   [TF2] Edit weapon props
Reply With Quote #1

EDIT: I stopped working on this in favour of a better method provided by AzuiSleet, hope to have a release soon
EDIT2: It Works, Ship It.

I decided to have a first attempt at MM:S coding today, tried a few things, converted an old CS:S plugin over to TF2, etc. I decided to convert one of my SM plugins to MM:S as some features I want to add would require a SM Extension, so I just decided to go the whole way . But I'm having some issues editing the player's weapon's m_iEntityQuality. The edit of m_iHealth works fine, but editing m_iEntityQuality has no effect, I think I may have messed up on either getting the entity for the weapons in each slot or using the entity of find the offset of m_iEntityQuality.

Edit: My offset for Weapon_GetSlot may also be outdated. I got it from the Wiki, matches here though.

Relevant Code:
Code:
bool SpawnhealthPlugin::FireEvent_Handler(IGameEvent *event, bool bDontBroadcast)
{
	if (!event || !event->GetName())
		RETURN_META_VALUE(MRES_IGNORED, false);

	const char *name = event->GetName();
	
	if (strcmp(name, "player_spawn") == 0)
	{
		int userid = event->GetInt("userid");
		edict_t *pEntityEdict = m_Engine->PEntityOfEntIndex(userid-1);
		if(pEntityEdict)
		{
			if(strcmp(pEntityEdict->GetClassName(),"player") == 0)
			{
				CBaseEntity *pEntity = pEntityEdict->GetUnknown()->GetBaseEntity();
				sm_sendprop_info_t propInfo;
				if (FindSendPropInfo("CTFPlayer", "m_iHealth", &propInfo))
				{
					/* Use the offset and our CBaseEntity as a base to find the prop pointer */
					int *m_iHealth = (int *)(((unsigned char *)pEntity) + propInfo.actual_offset);
					*m_iHealth += 100;
				}
			}
		}
	} 
	else if (strcmp(name, "inventory_updated") == 0)
	{
		int userid = event->GetInt("userid");
		edict_t *pEntityEdict = m_Engine->PEntityOfEntIndex(userid-1);
		if(pEntityEdict)
		{
			if(strcmp(pEntityEdict->GetClassName(),"player") == 0)
			{
				CBaseEntity *pEntity = pEntityEdict->GetUnknown()->GetBaseEntity();
				for (int i = 0; i < 8; i++) {
					CBaseCombatWeapon *pWeapon = Weapon_GetSlot(pEntity, 1);
					sm_sendprop_info_t propInfo;
					if (FindSendPropInfo("CTFWeaponBase", "m_iEntityQuality", &propInfo))
					{
						/* Use the offset and our CBaseEntity as a base to find the prop pointer */
						int *m_iEntityQuality = (int *)(((unsigned char *)pWeapon) + propInfo.actual_offset);
						*m_iEntityQuality = 6;
					}
				}
			}
		}
	}

//	META_LOG(g_PLAPI, "FireGameEvent called: name=%s", name); 

	RETURN_META_VALUE(MRES_IGNORED, true);
}

CBaseCombatWeapon *SpawnhealthPlugin::Weapon_GetSlot(CBaseEntity *pThisPtr, int slot)
{
	void **this_ptr = *(void ***)&pThisPtr;
	void **vtable = *(void ***)pThisPtr;
	void *func = vtable[242]; 
 
	union {CBaseEntity *(VfuncEmptyClass::*mfpnew)( 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 (CBaseCombatWeapon *) (reinterpret_cast<VfuncEmptyClass*>(this_ptr)->*u.mfpnew)(slot);
}

bool UTIL_FindInSendTable(SendTable *pTable, 
						  const char *name,
						  sm_sendprop_info_t *info,
						  unsigned int offset)
{
	const char *pname;
	int props = pTable->GetNumProps();
	SendProp *prop;

	for (int i=0; i<props; i++)
	{
		prop = pTable->GetProp(i);
		pname = prop->GetName();
		if (pname && strcmp(name, pname) == 0)
		{
			info->prop = prop;
			info->actual_offset = offset + info->prop->GetOffset();
			return true;
		}
		if (prop->GetDataTable())
		{
			if (UTIL_FindInSendTable(prop->GetDataTable(), 
				name,
				info,
				offset + prop->GetOffset())
				)
			{
				return true;
			}
		}
	}

	return false;
}

DataTableInfo *SpawnhealthPlugin::_FindServerClass(const char *classname)
{
	DataTableInfo *pInfo = NULL;

	ServerClass *sc = m_ServerDll->GetAllServerClasses();
	while (sc)
	{
		if (strcmp(classname, sc->GetName()) == 0)
		{
			pInfo = new DataTableInfo;
			pInfo->sc = sc;
			break;
		}
		sc = sc->m_pNext;
	}
	if (!pInfo)
	{
		return NULL;
	}

	return pInfo;
}

bool SpawnhealthPlugin::FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info)
{
	DataTableInfo *pInfo;
	sm_sendprop_info_t *prop;

	if ((pInfo = _FindServerClass(classname)) == NULL)
	{
		return false;
	}

	if ((prop = pInfo->lookup.retrieve(offset)) == NULL)
	{
		sm_sendprop_info_t temp_info;

		if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
		{
			return false;
		}

		pInfo->lookup.insert(offset, temp_info);
		*info = temp_info;
	}
	else
	{
		*info = *prop;
	}
	
	return true;
}
I have attached the complete project along with my original SM plugin, note that I just extended the plugin I was porting, so the naming is a bit odd

Any help on this would be greatly appreciated.

Last edited by asherkin; 01-10-2010 at 07:08.
asherkin 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 08:56.


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