Add LookupEntityAttachment & GetEntityAttachment natives (#1653)

Using the virtual `CBaseAnimating::GetAttachment(int, matrix3x4_t &)` was a deliberate choice because virtual offsets are generally easier to maintain than signatures. The `matrix3x4_t` is converted to world position and world angles internally.
Some of the other overloads are also inlined on a few games, making this the best choice.

Since this call can only be used on classes inheriting `CBaseAnimating`, we check if the `DT_BaseAnimating` SendTable exists on the entity, throwing a native error if it doesn't.
This safeguard could be greatly improved with a call to `CBaseEntity::GetBaseAnimating`, but would require more gamedata (maybe something to consider for the future?)
This commit is contained in:
Mikusch 2022-01-03 14:13:54 +01:00 committed by Your Name
parent cc1c02e3de
commit 542b7673d6
8 changed files with 246 additions and 0 deletions

View File

@ -53,6 +53,11 @@ SourceHook::List<ICallWrapper *> g_CallWraps;
return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseEntity", gamehelpers->ReferenceToIndex(ref), ref); \ return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseEntity", gamehelpers->ReferenceToIndex(ref), ref); \
} }
#define SET_VECTOR(addr, vec) \
addr[0] = sp_ftoc(vec.x); \
addr[1] = sp_ftoc(vec.y); \
addr[2] = sp_ftoc(vec.z);
inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsigned int flags, unsigned int decflags=0) inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsigned int flags, unsigned int decflags=0)
{ {
info.decflags = decflags; info.decflags = decflags;
@ -1638,6 +1643,113 @@ static cell_t SetEntityOwner(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t LookupEntityAttachment(IPluginContext* pContext, const cell_t* params)
{
CBaseEntity* pEntity;
ENTINDEX_TO_CBASEENTITY(params[1], pEntity);
ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating"))
{
return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]);
}
static ICallWrapper* pLookupAttachment = NULL;
if (!pLookupAttachment)
{
void* addr;
if (!g_pGameConf->GetMemSig("LookupAttachment", &addr))
{
return pContext->ThrowNativeError("\"LookupAttachment\" not supported by this mod");
}
PassInfo retpass;
retpass.type = PassType_Basic;
retpass.flags = PASSFLAG_BYVAL;
retpass.size = sizeof(int);
PassInfo pass[1];
pass[0].type = PassType_Basic;
pass[0].flags = PASSFLAG_BYVAL;
pass[0].size = sizeof(char*);
if (!(pLookupAttachment = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &retpass, pass, 1)))
{
return pContext->ThrowNativeError("\"LookupAttachment\" wrapper failed to initialize");
}
}
char* buffer;
pContext->LocalToString(params[2], &buffer);
ArgBuffer<CBaseEntity*, char*> vstk(pEntity, buffer);
int ret;
pLookupAttachment->Execute(vstk, &ret);
return ret;
}
static cell_t GetEntityAttachment(IPluginContext* pContext, const cell_t* params)
{
CBaseEntity* pEntity;
ENTINDEX_TO_CBASEENTITY(params[1], pEntity);
ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating"))
{
return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]);
}
static ICallWrapper* pGetAttachment = NULL;
if (!pGetAttachment)
{
int offset = -1;
if (!g_pGameConf->GetOffset("GetAttachment", &offset))
{
return pContext->ThrowNativeError("\"GetAttachment\" not supported by this mod");
}
PassInfo retpass;
retpass.type = PassType_Basic;
retpass.flags = PASSFLAG_BYVAL;
retpass.size = sizeof(bool);
PassInfo pass[2];
pass[0].type = PassType_Basic;
pass[0].flags = PASSFLAG_BYVAL;
pass[0].size = sizeof(int);
pass[1].type = PassType_Basic;
pass[1].flags = PASSFLAG_BYVAL;
pass[1].size = sizeof(matrix3x4_t*);
if (!(pGetAttachment = g_pBinTools->CreateVCall(offset, 0, 0, &retpass, pass, 2)))
{
return pContext->ThrowNativeError("\"GetAttachment\" wrapper failed to initialize");
}
}
matrix3x4_t attachmentToWorld;
ArgBuffer<CBaseEntity*, int, matrix3x4_t*> vstk(pEntity, params[2], &attachmentToWorld);
bool ret;
pGetAttachment->Execute(vstk, &ret);
// GetAttachment returns a matrix3x4_t but plugins can't do anything with this.
// Convert it to world origin and world angles.
QAngle absAngles;
Vector absOrigin;
MatrixAngles(attachmentToWorld, absAngles, absOrigin);
cell_t* pOrigin, * pAngles;
pContext->LocalToPhysAddr(params[3], &pOrigin);
pContext->LocalToPhysAddr(params[4], &pAngles);
SET_VECTOR(pOrigin, absOrigin);
SET_VECTOR(pAngles, absAngles);
return ret;
}
sp_nativeinfo_t g_Natives[] = sp_nativeinfo_t g_Natives[] =
{ {
{"ExtinguishEntity", ExtinguishEntity}, {"ExtinguishEntity", ExtinguishEntity},
@ -1672,5 +1784,7 @@ sp_nativeinfo_t g_Natives[] =
{"SetEntityCollisionGroup", SetEntityCollisionGroup}, {"SetEntityCollisionGroup", SetEntityCollisionGroup},
{"EntityCollisionRulesChanged", EntityCollisionRulesChanged}, {"EntityCollisionRulesChanged", EntityCollisionRulesChanged},
{"SetEntityOwner", SetEntityOwner}, {"SetEntityOwner", SetEntityOwner},
{"LookupEntityAttachment", LookupEntityAttachment},
{"GetEntityAttachment", GetEntityAttachment},
{NULL, NULL}, {NULL, NULL},
}; };

