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.