View File

@ -184,6 +184,21 @@
} }
} }
/* CBaseAnimating::LookupAttachment */
"#default"
{
"Signatures"
{
"LookupAttachment"
{
"library" "server"
"windows" "\x55\x8B\xEC\x57\x8B\xF9\x83\xBF\xC0\x04\x00\x00\x00\x75\x2A\xA1\x2A\x2A\x2A\x2A\x56\x8B\x30\x8B\x07\xFF\x50\x18\x8B\x0D\x2A\x2A\x2A\x2A\x50\xFF\x56\x04\x5E\x85\xC0\x74\x2A\x8B\xCF\xE8\x2A\x2A\x2A\x2A\x8B\x8F\xC0\x04\x00\x00\x5F\x85\xC9\x74\x2A\x83\x39\x00\x74\x2A\x8B\x55\x08\xE8\x2A\x2A\x2A\x2A"
"linux" "\x55\x89\xE5\x53\x83\xEC\x14\x8B\x5D\x08\x8B\x8B\xD8\x04\x00\x00\x85\xC9\x74\x2A\x8B\x83\xD8\x04\x00\x00\x85\xC0\x74\x2A\x8B\x10\x85\xD2\x74\x2A\x8B\x55\x0C\x89\x04\x24"
"linux64" "\x55\x48\x89\xE5\x53\x48\x89\xFB\x48\x83\xEC\x18\x48\x8B\xBF\x28\x06\x00\x00\x48\x85\xFF\x74\x2A\x48\x83\x3F\x00\x74\x2A\xE8\x2A\x2A\x2A\x2A"
}
}
}
/* SetUserInfo data */ /* SetUserInfo data */
"#default" "#default"
{ {
@ -354,6 +369,13 @@
"linux64" "280" "linux64" "280"
"mac64" "280" "mac64" "280"
} }
"GetAttachment"
{
"windows" "222"
"linux" "223"
"linux64" "223"
"mac64" "223"
}
} }
"Signatures" "Signatures"
{ {

View File

@ -89,6 +89,21 @@
} }
} }
/* CBaseAnimating::LookupAttachment */
"#default"
{
"Signatures"
{
"LookupAttachment"
{
"library" "server"
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x80\xBE\x31\x03\x00\x00\x00\x75\x2A\x83\xBE\x50\x04\x00\x00\x00\x75\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x8B\x86\x50\x04\x00\x00\x85\xC0\x74\x2A\x83\x38\x00\x74\x2A\xFF\x75\x08\x50\xE8\x2A\x2A\x2A\x2A\x83\xC4\x08\x40"
"linux" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
"mac" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
}
}
}
/* SetUserInfo data */ /* SetUserInfo data */
"#default" "#default"
{ {

View File

@ -168,6 +168,25 @@
} }
} }
/* CBaseAnimating::LookupAttachment */
"#default"
{
"#supported"
{
"game" "left4dead"
}
"Signatures"
{
"LookupAttachment"
{
"library" "server"
"windows" "\x56\x8B\xF1\x83\xBE\x68\x04\x00\x00\x00\x75\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x8B\x86\x68\x04\x00\x00\x85\xC0\x5E\x74\x2A\x83\x38\x00\x75\x2A\x33\xC0\xC2\x04\x00\x8B\x4C\x24\x04"
"linux" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
"mac" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
}
}
}
/* SetUserInfo data */ /* SetUserInfo data */
"#default" "#default"
{ {
@ -306,6 +325,12 @@
"linux" "428" "linux" "428"
"mac" "428" "mac" "428"
} }
"GetAttachment"
{
"windows" "202"
"linux" "203"
"mac" "203"
}
} }
} }
} }

View File

@ -123,6 +123,12 @@
"linux" "253" "linux" "253"
"mac" "253" "mac" "253"
} }
"GetAttachment"
{
"windows" "205"
"linux" "206"
"mac" "206"
}
} }
} }
} }

View File

@ -79,6 +79,21 @@
} }
} }
/* CBaseAnimating::LookupAttachment */
"#default"
{
"Signatures"
{
"LookupAttachment"
{
"library" "server"
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x83\xBE\xD0\x13\x00\x00\x00\x75\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x8B\x86\xD0\x13\x00\x00\x5E\x85\xC0\x74\x2A\x83\x38\x00\x75\x2A\x33\xC0\x5D\xC2\x04\x00\x8B\x4D\x08"
"linux" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
"mac" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
}
}
}
/* IServer interface pointer */ /* IServer interface pointer */
"#default" "#default"
{ {
@ -217,6 +232,12 @@
"linux" "275" "linux" "275"
"mac" "275" "mac" "275"
} }
"GetAttachment"
{
"windows" "219"
"linux" "220"
"mac" "220"
}
} }
"Keys" "Keys"

View File

@ -112,6 +112,12 @@
"linux" "260" "linux" "260"
"mac" "260" "mac" "260"
} }
"GetAttachment"
{
"windows" "212"
"linux" "213"
"mac" "213"
}
} }
"Keys" "Keys"
@ -135,4 +141,19 @@
} }
} }
} }
/* CBaseAnimating::LookupAttachment */
"#default"
{
"Signatures"
{
"LookupAttachment"
{
"library" "server"
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x80\xBE\x41\x03\x00\x00\x00\x75\x2A\x83\xBE\x6C\x04\x00\x00\x00\x75\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x8B\x86\x6C\x04\x00\x00\x85\xC0\x74\x2A\x83\x38\x00\x74\x2A\xFF\x75\x08\x50\xE8\x2A\x2A\x2A\x2A\x83\xC4\x08\x40"
"linux" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
"mac" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
}
}
}
} }

View File

@ -377,3 +377,25 @@ native void EntityCollisionRulesChanged(int entity);
* @error Invalid entity or lack of mod support. * @error Invalid entity or lack of mod support.
*/ */
native void SetEntityOwner(int entity, int owner=INVALID_ENT_REFERENCE); native void SetEntityOwner(int entity, int owner=INVALID_ENT_REFERENCE);
/**
* Returns the index number of a given named attachment.
*
* @param entity The entity index.
* @param name The attachment name.
* @return An attachment index, or 0 if the attachment name is invalid or unused.
* @error Invalid entity or lack of mod support.
*/
native int LookupEntityAttachment(int entity, const char[] name);
/**
* Returns the world location and world angles of an attachment.
*
* @param entity The entity index.
* @param attachment The attachment index.
* @param origin Destination vector to store the attachment's origin vector.
* @param angles Destination vector to store the attachment's position angle.
* @return True on success, otherwise false.
* @error Invalid entity or lack of mod support.
*/
native bool GetEntityAttachment(int entity, int attachment, float origin[3], float angles[3]);